diff --git a/CHANGELOG.md b/CHANGELOG.md index c10762e..ffc49ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ #### Backends +- `x11rb` event source integration used in anvil's XWayland implementation is now part of smithay at `utils::x11rb`. Enabled through the `x11rb_event_source` feature. - New `DrmNode` type in drm backend. This is primarily for use a backend which needs to run as client inside another session. ### Bugfixes diff --git a/Cargo.toml b/Cargo.toml index 42726c7..8bb7613 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,6 +46,7 @@ wayland-protocols = { version = "0.29.0", features = ["unstable_protocols", "sta wayland-server = { version = "0.29.0", optional = true } wayland-sys = { version = "0.29.0", optional = true } winit = { version = "0.25.0", optional = true } +x11rb = { version = "0.9.0", optional = true } xkbcommon = "0.4.0" scan_fmt = { version = "0.2.3", default-features = false } @@ -71,6 +72,7 @@ backend_session_libseat = ["backend_session", "libseat"] renderer_gl = ["gl_generator", "backend_egl"] use_system_lib = ["wayland_frontend", "wayland-sys", "wayland-server/use_system_lib"] wayland_frontend = ["wayland-server", "wayland-commons", "wayland-protocols", "tempfile"] +x11rb_event_source = ["x11rb"] xwayland = ["wayland_frontend"] test_all_features = ["default", "use_system_lib", "wayland-server/dlopen"] diff --git a/anvil/Cargo.toml b/anvil/Cargo.toml index 4dacbcf..e864c65 100644 --- a/anvil/Cargo.toml +++ b/anvil/Cargo.toml @@ -28,7 +28,7 @@ features = [ "wayland_frontend", "slog-stdlog" ] [dependencies.x11rb] optional = true -version = "0.8" +version = "0.9.0" default-features = false features = [ "composite" ] @@ -43,6 +43,6 @@ udev = [ "smithay/backend_libinput", "smithay/backend_udev", "smithay/backend_dr logind = [ "smithay/backend_session_logind" ] elogind = ["logind", "smithay/backend_session_elogind" ] libseat = ["smithay/backend_session_libseat" ] -xwayland = [ "smithay/xwayland", "x11rb" ] +xwayland = [ "smithay/xwayland", "x11rb", "smithay/x11rb_event_source" ] debug = [ "fps_ticker", "image/png" ] test_all_features = ["default", "debug"] diff --git a/anvil/src/xwayland/mod.rs b/anvil/src/xwayland/mod.rs index f876dba..2203bcd 100644 --- a/anvil/src/xwayland/mod.rs +++ b/anvil/src/xwayland/mod.rs @@ -4,7 +4,7 @@ use std::{ use smithay::{ reexports::wayland_server::{protocol::wl_surface::WlSurface, Client}, - utils::{Logical, Point}, + utils::{x11rb::X11Source, Logical, Point}, wayland::compositor::give_role, }; @@ -27,10 +27,6 @@ use crate::{ AnvilState, }; -use x11rb_event_source::X11Source; - -mod x11rb_event_source; - impl AnvilState { pub fn start_xwayland(&mut self) { if let Err(e) = self.xwayland.start() { @@ -237,7 +233,7 @@ pub fn commit_hook(surface: &WlSurface) { } } -#[derive(Clone)] +#[derive(Debug, Clone)] pub struct X11Surface { surface: WlSurface, } diff --git a/src/reexports.rs b/src/reexports.rs index b5bdd1c..7aa6a63 100644 --- a/src/reexports.rs +++ b/src/reexports.rs @@ -21,3 +21,5 @@ pub use wayland_protocols; pub use wayland_server; #[cfg(feature = "backend_winit")] pub use winit; +#[cfg(feature = "x11rb_event_source")] +pub use x11rb; diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 1d09421..48ce1fd 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -3,6 +3,9 @@ mod geometry; pub mod signaling; +#[cfg(feature = "x11rb_event_source")] +pub mod x11rb; + pub use self::geometry::{Buffer, Logical, Physical, Point, Raw, Rectangle, Size}; /// This resource is not managed by Smithay diff --git a/anvil/src/xwayland/x11rb_event_source.rs b/src/utils/x11rb.rs similarity index 84% rename from anvil/src/xwayland/x11rb_event_source.rs rename to src/utils/x11rb.rs index 694b434..6eebea7 100644 --- a/anvil/src/xwayland/x11rb_event_source.rs +++ b/src/utils/x11rb.rs @@ -1,3 +1,8 @@ +//! Helper utilities for using x11rb as an event source in calloop. +//! +//! The primary use for this module is XWayland integration but is also widely useful for an X11 +//! backend in a compositor. + use std::{ io::Result as IOResult, sync::Arc, @@ -13,7 +18,7 @@ use x11rb::{ rust_connection::RustConnection, }; -use smithay::reexports::calloop::{ +use calloop::{ channel::{sync_channel, Channel, Event as ChannelEvent, SyncSender}, EventSource, Poll, PostAction, Readiness, Token, TokenFactory, }; @@ -28,9 +33,10 @@ use smithay::reexports::calloop::{ /// iteration. Calloop only allows "when an FD becomes readable". /// /// [1]: https://docs.rs/x11rb/0.8.1/x11rb/event_loop_integration/index.html#threads-and-races +#[derive(Debug)] pub struct X11Source { connection: Arc, - channel: Channel, + channel: Option>, event_thread: Option>, close_window: Window, close_type: Atom, @@ -56,9 +62,10 @@ impl X11Source { let event_thread = Some(spawn(move || { run_event_thread(conn, sender, log2); })); + Self { connection, - channel, + channel: Some(channel), event_thread, close_window, close_type, @@ -70,9 +77,7 @@ impl X11Source { impl Drop for X11Source { fn drop(&mut self) { // Signal the worker thread to exit by dropping the read end of the channel. - // There is no easy and nice way to do this, so do it the ugly way: Replace it. - let (_, channel) = sync_channel(1); - self.channel = channel; + self.channel.take(); // Send an event to wake up the worker so that it actually exits let event = ClientMessageEvent { @@ -83,6 +88,7 @@ impl Drop for X11Source { type_: self.close_type, data: [0; 20].into(), }; + let _ = self .connection .send_event(false, self.close_window, EventMask::NO_EVENT, event); @@ -108,23 +114,39 @@ impl EventSource for X11Source { C: FnMut(Self::Event, &mut Self::Metadata) -> Self::Ret, { let log = self.log.clone(); - self.channel - .process_events(readiness, token, move |event, meta| match event { + + if let Some(channel) = &mut self.channel { + channel.process_events(readiness, token, move |event, meta| match event { ChannelEvent::Closed => slog::warn!(log, "Event thread exited"), ChannelEvent::Msg(event) => callback(event, meta), }) + } else { + Ok(PostAction::Remove) + } } fn register(&mut self, poll: &mut Poll, factory: &mut TokenFactory) -> IOResult<()> { - self.channel.register(poll, factory) + if let Some(channel) = &mut self.channel { + channel.register(poll, factory)?; + } + + Ok(()) } fn reregister(&mut self, poll: &mut Poll, factory: &mut TokenFactory) -> IOResult<()> { - self.channel.reregister(poll, factory) + if let Some(channel) = &mut self.channel { + channel.reregister(poll, factory)?; + } + + Ok(()) } fn unregister(&mut self, poll: &mut Poll) -> IOResult<()> { - self.channel.unregister(poll) + if let Some(channel) = &mut self.channel { + channel.unregister(poll)?; + } + + Ok(()) } }