Map between X11 Windows and WlSurfaces
Xwayland gives us a mapping between X11 window and WlSurface IDs via special WL_SURFACE_ID messages. This commit uses these messages to find the corresponding WlSurface. For this, the new client.get_resource API from wayland-server is needed. Signed-off-by: Uli Schlachter <psychon@znc.in>
This commit is contained in:
parent
a6c40a002b
commit
734b541ecd
|
@ -31,7 +31,7 @@ udev = { version = "0.5", optional = true }
|
|||
wayland-commons = { version = "0.28", optional = true }
|
||||
wayland-egl = { version = "0.28", optional = true }
|
||||
wayland-protocols = { version = "0.28", features = ["unstable_protocols", "server"], optional = true }
|
||||
wayland-server = { version = "0.28", optional = true }
|
||||
wayland-server = { version = "0.28.3", optional = true }
|
||||
wayland-sys = { version = "0.28", optional = true }
|
||||
winit = { version = "0.23.0", optional = true }
|
||||
xkbcommon = "0.4.0"
|
||||
|
|
|
@ -768,6 +768,9 @@ fn surface_commit(
|
|||
buffer_utils: &BufferUtils,
|
||||
window_map: &RefCell<MyWindowMap>,
|
||||
) {
|
||||
#[cfg(feature = "xwayland")]
|
||||
super::xwayland::commit_hook(surface);
|
||||
|
||||
let mut geometry = None;
|
||||
let mut min_size = (0, 0);
|
||||
let mut max_size = (0, 0);
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use std::{convert::TryFrom, os::unix::net::UnixStream, rc::Rc};
|
||||
use std::{cell::RefCell, collections::HashMap, convert::TryFrom, os::unix::net::UnixStream, rc::Rc};
|
||||
|
||||
use smithay::{
|
||||
reexports::{
|
||||
calloop::LoopHandle,
|
||||
wayland_server::Client,
|
||||
wayland_server::{protocol::wl_surface::WlSurface, Client},
|
||||
},
|
||||
xwayland::XWindowManager,
|
||||
};
|
||||
|
@ -15,7 +15,7 @@ use x11rb::{
|
|||
composite::{ConnectionExt as _, Redirect},
|
||||
xproto::{
|
||||
ChangeWindowAttributesAux, ConfigWindow, ConfigureWindowAux, ConnectionExt as _, EventMask,
|
||||
WindowClass,
|
||||
Window, WindowClass,
|
||||
},
|
||||
Event,
|
||||
},
|
||||
|
@ -42,12 +42,15 @@ impl XWm {
|
|||
}
|
||||
|
||||
impl XWindowManager for XWm {
|
||||
fn xwayland_ready(&mut self, connection: UnixStream, _client: Client) {
|
||||
let (mut wm, source) = X11State::start_wm(connection, self.log.clone()).unwrap();
|
||||
fn xwayland_ready(&mut self, connection: UnixStream, client: Client) {
|
||||
let (wm, source) = X11State::start_wm(connection, self.log.clone()).unwrap();
|
||||
let wm = Rc::new(RefCell::new(wm));
|
||||
client.data_map().insert_if_missing(|| Rc::clone(&wm));
|
||||
self.handle
|
||||
.insert_source(source, move |events, _, _| {
|
||||
let mut wm = wm.borrow_mut();
|
||||
for event in events.into_iter() {
|
||||
wm.handle_event(event)?;
|
||||
wm.handle_event(event, &client)?;
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
|
@ -69,6 +72,7 @@ struct X11State {
|
|||
conn: Rc<RustConnection>,
|
||||
atoms: Atoms,
|
||||
log: slog::Logger,
|
||||
unpaired_surfaces: HashMap<u32, Window>,
|
||||
}
|
||||
|
||||
impl X11State {
|
||||
|
@ -114,13 +118,14 @@ impl X11State {
|
|||
let wm = Self {
|
||||
conn: Rc::clone(&conn),
|
||||
atoms,
|
||||
unpaired_surfaces: Default::default(),
|
||||
log,
|
||||
};
|
||||
|
||||
Ok((wm, X11Source::new(conn)))
|
||||
}
|
||||
|
||||
fn handle_event(&mut self, event: Event) -> Result<(), ReplyOrIdError> {
|
||||
fn handle_event(&mut self, event: Event, client: &Client) -> Result<(), ReplyOrIdError> {
|
||||
debug!(self.log, "X11: Got event {:?}", event);
|
||||
match event {
|
||||
Event::ConfigureRequest(r) => {
|
||||
|
@ -155,15 +160,47 @@ impl X11State {
|
|||
}
|
||||
Event::ClientMessage(msg) => {
|
||||
if msg.type_ == self.atoms.WL_SURFACE_ID {
|
||||
// We get a WL_SURFACE_ID message when Xwayland creates a WlSurface for a
|
||||
// window. Both the creation of the surface and this client message happen at
|
||||
// roughly the same time and are sent over different sockets (X11 socket and
|
||||
// wayland socket). Thus, we could receive these two in any order. Hence, it
|
||||
// can happen that we get None below when X11 was faster than Wayland.
|
||||
|
||||
let id = msg.data.as_data32()[0];
|
||||
let surface = client.get_resource::<WlSurface>(id);
|
||||
info!(
|
||||
self.log,
|
||||
"X11 surface {:x?} corresponds to WlSurface {:x}", msg.window, id,
|
||||
"X11 surface {:x?} corresponds to WlSurface {:x} = {:?}", msg.window, id, surface,
|
||||
);
|
||||
match surface {
|
||||
None => {
|
||||
self.unpaired_surfaces.insert(id, msg.window);
|
||||
}
|
||||
Some(surface) => self.new_window(msg.window, surface),
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn new_window(&mut self, window: Window, surface: WlSurface) {
|
||||
debug!(self.log, "Matched X11 surface {:x?} to {:x?}", window, surface);
|
||||
}
|
||||
}
|
||||
|
||||
// Called when a WlSurface commits.
|
||||
pub fn commit_hook(surface: &WlSurface) {
|
||||
// Is this the Xwayland client?
|
||||
if let Some(client) = surface.as_ref().client() {
|
||||
if let Some(x11) = client.data_map().get::<Rc<RefCell<X11State>>>() {
|
||||
let mut inner = x11.borrow_mut();
|
||||
// Is the surface among the unpaired surfaces (see comment next to WL_SURFACE_ID
|
||||
// handling above)
|
||||
if let Some(window) = inner.unpaired_surfaces.remove(&surface.as_ref().id()) {
|
||||
inner.new_window(window, surface.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue