aaaa
This commit is contained in:
@@ -7,10 +7,12 @@ use x11rb::atom_manager;
|
|||||||
use x11rb::connection::Connection;
|
use x11rb::connection::Connection;
|
||||||
use x11rb::protocol::xproto::{
|
use x11rb::protocol::xproto::{
|
||||||
AtomEnum, ChangeWindowAttributesAux, ClientMessageEvent, ConfigureWindowAux,
|
AtomEnum, ChangeWindowAttributesAux, ClientMessageEvent, ConfigureWindowAux,
|
||||||
ConnectionExt as XprotoConnectionExt, EventMask, StackMode,
|
ConnectionExt as XprotoConnectionExt, EventMask, StackMode, UnmapNotifyEvent,
|
||||||
|
UNMAP_NOTIFY_EVENT,
|
||||||
};
|
};
|
||||||
use x11rb::protocol::Event;
|
use x11rb::protocol::Event;
|
||||||
use x11rb::rust_connection::RustConnection;
|
use x11rb::rust_connection::RustConnection;
|
||||||
|
use x11rb::wrapper::ConnectionExt as _;
|
||||||
|
|
||||||
atom_manager! {
|
atom_manager! {
|
||||||
pub Atoms: AtomsCookie {
|
pub Atoms: AtomsCookie {
|
||||||
@@ -172,9 +174,16 @@ pub async fn app_launch(
|
|||||||
// Detach: we don't wait() — Tauri exiting will SIGHUP it via the X11 parent.
|
// Detach: we don't wait() — Tauri exiting will SIGHUP it via the X11 parent.
|
||||||
std::mem::forget(child);
|
std::mem::forget(child);
|
||||||
|
|
||||||
|
eprintln!(
|
||||||
|
"[infinite] app_launch: command={:?} pid={} tauri_xid={:#x}",
|
||||||
|
opts.command, root_pid, parent_xid
|
||||||
|
);
|
||||||
|
|
||||||
let client_xid = wait_for_window_by_pid(&c, root_pid, Duration::from_secs(20))
|
let client_xid = wait_for_window_by_pid(&c, root_pid, Duration::from_secs(20))
|
||||||
.ok_or_else(|| "could not find window for launched process".to_string())?;
|
.ok_or_else(|| "could not find window for launched process".to_string())?;
|
||||||
|
|
||||||
|
eprintln!("[infinite] found client window {:#x} for pid {}", client_xid, root_pid);
|
||||||
|
|
||||||
embed_window(&c, client_xid, parent_xid)?;
|
embed_window(&c, client_xid, parent_xid)?;
|
||||||
|
|
||||||
let title = read_window_title(&c, client_xid).unwrap_or_else(|| opts.command.clone());
|
let title = read_window_title(&c, client_xid).unwrap_or_else(|| opts.command.clone());
|
||||||
@@ -279,6 +288,30 @@ pub fn app_close(app: AppHandle, state: State<'_, X11State>, xid: u32) -> Result
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn embed_window(c: &X11Conn, client_xid: u32, parent_xid: u32) -> Result<(), String> {
|
fn embed_window(c: &X11Conn, client_xid: u32, parent_xid: u32) -> Result<(), String> {
|
||||||
|
eprintln!(
|
||||||
|
"[infinite] embed: client={:#x} -> parent={:#x}",
|
||||||
|
client_xid, parent_xid
|
||||||
|
);
|
||||||
|
|
||||||
|
// XWithdrawWindow protocol: unmap then send synthetic UnmapNotify to root so
|
||||||
|
// the WM unmanages this window. Without this step Mutter et al. keep treating
|
||||||
|
// it as a top-level even after reparenting.
|
||||||
|
let _ = c.conn.unmap_window(client_xid);
|
||||||
|
let unmap_event = UnmapNotifyEvent {
|
||||||
|
response_type: UNMAP_NOTIFY_EVENT,
|
||||||
|
sequence: 0,
|
||||||
|
event: c.root,
|
||||||
|
window: client_xid,
|
||||||
|
from_configure: false,
|
||||||
|
};
|
||||||
|
let _ = c.conn.send_event(
|
||||||
|
false,
|
||||||
|
c.root,
|
||||||
|
EventMask::SUBSTRUCTURE_NOTIFY | EventMask::SUBSTRUCTURE_REDIRECT,
|
||||||
|
unmap_event,
|
||||||
|
);
|
||||||
|
let _ = c.conn.sync();
|
||||||
|
|
||||||
// Listen for destroy / property changes on the embedded window.
|
// Listen for destroy / property changes on the embedded window.
|
||||||
c.conn
|
c.conn
|
||||||
.change_window_attributes(
|
.change_window_attributes(
|
||||||
@@ -292,8 +325,7 @@ fn embed_window(c: &X11Conn, client_xid: u32, parent_xid: u32) -> Result<(), Str
|
|||||||
c.conn
|
c.conn
|
||||||
.reparent_window(client_xid, parent_xid, 0, 0)
|
.reparent_window(client_xid, parent_xid, 0, 0)
|
||||||
.map_err(|e| e.to_string())?;
|
.map_err(|e| e.to_string())?;
|
||||||
|
let _ = c.conn.sync();
|
||||||
c.conn.map_window(client_xid).map_err(|e| e.to_string())?;
|
|
||||||
|
|
||||||
// Stack above the webview's GDK X11 surface (siblings under Tauri toplevel).
|
// Stack above the webview's GDK X11 surface (siblings under Tauri toplevel).
|
||||||
c.conn
|
c.conn
|
||||||
@@ -303,6 +335,7 @@ fn embed_window(c: &X11Conn, client_xid: u32, parent_xid: u32) -> Result<(), Str
|
|||||||
)
|
)
|
||||||
.map_err(|e| e.to_string())?;
|
.map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
|
c.conn.map_window(client_xid).map_err(|e| e.to_string())?;
|
||||||
c.conn.flush().map_err(|e| e.to_string())?;
|
c.conn.flush().map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
// Inform the client it is now embedded (XEmbed protocol).
|
// Inform the client it is now embedded (XEmbed protocol).
|
||||||
@@ -315,6 +348,26 @@ fn embed_window(c: &X11Conn, client_xid: u32, parent_xid: u32) -> Result<(), Str
|
|||||||
let _ = c.conn.send_event(false, client_xid, EventMask::NO_EVENT, event);
|
let _ = c.conn.send_event(false, client_xid, EventMask::NO_EVENT, event);
|
||||||
c.conn.flush().map_err(|e| e.to_string())?;
|
c.conn.flush().map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
|
// Verify the reparent took effect at the X11 level. If it didn't, the call
|
||||||
|
// succeeded but something (WM, compositor) reverted it.
|
||||||
|
let tree = c
|
||||||
|
.conn
|
||||||
|
.query_tree(client_xid)
|
||||||
|
.map_err(|e| e.to_string())?
|
||||||
|
.reply()
|
||||||
|
.map_err(|e| e.to_string())?;
|
||||||
|
eprintln!(
|
||||||
|
"[infinite] after reparent: parent={:#x} (wanted {:#x}), root={:#x}",
|
||||||
|
tree.parent, parent_xid, tree.root
|
||||||
|
);
|
||||||
|
if tree.parent != parent_xid {
|
||||||
|
return Err(format!(
|
||||||
|
"reparent did not stick: window {:#x} parent is {:#x}, not {:#x}. \
|
||||||
|
Likely a Wayland session — try logging in to 'Ubuntu on Xorg'.",
|
||||||
|
client_xid, tree.parent, parent_xid
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user