<NME> mod.rs
<BEF> use std::{collections::HashMap, convert::TryFrom, os::unix::net::UnixStream, sync::Arc};

use crate::AnvilState;
use smithay::{
        calloop::LoopHandle,
        wayland_server::{protocol::wl_surface::WlSurface, Client},
    },
    xwayland::XWindowManager,
};

    errors::ReplyOrIdError,
    protocol::{
        composite::{ConnectionExt as _, Redirect},
        xproto::{
            ChangeWindowAttributesAux, ConfigWindow, ConfigureWindowAux, ConnectionExt as _, EventMask,
            Window as X11Window, WindowClass,
        },
        Event,
    },
    rust_connection::{DefaultStream, RustConnection},
};
    rust_connection::{DefaultStream, RustConnection},
};

use crate::AnvilState;

use x11rb_event_source::X11Source;

        let log = self.log.clone();
        self.handle
            .insert_source(source, move |event, _, data| {
/// After XWayland was started, the actual state is kept in `X11State`.
pub struct XWm {
    handle: LoopHandle<AnvilState>,
    log: slog::Logger,
}

impl XWm {
    pub fn new(handle: LoopHandle<AnvilState>, log: slog::Logger) -> Self {
        Self { handle, log }
    }
}

impl XWindowManager for XWm {
    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
    unpaired_surfaces: HashMap<u32, (X11Window, Point<i32, Logical>)>,
}

impl X11State {
    fn start_wm(
        connection: UnixStream,
        client: Client,
        log: slog::Logger,
    ) -> Result<(Self, X11Source), Box<dyn std::error::Error>> {
        // Create an X11 connection. XWayland only uses screen 0.
        let screen = 0;
        let stream = DefaultStream::from_unix_stream(connection)?;
        let conn = RustConnection::connect_to_stream(stream, screen)?;
        let atoms = Atoms::new(&conn)?.reply()?;

        let screen = &conn.setup().roots[0];

        // Actually become the WM by redirecting some operations
        conn.change_window_attributes(
            screen.root,
            &ChangeWindowAttributesAux::default().event_mask(EventMask::SUBSTRUCTURE_REDIRECT),
        )?;

    atoms: Atoms,
    log: slog::Logger,
    unpaired_surfaces: HashMap<u32, Window>,
}

impl X11State {
    fn start_wm(connection: UnixStream, log: slog::Logger) -> Result<(Self, X11Source), Box<dyn std::error::Error>> {
        // Create an X11 connection. XWayland only uses screen 0.
        let screen = 0;
        let stream = DefaultStream::from_unix_stream(connection)?;

        // XWayland wants us to do this to function properly...?
        conn.composite_redirect_subwindows(screen.root, Redirect::MANUAL)?;

        conn.flush()?;

        let conn = Arc::new(conn);
        let wm = Self {
            conn: Arc::clone(&conn),
            atoms,
            client,
            unpaired_surfaces: Default::default(),
            log: log.clone(),
        };

        Ok((wm, X11Source::new(conn, win, atoms._ANVIL_CLOSE_CONNECTION, log)))
    }

    fn handle_event(
        &mut self,
        event: Event,
        dh: &DisplayHandle,
        space: &mut Space<Window>,
    ) -> Result<(), ReplyOrIdError> {
        debug!(self.log, "X11: Got event {:?}", event);
        match event {
            Event::ConfigureRequest(r) => {
                // Just grant the wish
                let mut aux = ConfigureWindowAux::default();
                if r.value_mask & u16::from(ConfigWindow::STACK_MODE) != 0 {
                    aux = aux.stack_mode(r.stack_mode);
                }
                if r.value_mask & u16::from(ConfigWindow::SIBLING) != 0 {
                    aux = aux.sibling(r.sibling);
                }
                if r.value_mask & u16::from(ConfigWindow::X) != 0 {
            conn: Rc::clone(&conn),
            atoms,
            unpaired_surfaces: Default::default(),
            log,
        };

                if r.value_mask & u16::from(ConfigWindow::HEIGHT) != 0 {
                    aux = aux.height(u32::try_from(r.height).unwrap());
                }
                if r.value_mask & u16::from(ConfigWindow::BORDER_WIDTH) != 0 {
                    aux = aux.border_width(u32::try_from(r.border_width).unwrap());
                }
                self.conn.configure_window(r.window, &aux)?;
            }
            Event::MapRequest(r) => {
                // Just grant the wish
                self.conn.map_window(r.window)?;
            }
            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 location = {
                        match self.conn.get_geometry(msg.window)?.reply() {
                            Ok(geo) => (geo.x as i32, geo.y as i32).into(),
                            Err(err) => {
                                error!(
                                    self.log,
                                    "Failed to get geometry for {:x}, perhaps the window was already destroyed?",
                                    msg.window;
                                    "err" => format!("{:?}", err),
                                );
                                (0, 0).into()
                            }
                        }
                    };

                    let id = msg.data.as_data32()[0];
                    let surface = self.client.object_from_protocol_id(dh, id);

                    match surface {
                        Err(_) => {
                            self.unpaired_surfaces.insert(id, (msg.window, location));
                        }
                        Ok(surface) => {
                            debug!(
                                self.log,
                                "X11 surface {:x?} corresponds to WlSurface {:x} = {:?}",
                                msg.window,
                                id,
                                surface,
                            );
                            self.new_window(msg.window, surface, location, space);
                        }
                    }
                }
            }
            _ => {}
        }
        self.conn.flush()?;
        Ok(())
    }

    fn new_window(

    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, dh: &DisplayHandle, state: &mut X11State, space: &mut Space<Window>) {
    if let Ok(client) = dh.get_client(surface.id()) {
        // Is this the Xwayland client?
        if client == state.client {
            // Is the surface among the unpaired surfaces (see comment next to WL_SURFACE_ID
            // handling above)
            if let Some((window, location)) = state.unpaired_surfaces.remove(&surface.id().protocol_id()) {
                state.new_window(window, surface.clone(), location, space);
        }
    }
}

<MSG> Add a new surface role for Xwayland surfaces

Signed-off-by: Uli Schlachter <346c0ad49ac8427b61b3b55abbe37dc0ebd524f2@znc.in>

<DFF> @@ -5,6 +5,7 @@ use smithay::{
         calloop::LoopHandle,
         wayland_server::{protocol::wl_surface::WlSurface, Client},
     },
+    wayland::compositor::CompositorToken,
     xwayland::XWindowManager,
 };
 
@@ -22,7 +23,11 @@ use x11rb::{
     rust_connection::{DefaultStream, RustConnection},
 };
 
-use crate::AnvilState;
+use crate::{
+    shell::{MyWindowMap, Roles},
+    window_map::Kind,
+    AnvilState,
+};
 
 use x11rb_event_source::X11Source;
 
@@ -32,18 +37,31 @@ mod x11rb_event_source;
 /// After XWayland was started, the actual state is kept in `X11State`.
 pub struct XWm {
     handle: LoopHandle<AnvilState>,
+    token: CompositorToken<Roles>,
+    window_map: Rc<RefCell<MyWindowMap>>,
     log: slog::Logger,
 }
 
 impl XWm {
-    pub fn new(handle: LoopHandle<AnvilState>, log: slog::Logger) -> Self {
-        Self { handle, log }
+    pub fn new(
+        handle: LoopHandle<AnvilState>,
+        token: CompositorToken<Roles>,
+        window_map: Rc<RefCell<MyWindowMap>>,
+        log: slog::Logger,
+    ) -> Self {
+        Self {
+            handle,
+            token,
+            window_map,
+            log,
+        }
     }
 }
 
 impl XWindowManager for XWm {
     fn xwayland_ready(&mut self, connection: UnixStream, client: Client) {
-        let (wm, source) = X11State::start_wm(connection, self.log.clone()).unwrap();
+        let (wm, source) =
+            X11State::start_wm(connection, self.token, self.window_map.clone(), self.log.clone()).unwrap();
         let wm = Rc::new(RefCell::new(wm));
         client.data_map().insert_if_missing(|| Rc::clone(&wm));
         self.handle
@@ -73,10 +91,17 @@ struct X11State {
     atoms: Atoms,
     log: slog::Logger,
     unpaired_surfaces: HashMap<u32, Window>,
+    token: CompositorToken<Roles>,
+    window_map: Rc<RefCell<MyWindowMap>>,
 }
 
 impl X11State {
-    fn start_wm(connection: UnixStream, log: slog::Logger) -> Result<(Self, X11Source), Box<dyn std::error::Error>> {
+    fn start_wm(
+        connection: UnixStream,
+        token: CompositorToken<Roles>,
+        window_map: Rc<RefCell<MyWindowMap>>,
+        log: slog::Logger,
+    ) -> Result<(Self, X11Source), Box<dyn std::error::Error>> {
         // Create an X11 connection. XWayland only uses screen 0.
         let screen = 0;
         let stream = DefaultStream::from_unix_stream(connection)?;
@@ -119,6 +144,8 @@ impl X11State {
             conn: Rc::clone(&conn),
             atoms,
             unpaired_surfaces: Default::default(),
+            token,
+            window_map,
             log,
         };
 
@@ -187,6 +214,17 @@ impl X11State {
 
     fn new_window(&mut self, window: Window, surface: WlSurface) {
         debug!(self.log, "Matched X11 surface {:x?} to {:x?}", window, surface);
+
+        if self.token.give_role_with(&surface, X11SurfaceRole).is_err() {
+            // It makes no sense to post a protocol error here since that would only kill Xwayland
+            error!(self.log, "Surface {:x?} already has a role?!", surface);
+            return;
+        }
+
+        let x11surface = X11Surface { surface };
+        self.window_map
+            .borrow_mut()
+            .insert(Kind::X11(x11surface), (0, 0));
     }
 }
 
@@ -204,3 +242,28 @@ pub fn commit_hook(surface: &WlSurface) {
         }
     }
 }
+
+pub struct X11SurfaceRole;
+
+#[derive(Clone)]
+pub struct X11Surface {
+    surface: WlSurface,
+}
+
+impl X11Surface {
+    pub fn alive(&self) -> bool {
+        self.surface.as_ref().is_alive()
+    }
+
+    pub fn equals(&self, other: &Self) -> bool {
+        self.alive() && other.alive() && self.surface.as_ref().equals(&other.surface.as_ref())
+    }
+
+    pub fn get_surface(&self) -> Option<&WlSurface> {
+        if self.alive() {
+            Some(&self.surface)
+        } else {
+            None
+        }
+    }
+}

Add a new surface role for Xwayland surfaces