<NME> xserver.rs
<BEF> /*
 * Steps of XWayland server creation
 *
 * Sockets to create:
 * - a pair for XWayland to connect to smithay as a wayland client, we use our
 *   end to insert the XWayland client in the display
 * - a pair for smithay to connect to XWayland as a WM, we give our end to the
 *   WM and it deals with it
 * - 2 listening sockets on which the XWayland server will listen. We need to
 *   bind them ourselves so we know what value put in the $DISPLAY env variable.
 *   This involves some dance with a lockfile to ensure there is no collision with
 *   an other starting xserver
 *   if we listen on display $D, their paths are respectively:
 *   - /tmp/.X11-unix/X$D
 *   - @/tmp/.X11-unix/X$D (abstract socket)
 *
 * The XWayland server is spawned via an intermediate shell
 * -> wlroots does a double-fork while weston a single one, why ??
 *    -> https://stackoverflow.com/questions/881388/
 * -> once it is started, it will check if SIGUSR1 is set to ignored. If so,
 *    if will consider its parent as "smart", and send a SIGUSR1 signal when
 *    startup completes. We want to catch this so we can launch the VM.
 * -> we need to track if the XWayland crashes, to restart it
 *
 * cf https://github.com/swaywm/wlroots/blob/master/xwayland/xwayland.c
 *
 * Setting SIGUSR1 handler is complicated in multithreaded program, because
 * Xwayland will send SIGUSR1 to the process, and if a thread cannot handle
 * SIGUSR1, that thread will be killed.
 *
 * Double-fork can tackle this issue, but this is also very complex in a
 * a multithread program, after forking only signal-safe functions can be used.
 * The only workaround is to fork early before any other thread starts, but
 * doing so will expose an unsafe interface.
 *
 * We use an intermediate shell to translate the signal to simple fd IO.
 * We ask sh to setup SIGUSR1 handler, and in a subshell mute SIGUSR1 and exec
 * Xwayland. When the SIGUSR1 is received, it can communicate to us via redirected
 * STDOUT.
 */
use std::{
    any::Any,
    cell::RefCell,
    env,
    io::{self, Read},
    os::unix::{
        io::{AsRawFd, IntoRawFd, RawFd},
        net::UnixStream,
        process::CommandExt,
    },
    process::{ChildStdout, Command, Stdio},
    rc::Rc,
    sync::Arc,
};

use calloop::{
    channel::{sync_channel, Channel, SyncSender},
    generic::Generic,
    Interest, LoopHandle, Mode,
};

use slog::{error, info, o};

use wayland_server::{Client, Display, Filter};

use super::x11_sockets::{prepare_x11_sockets, X11Lock};

/// The XWayland handle
#[derive(Debug)]
pub struct XWayland<Data> {
    inner: Rc<RefCell<Inner<Data>>>,
}

/// Events generated by the XWayland manager
    inner: Arc<Mutex<Inner>>,
}

/// Events generated by the XWayland manager
///
/// disconnecting several time in a row, but only a single connection will
/// be active at any given time.
#[derive(Debug)]
pub enum XWaylandEvent {
    /// The XWayland server is ready
    Ready {
        /// Privileged X11 connection to XWayland
        connection: UnixStream,
        /// Wayland client representing XWayland
        client: Client,
    },
    /// The XWayland server exited
    Exited,
}

impl<Data: Any + 'static> XWayland<Data> {
    /// Create a new XWayland manager
    ///
    /// This function returns both the [`XWayland`] handle and an [`XWaylandSource`] that needs to be inserted
    /// into the [`calloop`] event loop, producing the Xwayland startup and shutdown events.
    pub fn new<L>(
        handle: LoopHandle<'static, Data>,
        display: Rc<RefCell<Display>>,
        logger: L,
    ) -> (XWayland<Data>, XWaylandSource)
    where
        L: Into<Option<::slog::Logger>>,
    {
    where
        // We don't expect to ever have more than 2 messages in flight, if XWayland got ready and then died right away
        let (sender, channel) = sync_channel(2);
        let inner = Rc::new(RefCell::new(Inner {
            handle,
            wayland_display: display,
            instance: None,
            sender,
            log: log.new(o!("smithay_module" => "XWayland")),
            instance: None,
            sender,
            dh: dh.clone(),
            log: log.new(o!("smithay_module" => "XWayland")),
        }));
        (XWayland { inner }, XWaylandSource { channel })
    }

    /// Attempt to start the XWayland instance
    /// wayland `Client` for XWayland.
    ///
    /// Does nothing if XWayland is already started or starting.
    pub fn start(&self) -> std::io::Result<()> {
        launch(&self.inner)
    }

    /// Shutdown XWayland
        let dh = self.inner.lock().unwrap().dh.clone();
        launch(&self.inner, loop_handle, dh)
    }

    /// Shutdown XWayland
    }
}

impl<Data> Drop for XWayland<Data> {
    fn drop(&mut self) {
        self.inner.borrow_mut().shutdown();
    }

impl Drop for XWayland {
#[derive(Debug)]
struct XWaylandInstance {
    display_lock: X11Lock,
    wayland_client: Option<Client>,
    wm_fd: Option<UnixStream>,
    child_stdout: Option<ChildStdout>,
}

// Inner implementation of the XWayland manager
#[derive(Debug)]
struct Inner<Data> {
    sender: SyncSender<XWaylandEvent>,
    handle: LoopHandle<'static, Data>,
    wayland_display: Rc<RefCell<Display>>,
    instance: Option<XWaylandInstance>,
    log: ::slog::Logger,
}
#[derive(Debug)]
// Launch an XWayland server
//
// Does nothing if there is already a launched instance
fn launch<Data: Any>(inner: &Rc<RefCell<Inner<Data>>>) -> std::io::Result<()> {
    let mut guard = inner.borrow_mut();
    if guard.instance.is_some() {
        return Ok(());
struct XWaylandClientData {
    inner: Arc<Mutex<Inner>>,
}

impl ClientData for XWaylandClientData {
    fn initialized(&self, _client_id: ClientId) {}
    fn disconnected(&self, _client_id: ClientId, _reason: DisconnectReason) {
        // If we are unable to take a lock we are most likely called during
        // a shutdown. This will definitely be the case when the compositor exits
        // and the XWayland instance is dropped.
        if let Ok(mut guard) = self.inner.try_lock() {
    // Setup the associated wayland client to be created in an idle callback, so that we don't need
    // to access the dispatch_data *right now*
    let idle_inner = inner.clone();
    guard.handle.insert_idle(move |data| {
        let mut guard = idle_inner.borrow_mut();
        let guard = &mut *guard;
        if let Some(ref mut instance) = guard.instance {
            // create the wayland client for XWayland
            let client = unsafe {
                guard
                    .wayland_display
                    .borrow_mut()
                    .create_client(wl_me.into_raw_fd(), data)
            };
            client.data_map().insert_if_missing(|| idle_inner.clone());
            client.add_destructor(Filter::new(|e: Arc<_>, _, _| client_destroy::<Data>(&e)));

            instance.wayland_client = Some(client);
        }
    });

) -> io::Result<()> {
    let mut guard = inner.lock().unwrap();
    if guard.instance.is_some() {
        return Ok(());
    }

    info!(guard.log, "Starting XWayland");
    };

    let inner = inner.clone();
    guard
        .handle
        .insert_source(
            Generic::<_, io::Error>::new(child_stdout.as_raw_fd(), Interest::READ, Mode::Level),
            move |_, _, _| {

    // all is ready, we can do the fork dance
    let child_stdout = match spawn_xwayland(lock.display(), wl_x11, x_wm_x11, &x_fds) {
        Ok(child_stdout) => child_stdout,
        Err(e) => {
            error!(guard.log, "XWayland failed to spawn"; "err" => format!("{:?}", e));

    guard.instance = Some(XWaylandInstance {
        display_lock: lock,
        wayland_client: None,
        wm_fd: Some(x_wm_me),
        child_stdout: Some(child_stdout),
    });
            Generic::<_, io::Error>::new(child_stdout.as_raw_fd(), Interest::READ, Mode::Level),
            move |_, _, _| {
                // the closure must be called exactly one time, this cannot panic
                xwayland_ready(&loop_inner);
                Ok(calloop::PostAction::Remove)
            },
        )
/// of type [`XWaylandEvent`], which notify you about startup and shutdown of the Xwayland
/// instance.
#[derive(Debug)]
pub struct XWaylandSource {
    channel: Channel<XWaylandEvent>,
}
        wayland_client_fd: client_fd,
        wm_fd: Some(x_wm_me),
        child_stdout,
    });

    Ok(())
}

/// An event source for monitoring XWayland status
        readiness: calloop::Readiness,
        token: calloop::Token,
        mut callback: F,
    ) -> std::io::Result<calloop::PostAction>
    where
        F: FnMut(Self::Event, &mut Self::Metadata) -> Self::Ret,
    {
        self.channel
            .process_events(readiness, token, |event, &mut ()| match event {
                calloop::channel::Event::Msg(msg) => callback(msg, &mut ()),
                calloop::channel::Event::Closed => {}
            })
            .map_err(|err| io::Error::new(io::ErrorKind::BrokenPipe, err))
    }
    type Error = io::Error;

    fn process_events<F>(
        &mut self,
        readiness: calloop::Readiness,
        token: calloop::Token,
        mut callback: F,
    ) -> io::Result<calloop::PostAction>
    where
        F: FnMut(Self::Event, &mut Self::Metadata) -> Self::Ret,
    {
        self.channel
            .process_events(readiness, token, |event, &mut ()| match event {
                channel::Event::Msg(msg) => callback(msg, &mut ()),
                channel::Event::Closed => {}
            })
            .map_err(|err| io::Error::new(io::ErrorKind::BrokenPipe, err))
    }

    }
}

impl<Data> Inner<Data> {
    // Shutdown the XWayland server and cleanup everything
    fn shutdown(&mut self) {
        // don't do anything if not running
        if let Some(instance) = self.instance.take() {
            info!(self.log, "Shutting down XWayland.");
            // kill the client
            if let Some(client) = instance.wayland_client {
                client.kill();
            }
            // send error occurs if the user dropped the channel... We cannot do much except ignore.
            let _ = self.sender.send(XWaylandEvent::Exited);

        self.channel.reregister(poll, factory)
    }

    fn unregister(&mut self, poll: &mut calloop::Poll) -> calloop::Result<()> {
        self.channel.unregister(poll)
    }
}

impl Inner {
    }
}

fn client_destroy<Data: 'static>(map: &::wayland_server::UserDataMap) {
    let inner = map.get::<Rc<RefCell<Inner<Data>>>>().unwrap();
    // If we are unable to take a lock we are most likely called during
    // a shutdown. This will definitely be the case when the compositor exits
    // and the XWayland instance is dropped.
    if let Ok(mut guard) = inner.try_borrow_mut() {
        guard.shutdown();
    }
}

fn xwayland_ready<Data: 'static>(inner: &Rc<RefCell<Inner<Data>>>) {
    // Lots of re-borrowing to please the borrow-checker
    let mut guard = inner.borrow_mut();
    let guard = &mut *guard;
                .kill_client(instance.wayland_client.id(), DisconnectReason::ConnectionClosed);

            // send error occurs if the user dropped the channel... We cannot do much except ignore.
            let _ = self.sender.send(XWaylandEvent::Exited);

            // All connections and lockfiles are cleaned by their destructors

            // Remove DISPLAY from the env
            ::std::env::remove_var("DISPLAY");
            // We do like wlroots:
            // > We do not kill the XWayland process, it dies to broken pipe
            // > after we close our side of the wm/wl fds. This is more reliable
            // > than trying to kill something that might no longer be XWayland.
    };

    if success {
        // setup the environemnt
        ::std::env::set_var("DISPLAY", format!(":{}", instance.display_lock.display()));

        // signal the WM
    let guard = &mut *guard;
    info!(guard.log, "XWayland ready");
    // instance should never be None at this point
    let instance = guard.instance.as_mut().unwrap();
    // neither the child_stdout
        // send error occurs if the user dropped the channel... We cannot do much except ignore.
        let _ = guard.sender.send(XWaylandEvent::Ready {
            connection: instance.wm_fd.take().unwrap(), // This is a bug if None
            client: instance.wayland_client.clone().unwrap(),
        });
    } else {
        error!(
            false
        }
    };

    if success {
        // setup the environment
        ::std::env::set_var("DISPLAY", format!(":{}", instance.display_lock.display()));

        // signal the WM
        info!(
            guard.log,
            "XWayland is ready on DISPLAY \":{}\", signaling the WM.",
            instance.display_lock.display()
        );
        // send error occurs if the user dropped the channel... We cannot do much except ignore.
        let _ = guard.sender.send(XWaylandEvent::Ready {
            connection: instance.wm_fd.take().unwrap(), // This is a bug if None
            client: instance.wayland_client.clone(),
            client_fd: instance.wayland_client_fd,
            display: instance.display_lock.display(),
        });
    } else {
        error!(
            guard.log,
            "XWayland crashed at startup, will not try to restart it."
        );
    }
}

/// Spawn XWayland with given sockets on given display
///
/// Returns a pipe that outputs 'S' upon successful launch.
fn spawn_xwayland(
    display: u32,
    wayland_socket: UnixStream,
    wm_socket: UnixStream,
    listen_sockets: &[UnixStream],
) -> io::Result<ChildStdout> {
    let mut command = Command::new("sh");

    // We use output stream to communicate because FD is easier to handle than exit code.
    command.stdout(Stdio::piped());

    let mut xwayland_args = format!(":{} -rootless -terminate -wm {}", display, wm_socket.as_raw_fd());
    for socket in listen_sockets {
        // Will only fail to write on OOM, so this panic is fine.
        write!(xwayland_args, " -listenfd {}", socket.as_raw_fd()).unwrap();
    }
    // This command let sh to:
    // * Set up signal handler for USR1
    // * Launch Xwayland with USR1 ignored so Xwayland will signal us when it is ready (also redirect
    //   Xwayland's STDOUT to STDERR so its output, if any, won't distract us)
    // * Print "S" and exit if USR1 is received
    command.arg("-c").arg(format!(
        "trap 'echo S' USR1; (trap '' USR1; exec Xwayland {}) 1>&2 & wait",
        xwayland_args
    ));

    // Setup the environment: clear everything except PATH and XDG_RUNTIME_DIR
    command.env_clear();
    for (key, value) in env::vars_os() {
        if key.to_str() == Some("PATH") || key.to_str() == Some("XDG_RUNTIME_DIR") {
            command.env(key, value);
            continue;
        }
    }
    command.env("WAYLAND_SOCKET", format!("{}", wayland_socket.as_raw_fd()));

    unsafe {
        let wayland_socket_fd = wayland_socket.as_raw_fd();
        let wm_socket_fd = wm_socket.as_raw_fd();
        let socket_fds: Vec<_> = listen_sockets.iter().map(|socket| socket.as_raw_fd()).collect();
        command.pre_exec(move || {
            // unset the CLOEXEC flag from the sockets we need to pass
            // to xwayland
            unset_cloexec(wayland_socket_fd)?;
            unset_cloexec(wm_socket_fd)?;
            for &socket in socket_fds.iter() {
                unset_cloexec(socket)?;
            }
            Ok(())
        });
    }

    let mut child = command.spawn()?;
    Ok(child.stdout.take().expect("stdout should be piped"))
}

/// Remove the `O_CLOEXEC` flag from this `Fd`
///
/// This means that the `Fd` will *not* be automatically
/// closed when we `exec()` into XWayland
fn unset_cloexec(fd: RawFd) -> io::Result<()> {
    use nix::fcntl::{fcntl, FcntlArg, FdFlag};
    fcntl(fd, FcntlArg::F_SETFD(FdFlag::empty()))?;
    Ok(())
}

<MSG> XWayland 0.30

<DFF> @@ -39,36 +39,32 @@
  * STDOUT.
  */
 use std::{
-    any::Any,
     cell::RefCell,
     env,
     io::{self, Read},
     os::unix::{
-        io::{AsRawFd, IntoRawFd, RawFd},
+        io::{AsRawFd, RawFd},
         net::UnixStream,
         process::CommandExt,
     },
     process::{ChildStdout, Command, Stdio},
     rc::Rc,
-    sync::Arc,
 };
 
 use calloop::{
-    channel::{sync_channel, Channel, SyncSender},
+    channel::{self, sync_channel, Channel, SyncSender},
     generic::Generic,
     Interest, LoopHandle, Mode,
 };
 
 use slog::{error, info, o};
 
-use wayland_server::{Client, Display, Filter};
-
 use super::x11_sockets::{prepare_x11_sockets, X11Lock};
 
 /// The XWayland handle
 #[derive(Debug)]
-pub struct XWayland<Data> {
-    inner: Rc<RefCell<Inner<Data>>>,
+pub struct XWayland {
+    inner: Rc<RefCell<Inner>>,
 }
 
 /// Events generated by the XWayland manager
@@ -80,28 +76,39 @@ pub struct XWayland<Data> {
 /// disconnecting several time in a row, but only a single connection will
 /// be active at any given time.
 #[derive(Debug)]
+#[must_use = "Connection events must be handled to prevent fd leaking"]
 pub enum XWaylandEvent {
     /// The XWayland server is ready
     Ready {
         /// Privileged X11 connection to XWayland
         connection: UnixStream,
+
         /// Wayland client representing XWayland
-        client: Client,
+        ///
+        /// This should be used to create a Wayland client using [`Display::insert_client`](wayland_server::Display::insert_client).
+        ///
+        /// When the client is disconnected, you should [`shutdown`](XWayland::shutdown) XWayland.
+        client: UnixStream,
+
+        /// The display number the XWayland server is available at.
+        ///
+        /// This may be used if you wish to set the `DISPLAY` variable manually when spawning processes that
+        /// may use XWayland.
+        display: u32,
     },
+
     /// The XWayland server exited
+    ///
+    /// This event is sent when the [`XWayland`] handle is dropped.
     Exited,
 }
 
-impl<Data: Any + 'static> XWayland<Data> {
+impl XWayland {
     /// Create a new XWayland manager
     ///
     /// This function returns both the [`XWayland`] handle and an [`XWaylandSource`] that needs to be inserted
     /// into the [`calloop`] event loop, producing the Xwayland startup and shutdown events.
-    pub fn new<L>(
-        handle: LoopHandle<'static, Data>,
-        display: Rc<RefCell<Display>>,
-        logger: L,
-    ) -> (XWayland<Data>, XWaylandSource)
+    pub fn new<L>(logger: L) -> (XWayland, XWaylandSource)
     where
         L: Into<Option<::slog::Logger>>,
     {
@@ -109,8 +116,6 @@ impl<Data: Any + 'static> XWayland<Data> {
         // We don't expect to ever have more than 2 messages in flight, if XWayland got ready and then died right away
         let (sender, channel) = sync_channel(2);
         let inner = Rc::new(RefCell::new(Inner {
-            handle,
-            wayland_display: display,
             instance: None,
             sender,
             log: log.new(o!("smithay_module" => "XWayland")),
@@ -126,8 +131,8 @@ impl<Data: Any + 'static> XWayland<Data> {
     /// wayland `Client` for XWayland.
     ///
     /// Does nothing if XWayland is already started or starting.
-    pub fn start(&self) -> std::io::Result<()> {
-        launch(&self.inner)
+    pub fn start<D>(&self, loop_handle: LoopHandle<'_, D>) -> io::Result<()> {
+        launch(&self.inner, loop_handle)
     }
 
     /// Shutdown XWayland
@@ -139,7 +144,7 @@ impl<Data: Any + 'static> XWayland<Data> {
     }
 }
 
-impl<Data> Drop for XWayland<Data> {
+impl Drop for XWayland {
     fn drop(&mut self) {
         self.inner.borrow_mut().shutdown();
     }
@@ -148,17 +153,15 @@ impl<Data> Drop for XWayland<Data> {
 #[derive(Debug)]
 struct XWaylandInstance {
     display_lock: X11Lock,
-    wayland_client: Option<Client>,
+    wayland_client_fd: Option<UnixStream>,
     wm_fd: Option<UnixStream>,
     child_stdout: Option<ChildStdout>,
 }
 
 // Inner implementation of the XWayland manager
 #[derive(Debug)]
-struct Inner<Data> {
+struct Inner {
     sender: SyncSender<XWaylandEvent>,
-    handle: LoopHandle<'static, Data>,
-    wayland_display: Rc<RefCell<Display>>,
     instance: Option<XWaylandInstance>,
     log: ::slog::Logger,
 }
@@ -166,7 +169,7 @@ struct Inner<Data> {
 // Launch an XWayland server
 //
 // Does nothing if there is already a launched instance
-fn launch<Data: Any>(inner: &Rc<RefCell<Inner<Data>>>) -> std::io::Result<()> {
+fn launch<D>(inner: &Rc<RefCell<Inner>>, loop_handle: LoopHandle<'_, D>) -> io::Result<()> {
     let mut guard = inner.borrow_mut();
     if guard.instance.is_some() {
         return Ok(());
@@ -184,21 +187,12 @@ fn launch<Data: Any>(inner: &Rc<RefCell<Inner<Data>>>) -> std::io::Result<()> {
     // Setup the associated wayland client to be created in an idle callback, so that we don't need
     // to access the dispatch_data *right now*
     let idle_inner = inner.clone();
-    guard.handle.insert_idle(move |data| {
+    loop_handle.insert_idle(move |_| {
         let mut guard = idle_inner.borrow_mut();
         let guard = &mut *guard;
+
         if let Some(ref mut instance) = guard.instance {
-            // create the wayland client for XWayland
-            let client = unsafe {
-                guard
-                    .wayland_display
-                    .borrow_mut()
-                    .create_client(wl_me.into_raw_fd(), data)
-            };
-            client.data_map().insert_if_missing(|| idle_inner.clone());
-            client.add_destructor(Filter::new(|e: Arc<_>, _, _| client_destroy::<Data>(&e)));
-
-            instance.wayland_client = Some(client);
+            instance.wayland_client_fd = Some(wl_me);
         }
     });
 
@@ -212,8 +206,7 @@ fn launch<Data: Any>(inner: &Rc<RefCell<Inner<Data>>>) -> std::io::Result<()> {
     };
 
     let inner = inner.clone();
-    guard
-        .handle
+    loop_handle
         .insert_source(
             Generic::<_, io::Error>::new(child_stdout.as_raw_fd(), Interest::READ, Mode::Level),
             move |_, _, _| {
@@ -226,7 +219,7 @@ fn launch<Data: Any>(inner: &Rc<RefCell<Inner<Data>>>) -> std::io::Result<()> {
 
     guard.instance = Some(XWaylandInstance {
         display_lock: lock,
-        wayland_client: None,
+        wayland_client_fd: None,
         wm_fd: Some(x_wm_me),
         child_stdout: Some(child_stdout),
     });
@@ -240,6 +233,7 @@ fn launch<Data: Any>(inner: &Rc<RefCell<Inner<Data>>>) -> std::io::Result<()> {
 /// of type [`XWaylandEvent`], which notify you about startup and shutdown of the Xwayland
 /// instance.
 #[derive(Debug)]
+#[must_use]
 pub struct XWaylandSource {
     channel: Channel<XWaylandEvent>,
 }
@@ -255,14 +249,14 @@ impl calloop::EventSource for XWaylandSource {
         readiness: calloop::Readiness,
         token: calloop::Token,
         mut callback: F,
-    ) -> std::io::Result<calloop::PostAction>
+    ) -> io::Result<calloop::PostAction>
     where
         F: FnMut(Self::Event, &mut Self::Metadata) -> Self::Ret,
     {
         self.channel
             .process_events(readiness, token, |event, &mut ()| match event {
-                calloop::channel::Event::Msg(msg) => callback(msg, &mut ()),
-                calloop::channel::Event::Closed => {}
+                channel::Event::Msg(msg) => callback(msg, &mut ()),
+                channel::Event::Closed => {}
             })
             .map_err(|err| io::Error::new(io::ErrorKind::BrokenPipe, err))
     }
@@ -288,16 +282,13 @@ impl calloop::EventSource for XWaylandSource {
     }
 }
 
-impl<Data> Inner<Data> {
+impl Inner {
     // Shutdown the XWayland server and cleanup everything
     fn shutdown(&mut self) {
         // don't do anything if not running
-        if let Some(instance) = self.instance.take() {
+        if self.instance.take().is_some() {
             info!(self.log, "Shutting down XWayland.");
-            // kill the client
-            if let Some(client) = instance.wayland_client {
-                client.kill();
-            }
+
             // send error occurs if the user dropped the channel... We cannot do much except ignore.
             let _ = self.sender.send(XWaylandEvent::Exited);
 
@@ -313,17 +304,7 @@ impl<Data> Inner<Data> {
     }
 }
 
-fn client_destroy<Data: 'static>(map: &::wayland_server::UserDataMap) {
-    let inner = map.get::<Rc<RefCell<Inner<Data>>>>().unwrap();
-    // If we are unable to take a lock we are most likely called during
-    // a shutdown. This will definitely be the case when the compositor exits
-    // and the XWayland instance is dropped.
-    if let Ok(mut guard) = inner.try_borrow_mut() {
-        guard.shutdown();
-    }
-}
-
-fn xwayland_ready<Data: 'static>(inner: &Rc<RefCell<Inner<Data>>>) {
+fn xwayland_ready(inner: &Rc<RefCell<Inner>>) {
     // Lots of re-borrowing to please the borrow-checker
     let mut guard = inner.borrow_mut();
     let guard = &mut *guard;
@@ -343,7 +324,7 @@ fn xwayland_ready<Data: 'static>(inner: &Rc<RefCell<Inner<Data>>>) {
     };
 
     if success {
-        // setup the environemnt
+        // setup the environment
         ::std::env::set_var("DISPLAY", format!(":{}", instance.display_lock.display()));
 
         // signal the WM
@@ -355,7 +336,8 @@ fn xwayland_ready<Data: 'static>(inner: &Rc<RefCell<Inner<Data>>>) {
         // send error occurs if the user dropped the channel... We cannot do much except ignore.
         let _ = guard.sender.send(XWaylandEvent::Ready {
             connection: instance.wm_fd.take().unwrap(), // This is a bug if None
-            client: instance.wayland_client.clone().unwrap(),
+            client: instance.wayland_client_fd.take().unwrap(),
+            display: instance.display_lock.display(),
         });
     } else {
         error!(

XWayland 0.30