diff --git a/Cargo.toml b/Cargo.toml index 377edc8..7965426 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,10 +11,10 @@ edition = "2018" members = [ "anvil" ] [dependencies] -wayland-server = { version = "0.23.4", optional = true } -wayland-commons = { version = "0.23.4", optional = true } -wayland-sys = { version = "0.23.4", optional = true } -calloop = "0.4.2" +wayland-server = { version = "0.25.0", optional = true } +wayland-commons = { version = "0.25.0", optional = true } +wayland-sys = { version = "0.25.0", optional = true } +calloop = "0.5.1" bitflags = "1" nix = "0.13" xkbcommon = "0.4.0" @@ -31,7 +31,7 @@ input = { version = "0.4.1", optional = true } udev = { version = "0.2.0", optional = true } dbus = { version = "0.8", optional = true } systemd = { version = "0.4.0", optional = true } -wayland-protocols = { version = "0.23.4", features = ["unstable_protocols", "server"], optional = true } +wayland-protocols = { version = "0.25.0", features = ["unstable_protocols", "server"], optional = true } image = { version = "0.21.0", optional = true } error-chain = "0.12.0" lazy_static = "1.0.0" @@ -44,7 +44,7 @@ gl_generator = { version = "0.10", optional = true } [features] default = ["backend_winit", "backend_drm_legacy", "backend_drm_gbm", "backend_drm_egl", "backend_libinput", "backend_udev", "backend_session", "renderer_glium", "xwayland", "wayland_frontend"] -backend_winit = ["winit", "wayland-server/dlopen", "wayland-client/dlopen", "backend_egl", "renderer_gl", "native_lib"] +backend_winit = ["winit", "wayland-server/dlopen", "wayland-client/dlopen", "backend_egl", "renderer_gl", "use_system_lib"] backend_drm = ["drm"] backend_drm_legacy = ["backend_drm"] backend_drm_gbm = ["backend_drm", "gbm", "image"] @@ -56,7 +56,7 @@ backend_udev = ["udev"] backend_session_logind = ["dbus", "systemd", "backend_session"] renderer_gl = ["gl_generator"] renderer_glium = ["renderer_gl", "glium"] -native_lib = ["wayland_frontend", "wayland-sys", "wayland-server/native_lib"] +use_system_lib = ["wayland_frontend", "wayland-sys", "wayland-server/use_system_lib"] wayland_frontend = ["wayland-server", "wayland-commons", "wayland-protocols"] xwayland = ["wayland_frontend"] diff --git a/anvil/Cargo.toml b/anvil/Cargo.toml index 21cf6f9..84864fa 100644 --- a/anvil/Cargo.toml +++ b/anvil/Cargo.toml @@ -12,7 +12,7 @@ slog-term = "2.3" slog-async = "2.2" rand = "0.6" glium = { version = "0.23.0", default-features = false } -wayland-server = "0.23" +wayland-server = "0.25.0" xkbcommon = "0.4.0" bitflags = "1.2.1" @@ -26,7 +26,7 @@ gl_generator = "0.10" [features] default = [ "winit", "egl", "udev" ] -egl = [ "smithay/native_lib" ] +egl = [ "smithay/use_system_lib" ] winit = [ "smithay/backend_winit" ] udev = [ "smithay/backend_libinput", "smithay/backend_drm_legacy", "smithay/backend_drm_gbm", "smithay/backend_drm_egl", "smithay/backend_udev", "smithay/backend_session" ] logind = [ "smithay/backend_session_logind" ] diff --git a/anvil/src/glium_drawer.rs b/anvil/src/glium_drawer.rs index 3292edc..e924810 100644 --- a/anvil/src/glium_drawer.rs +++ b/anvil/src/glium_drawer.rs @@ -299,7 +299,8 @@ impl GliumDrawer { location, |_surface, attributes, role, &(mut x, mut y)| { // Pull a new buffer if available - if let Some(data) = attributes.user_data.get_mut::() { + if let Some(data) = attributes.user_data.get::>() { + let mut data = data.borrow_mut(); if data.texture.is_none() { if let Some(buffer) = data.buffer.take() { if let Ok(m) = self.texture_from_buffer(buffer.clone()) { @@ -341,8 +342,8 @@ impl GliumDrawer { } }, |_surface, attributes, role, &(mut x, mut y)| { - if let Some(ref data) = attributes.user_data.get::() { - if let Some(ref metadata) = data.texture { + if let Some(ref data) = attributes.user_data.get::>() { + if let Some(ref metadata) = data.borrow().texture { // we need to re-extract the subsurface offset, as the previous closure // only passes it to our children if let Ok(subdata) = Role::::data(role) { diff --git a/anvil/src/main.rs b/anvil/src/main.rs index f593091..fb66ada 100644 --- a/anvil/src/main.rs +++ b/anvil/src/main.rs @@ -8,7 +8,7 @@ extern crate slog; extern crate smithay; use slog::Drain; -use smithay::reexports::{calloop::EventLoop, wayland_server::Display}; +use smithay::reexports::{calloop::{EventLoop, generic::Generic, mio::Interest}, wayland_server::Display}; #[macro_use] mod shaders; @@ -30,6 +30,20 @@ static POSSIBLE_BACKENDS: &[&str] = &[ "--tty-udev : Run anvil as a tty udev client (requires root if without logind).", ]; +pub struct AnvilState { + pub need_wayland_dispatch: bool, + pub running: bool, +} + +impl Default for AnvilState { + fn default() -> AnvilState { + AnvilState { + need_wayland_dispatch: false, + running: true, + } + } +} + fn main() { // A logger facility, here we use the terminal here let log = slog::Logger::root( @@ -37,8 +51,16 @@ fn main() { o!(), ); - let mut event_loop = EventLoop::<()>::new().unwrap(); - let mut display = Display::new(event_loop.handle()); + let mut event_loop = EventLoop::::new().unwrap(); + let mut display = Display::new(); + + // Glue for event dispatching + let mut wayland_event_source = Generic::from_raw_fd(display.get_poll_fd()); + wayland_event_source.set_interest(Interest::READABLE); + let _wayland_source = event_loop.handle().insert_source( + wayland_event_source, + |_, state: &mut AnvilState| { state.need_wayland_dispatch = true; } + ); let arg = ::std::env::args().nth(1); match arg.as_ref().map(|s| &s[..]) { diff --git a/anvil/src/shell.rs b/anvil/src/shell.rs index 3935f0b..874bdbd 100644 --- a/anvil/src/shell.rs +++ b/anvil/src/shell.rs @@ -187,7 +187,7 @@ impl PointerGrab for ResizeSurfaceGrab { let (min_size, max_size) = self.ctoken .with_surface_data(self.toplevel.get_surface().unwrap(), |attrs| { - let data = attrs.user_data.get::().unwrap(); + let data = attrs.user_data.get::>().unwrap().borrow(); (data.min_size, data.max_size) }); @@ -245,7 +245,7 @@ impl PointerGrab for ResizeSurfaceGrab { self.ctoken .with_surface_data(self.toplevel.get_surface().unwrap(), |attrs| { - let data = attrs.user_data.get_mut::().unwrap(); + let mut data = attrs.user_data.get::>().unwrap().borrow_mut(); if let ResizeState::Resizing(resize_data) = data.resize_state { data.resize_state = ResizeState::WaitingForFinalAck(resize_data, serial); } else { @@ -255,7 +255,7 @@ impl PointerGrab for ResizeSurfaceGrab { } else { self.ctoken .with_surface_data(self.toplevel.get_surface().unwrap(), |attrs| { - let data = attrs.user_data.get_mut::().unwrap(); + let mut data = attrs.user_data.get::>().unwrap().borrow_mut(); if let ResizeState::Resizing(resize_data) = data.resize_state { data.resize_state = ResizeState::WaitingForCommit(resize_data); } else { @@ -298,9 +298,10 @@ pub fn init_shell( let window_map = window_map.as_ref().unwrap(); surface_commit(&surface, ctoken, &buffer_utils, &*window_map) } - SurfaceEvent::Frame { callback } => callback - .implement_closure(|_, _| unreachable!(), None::, ()) - .done(0), + SurfaceEvent::Frame { callback } => { + callback.quick_assign(|_, _, _| unreachable!()); + callback.done(0) + } }, log.clone(), ); @@ -413,7 +414,7 @@ pub fn init_shell( let initial_window_size = (geometry.width, geometry.height); compositor_token.with_surface_data(surface.get_surface().unwrap(), move |attrs| { - attrs.user_data.get_mut::().unwrap().resize_state = + attrs.user_data.get::>().unwrap().borrow_mut().resize_state = ResizeState::Resizing(ResizeData { edges: edges.into(), initial_window_location, @@ -434,8 +435,8 @@ pub fn init_shell( } XdgRequest::AckConfigure { surface, .. } => { let waiting_for_serial = compositor_token.with_surface_data(&surface, |attrs| { - if let Some(data) = attrs.user_data.get_mut::() { - if let ResizeState::WaitingForFinalAck(_, serial) = data.resize_state { + if let Some(data) = attrs.user_data.get::>() { + if let ResizeState::WaitingForFinalAck(_, serial) = data.borrow().resize_state { return Some(serial); } } @@ -452,7 +453,7 @@ pub fn init_shell( if acked { compositor_token.with_surface_data(&surface, |attrs| { - let data = attrs.user_data.get_mut::().unwrap(); + let mut data = attrs.user_data.get::>().unwrap().borrow_mut(); if let ResizeState::WaitingForFinalAck(resize_data, _) = data.resize_state { data.resize_state = ResizeState::WaitingForCommit(resize_data); } else { @@ -565,7 +566,7 @@ pub fn init_shell( let initial_window_size = (geometry.width, geometry.height); compositor_token.with_surface_data(surface.get_surface().unwrap(), move |attrs| { - attrs.user_data.get_mut::().unwrap().resize_state = + attrs.user_data.get::>().unwrap().borrow_mut().resize_state = ResizeState::Resizing(ResizeData { edges: edges.into(), initial_window_location, @@ -697,8 +698,8 @@ fn surface_commit( }); let refresh = token.with_surface_data(surface, |attributes| { - attributes.user_data.insert_if_missing(SurfaceData::default); - let data = attributes.user_data.get_mut::().unwrap(); + attributes.user_data.insert_if_missing(|| RefCell::new(SurfaceData::default())); + let mut data = attributes.user_data.get::>().unwrap().borrow_mut(); data.geometry = geometry; data.input_region = attributes.input_region.clone(); @@ -738,7 +739,7 @@ fn surface_commit( let Rectangle { width, height, .. } = window_map.geometry(&toplevel).unwrap(); let new_location = token.with_surface_data(surface, |attributes| { - let data = attributes.user_data.get_mut::().unwrap(); + let mut data = attributes.user_data.get::>().unwrap().borrow_mut(); let mut new_location = None; diff --git a/anvil/src/udev.rs b/anvil/src/udev.rs index c3b3710..1ddfc24 100644 --- a/anvil/src/udev.rs +++ b/anvil/src/udev.rs @@ -35,6 +35,10 @@ use smithay::{ udev::{primary_gpu, udev_backend_bind, UdevBackend, UdevHandler}, }, reexports::{ + calloop::{ + generic::{SourceFd, Generic}, + EventLoop, LoopHandle, Source, + }, drm::control::{ connector::{Info as ConnectorInfo, State as ConnectorState}, crtc, @@ -44,10 +48,6 @@ use smithay::{ input::Libinput, nix::{fcntl::OFlag, sys::stat::dev_t}, wayland_server::{ - calloop::{ - generic::{EventedFd, Generic}, - EventLoop, LoopHandle, Source, - }, protocol::{wl_output, wl_surface}, Display, }, @@ -65,6 +65,7 @@ use crate::buffer_utils::BufferUtils; use crate::glium_drawer::GliumDrawer; use crate::input_handler::AnvilInputHandler; use crate::shell::{init_shell, MyWindowMap, Roles}; +use crate::AnvilState; pub struct SessionFd(RawFd); impl AsRawFd for SessionFd { @@ -78,7 +79,7 @@ type RenderDevice = type RenderSurface = EglSurface>, GbmDevice>>; -pub fn run_udev(mut display: Display, mut event_loop: EventLoop<()>, log: Logger) -> Result<(), ()> { +pub fn run_udev(mut display: Display, mut event_loop: EventLoop, log: Logger) -> Result<(), ()> { let name = display.add_socket_auto().unwrap().into_string().unwrap(); info!(log, "Listening on wayland socket"; "name" => name.clone()); ::std::env::set_var("WAYLAND_DISPLAY", name); @@ -253,14 +254,19 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop<()>, log: Logger /* * And run our loop */ + let mut state = AnvilState::default(); + while running.load(Ordering::SeqCst) { if event_loop - .dispatch(Some(::std::time::Duration::from_millis(16)), &mut ()) + .dispatch(Some(::std::time::Duration::from_millis(16)), &mut state) .is_err() { running.store(false, Ordering::SeqCst); } else { - display.borrow_mut().flush_clients(); + if state.need_wayland_dispatch { + display.borrow_mut().dispatch(std::time::Duration::from_millis(0), &mut state); + } + display.borrow_mut().flush_clients(&mut state); window_map.borrow_mut().refresh(); } } @@ -287,7 +293,7 @@ struct UdevHandlerImpl { dev_t, ( S::Id, - Source>>, + Source>>, Rc>>>, ), >, diff --git a/anvil/src/window_map.rs b/anvil/src/window_map.rs index c014626..6fb104e 100644 --- a/anvil/src/window_map.rs +++ b/anvil/src/window_map.rs @@ -87,7 +87,7 @@ where wl_surface, self.location, |wl_surface, attributes, role, &(mut x, mut y)| { - let data = attributes.user_data.get::(); + let data = attributes.user_data.get::>(); if let Ok(subdata) = Role::::data(role) { x += subdata.location.0; @@ -96,7 +96,7 @@ where let surface_local_point = (point.0 - x as f64, point.1 - y as f64); if data - .map(|data| data.contains_point(surface_local_point)) + .map(|data| data.borrow().contains_point(surface_local_point)) .unwrap_or(false) { *found.borrow_mut() = Some((wl_surface.clone(), (x as f64, y as f64))); @@ -122,9 +122,9 @@ where wl_surface, (base_x, base_y), |_, attributes, role, &(mut x, mut y)| { - let data = attributes.user_data.get::(); + let data = attributes.user_data.get::>(); - if let Some((w, h)) = data.and_then(SurfaceData::size) { + if let Some((w, h)) = data.and_then(|d| d.borrow().size()) { if let Ok(subdata) = Role::::data(role) { x += subdata.location.0; y += subdata.location.1; @@ -160,7 +160,7 @@ where // It's the set geometry with the full bounding box as the fallback. ctoken .with_surface_data(self.toplevel.get_surface().unwrap(), |attributes| { - attributes.user_data.get::().unwrap().geometry + attributes.user_data.get::>().unwrap().borrow().geometry }) .unwrap_or(self.bbox) } diff --git a/anvil/src/winit.rs b/anvil/src/winit.rs index 841936d..86b71fc 100644 --- a/anvil/src/winit.rs +++ b/anvil/src/winit.rs @@ -27,8 +27,9 @@ use crate::buffer_utils::BufferUtils; use crate::glium_drawer::GliumDrawer; use crate::input_handler::AnvilInputHandler; use crate::shell::init_shell; +use crate::AnvilState; -pub fn run_winit(display: &mut Display, event_loop: &mut EventLoop<()>, log: Logger) -> Result<(), ()> { +pub fn run_winit(display: &mut Display, event_loop: &mut EventLoop, log: Logger) -> Result<(), ()> { let (renderer, mut input) = winit::init(log.clone()).map_err(|_| ())?; #[cfg(feature = "egl")] @@ -187,13 +188,18 @@ pub fn run_winit(display: &mut Display, event_loop: &mut EventLoop<()>, log: Log } } + let mut state = AnvilState::default(); + if event_loop - .dispatch(Some(::std::time::Duration::from_millis(16)), &mut ()) + .dispatch(Some(::std::time::Duration::from_millis(16)), &mut state) .is_err() { running.store(false, Ordering::SeqCst); } else { - display.flush_clients(); + if state.need_wayland_dispatch { + display.dispatch(std::time::Duration::from_millis(0), &mut state); + } + display.flush_clients(&mut state); window_map.borrow_mut().refresh(); } } diff --git a/src/backend/drm/egl/mod.rs b/src/backend/drm/egl/mod.rs index 542ed18..52bb5dd 100644 --- a/src/backend/drm/egl/mod.rs +++ b/src/backend/drm/egl/mod.rs @@ -12,7 +12,7 @@ use drm::control::{crtc, ResourceHandles, ResourceInfo}; use nix::libc::dev_t; use std::os::unix::io::{AsRawFd, RawFd}; use std::rc::Rc; -#[cfg(feature = "native_lib")] +#[cfg(feature = "use_system_lib")] use wayland_server::Display; use super::{Device, DeviceHandler, Surface}; @@ -20,7 +20,7 @@ use crate::backend::egl::context::GlAttributes; use crate::backend::egl::error::Result as EGLResult; use crate::backend::egl::native::{Backend, NativeDisplay, NativeSurface}; use crate::backend::egl::EGLContext; -#[cfg(feature = "native_lib")] +#[cfg(feature = "use_system_lib")] use crate::backend::egl::{EGLDisplay, EGLGraphicsBackend}; pub mod error; @@ -181,7 +181,7 @@ where } } -#[cfg(feature = "native_lib")] +#[cfg(feature = "use_system_lib")] impl EGLGraphicsBackend for EglDevice where B: Backend::Surface> + 'static, diff --git a/src/backend/drm/mod.rs b/src/backend/drm/mod.rs index 76652af..0e0d334 100644 --- a/src/backend/drm/mod.rs +++ b/src/backend/drm/mod.rs @@ -46,8 +46,8 @@ use std::iter::IntoIterator; use std::os::unix::io::AsRawFd; use std::path::PathBuf; -use calloop::generic::{EventedFd, Generic}; -use calloop::mio::Ready; +use calloop::generic::{SourceFd, Generic}; +use calloop::mio::Interest; use calloop::InsertError; use calloop::{LoopHandle, Source}; @@ -229,13 +229,13 @@ impl DevPath for A { pub fn device_bind( handle: &LoopHandle, device: D, -) -> ::std::result::Result>>, InsertError>>> +) -> ::std::result::Result>>, InsertError>>> where D: Device, Data: 'static, { let mut source = Generic::from_fd_source(device); - source.set_interest(Ready::readable()); + source.set_interest(Interest::READABLE); handle.insert_source(source, |evt, _| { evt.source.borrow_mut().0.process_events(); diff --git a/src/backend/egl/mod.rs b/src/backend/egl/mod.rs index 6ecdde3..d466804 100644 --- a/src/backend/egl/mod.rs +++ b/src/backend/egl/mod.rs @@ -28,7 +28,7 @@ use std::{ }; #[cfg(feature = "wayland_frontend")] use wayland_server::{protocol::wl_buffer::WlBuffer, Display}; -#[cfg(feature = "native_lib")] +#[cfg(feature = "use_system_lib")] use wayland_sys::server::wl_display; pub mod context; @@ -306,7 +306,7 @@ impl Drop for EGLImages { /// Trait any backend type may implement that allows binding a [`Display`](wayland_server::Display) /// to create an [`EGLDisplay`] for EGL-based [`WlBuffer`]s. -#[cfg(feature = "native_lib")] +#[cfg(feature = "use_system_lib")] pub trait EGLGraphicsBackend { /// Binds this EGL context to the given Wayland display. /// @@ -326,7 +326,7 @@ pub trait EGLGraphicsBackend { /// Type to receive [`EGLImages`] for EGL-based [`WlBuffer`]s. /// /// Can be created by using [`EGLGraphicsBackend::bind_wl_display`]. -#[cfg(feature = "native_lib")] +#[cfg(feature = "use_system_lib")] pub struct EGLDisplay { egl: Weak, wayland: *mut wl_display, @@ -336,7 +336,7 @@ pub struct EGLDisplay { egl_to_texture_support: bool, } -#[cfg(feature = "native_lib")] +#[cfg(feature = "use_system_lib")] impl EGLDisplay { fn new>( context: &EGLContext, @@ -510,7 +510,7 @@ impl EGLDisplay { } } -#[cfg(feature = "native_lib")] +#[cfg(feature = "use_system_lib")] impl Drop for EGLDisplay { fn drop(&mut self) { if let Some(display) = self.egl.upgrade() { @@ -523,14 +523,14 @@ impl Drop for EGLDisplay { } } -#[cfg(feature = "native_lib")] +#[cfg(feature = "use_system_lib")] impl EGLGraphicsBackend for Rc { fn bind_wl_display(&self, display: &Display) -> Result { (**self).bind_wl_display(display) } } -#[cfg(feature = "native_lib")] +#[cfg(feature = "use_system_lib")] impl> EGLGraphicsBackend for EGLContext { fn bind_wl_display(&self, display: &Display) -> Result { if !self.wl_drm_support { diff --git a/src/backend/libinput.rs b/src/backend/libinput.rs index a227631..5f198c3 100644 --- a/src/backend/libinput.rs +++ b/src/backend/libinput.rs @@ -16,8 +16,8 @@ use std::{ }; use calloop::{ - generic::{EventedFd, Generic}, - mio::Ready, + generic::{SourceFd, Generic}, + mio::Interest, InsertError, LoopHandle, Source, }; @@ -608,11 +608,11 @@ pub fn libinput_bind( backend: LibinputInputBackend, handle: LoopHandle, ) -> ::std::result::Result< - Source>>, - InsertError>>, + Source>>, + InsertError>>, > { let mut source = Generic::from_fd_source(backend); - source.set_interest(Ready::readable()); + source.set_interest(Interest::READABLE); handle.insert_source(source, move |evt, _| { let mut backend = evt.source.borrow_mut(); diff --git a/src/backend/session/dbus/logind.rs b/src/backend/session/dbus/logind.rs index b2351a6..1348ab6 100644 --- a/src/backend/session/dbus/logind.rs +++ b/src/backend/session/dbus/logind.rs @@ -53,8 +53,8 @@ use std::{ use systemd::login; use calloop::{ - generic::{Event, EventedRawFd, Generic}, - mio::Ready, + generic::{Event, SourceRawFd, Generic}, + mio::Interest, InsertError, LoopHandle, Source, }; @@ -431,7 +431,7 @@ impl SessionNotifier for LogindSessionNotifier { pub struct BoundLogindSession { notifier: LogindSessionNotifier, _watches: Vec, - sources: Vec>>, + sources: Vec>>, } /// Bind a [`LogindSessionNotifier`] to an [`EventLoop`](calloop::EventLoop). @@ -449,17 +449,21 @@ pub fn logind_session_bind( let sources = watches .clone() .into_iter() - .map(|watch| { + .filter_map(|watch| { + let interest = match (watch.writable(), watch.readable()) { + (true, true) => Interest::WRITABLE | Interest::READABLE, + (true, false) => Interest::WRITABLE, + (false, true) => Interest::READABLE, + (false, false) => return None + }; let mut source = Generic::from_raw_fd(watch.fd()); - source.set_interest( - if watch.readable() { Ready::readable() } else { Ready::empty() } - | if watch.writable() { Ready::writable() } else { Ready::empty() } - ); - handle.insert_source(source, { + source.set_interest(interest); + let source = handle.insert_source(source, { let mut notifier = notifier.clone(); move |evt, _| notifier.event(evt) - }) - }).collect::<::std::result::Result>>, InsertError>>>() + }); + Some(source) + }).collect::<::std::result::Result>>, InsertError>>>() .map_err(|err| { ( err.into(), @@ -502,17 +506,17 @@ impl Drop for LogindSessionNotifier { } impl LogindSessionNotifier { - fn event(&mut self, event: Event) { + fn event(&mut self, event: Event) { let fd = event.source.borrow().0; let readiness = event.readiness; let conn = self.internal.conn.borrow(); let items = conn.watch_handle( fd, - if readiness.is_readable() && readiness.is_writable() { + if readiness.readable && readiness.writable { WatchEvent::Readable as u32 | WatchEvent::Writable as u32 - } else if readiness.is_readable() { + } else if readiness.readable { WatchEvent::Readable as u32 - } else if readiness.is_writable() { + } else if readiness.writable { WatchEvent::Writable as u32 } else { return; diff --git a/src/backend/udev.rs b/src/backend/udev.rs index 6512044..5478499 100644 --- a/src/backend/udev.rs +++ b/src/backend/udev.rs @@ -19,8 +19,8 @@ use std::{ use udev::{Context, Enumerator, EventType, MonitorBuilder, MonitorSocket, Result as UdevResult}; use calloop::{ - generic::{EventedFd, Generic}, - mio::Ready, + generic::{SourceFd, Generic}, + mio::Interest, InsertError, LoopHandle, Source, }; @@ -104,9 +104,9 @@ impl Drop for UdevBackend { pub fn udev_backend_bind( udev: UdevBackend, handle: &LoopHandle, -) -> Result>>>, InsertError>>>> { +) -> Result>>>, InsertError>>>> { let mut source = Generic::from_fd_source(udev); - source.set_interest(Ready::readable()); + source.set_interest(Interest::READABLE); handle.insert_source(source, |evt, _| { evt.source.borrow_mut().0.process_events(); diff --git a/src/wayland/compositor/handlers.rs b/src/wayland/compositor/handlers.rs index 2a1acfa..fdaff9e 100644 --- a/src/wayland/compositor/handlers.rs +++ b/src/wayland/compositor/handlers.rs @@ -1,8 +1,8 @@ -use std::{cell::RefCell, rc::Rc, sync::Mutex}; +use std::{cell::RefCell, ops::Deref as _, rc::Rc, sync::Mutex}; use wayland_server::{ protocol::{wl_compositor, wl_region, wl_subcompositor, wl_subsurface, wl_surface}, - NewResource, + Filter, Main, }; use super::{ @@ -16,29 +16,26 @@ use super::{ */ pub(crate) fn implement_compositor( - compositor: NewResource, + compositor: Main, log: ::slog::Logger, implem: Rc>, ) -> wl_compositor::WlCompositor where - R: Default + 'static, + R: Default + Send + 'static, Impl: FnMut(SurfaceEvent, wl_surface::WlSurface, CompositorToken) + 'static, { - compositor.implement_closure( - move |request, _compositor| match request { - wl_compositor::Request::CreateSurface { id } => { - trace!(log, "Creating a new wl_surface."); - implement_surface(id, log.clone(), implem.clone()); - } - wl_compositor::Request::CreateRegion { id } => { - trace!(log, "Creating a new wl_region."); - implement_region(id); - } - _ => unreachable!(), - }, - None::, - (), - ) + compositor.quick_assign(move |_compositor, request, _| match request { + wl_compositor::Request::CreateSurface { id } => { + trace!(log, "Creating a new wl_surface."); + implement_surface(id, log.clone(), implem.clone()); + } + wl_compositor::Request::CreateRegion { id } => { + trace!(log, "Creating a new wl_region."); + implement_region(id); + } + _ => unreachable!(), + }); + compositor.deref().clone() } /* @@ -81,14 +78,14 @@ where } wl_surface::Request::SetOpaqueRegion { region } => { let attributes = region.map(|r| { - let attributes_mutex = r.as_ref().user_data::>().unwrap(); + let attributes_mutex = r.as_ref().user_data().get::>().unwrap(); attributes_mutex.lock().unwrap().clone() }); SurfaceData::::with_data(&surface, |d| d.opaque_region = attributes); } wl_surface::Request::SetInputRegion { region } => { let attributes = region.map(|r| { - let attributes_mutex = r.as_ref().user_data::>().unwrap(); + let attributes_mutex = r.as_ref().user_data().get::>().unwrap(); attributes_mutex.lock().unwrap().clone() }); SurfaceData::::with_data(&surface, |d| d.input_region = attributes); @@ -118,24 +115,25 @@ where } fn implement_surface( - surface: NewResource, + surface: Main, log: ::slog::Logger, implem: Rc>, ) -> wl_surface::WlSurface where - R: Default + 'static, + R: Default + Send + 'static, Impl: FnMut(SurfaceEvent, wl_surface::WlSurface, CompositorToken) + 'static, { - let surface = surface.implement_closure( - { - let mut implem = SurfaceImplem::make(log, implem); - move |req, surface| implem.receive_surface_request(req, surface) - }, - Some(|surface| SurfaceData::::cleanup(&surface)), - SurfaceData::::new(), - ); - SurfaceData::::init(&surface); + surface.quick_assign({ + let mut implem = SurfaceImplem::make(log, implem); + move |surface, req, _| implem.receive_surface_request(req, surface.deref().clone()) + }); + surface.assign_destructor(Filter::new(|surface, _, _| SurfaceData::::cleanup(&surface))); surface + .as_ref() + .user_data() + .set_threadsafe(|| SurfaceData::::new()); + SurfaceData::::init(&surface); + surface.deref().clone() } /* @@ -143,7 +141,11 @@ where */ fn region_implem(request: wl_region::Request, region: wl_region::WlRegion) { - let attributes_mutex = region.as_ref().user_data::>().unwrap(); + let attributes_mutex = region + .as_ref() + .user_data() + .get::>() + .unwrap(); let mut guard = attributes_mutex.lock().unwrap(); match request { wl_region::Request::Add { x, y, width, height } => guard @@ -159,12 +161,13 @@ fn region_implem(request: wl_region::Request, region: wl_region::WlRegion) { } } -fn implement_region(region: NewResource) -> wl_region::WlRegion { - region.implement_closure( - region_implem, - None::, - Mutex::new(RegionAttributes::default()), - ) +fn implement_region(region: Main) -> wl_region::WlRegion { + region.quick_assign(|region, req, _| region_implem(req, region.deref().clone())); + region + .as_ref() + .user_data() + .set_threadsafe(|| Mutex::new(RegionAttributes::default())); + region.deref().clone() } /* @@ -172,29 +175,26 @@ fn implement_region(region: NewResource) -> wl_region::WlRe */ pub(crate) fn implement_subcompositor( - subcompositor: NewResource, + subcompositor: Main, ) -> wl_subcompositor::WlSubcompositor where R: RoleType + Role + 'static, { - subcompositor.implement_closure( - move |request, subcompositor| match request { - wl_subcompositor::Request::GetSubsurface { id, surface, parent } => { - if let Err(()) = SurfaceData::::set_parent(&surface, &parent) { - subcompositor.as_ref().post_error( - wl_subcompositor::Error::BadSurface as u32, - "Surface already has a role.".into(), - ); - return; - } - implement_subsurface::(id, surface); + subcompositor.quick_assign(move |subcompositor, request, _| match request { + wl_subcompositor::Request::GetSubsurface { id, surface, parent } => { + if let Err(()) = SurfaceData::::set_parent(&surface, &parent) { + subcompositor.as_ref().post_error( + wl_subcompositor::Error::BadSurface as u32, + "Surface already has a role.".into(), + ); + return; } - wl_subcompositor::Request::Destroy => {} - _ => unreachable!(), - }, - None::, - (), - ) + implement_subsurface::(id, surface); + } + wl_subcompositor::Request::Destroy => {} + _ => unreachable!(), + }); + subcompositor.deref().clone() } /* @@ -206,68 +206,83 @@ where F: FnOnce(&mut SubsurfaceRole), R: RoleType + Role + 'static, { - let surface = subsurface.as_ref().user_data::().unwrap(); + let surface = subsurface + .as_ref() + .user_data() + .get::() + .unwrap(); SurfaceData::::with_role_data::(surface, |d| f(d)) .expect("The surface does not have a subsurface role while it has a wl_subsurface?!"); } fn implement_subsurface( - subsurface: NewResource, + subsurface: Main, surface: wl_surface::WlSurface, ) -> wl_subsurface::WlSubsurface where R: RoleType + Role + 'static, { - subsurface.implement_closure( - |request, subsurface| { - match request { - wl_subsurface::Request::SetPosition { x, y } => { - with_subsurface_attributes::(&subsurface, |attrs| { - attrs.location = (x, y); - }) - } - wl_subsurface::Request::PlaceAbove { sibling } => { - let surface = subsurface.as_ref().user_data::().unwrap(); - if let Err(()) = SurfaceData::::reorder(surface, Location::After, &sibling) { - subsurface.as_ref().post_error( - wl_subsurface::Error::BadSurface as u32, - "Provided surface is not a sibling or parent.".into(), - ) - } - } - wl_subsurface::Request::PlaceBelow { sibling } => { - let surface = subsurface.as_ref().user_data::().unwrap(); - if let Err(()) = SurfaceData::::reorder(surface, Location::Before, &sibling) { - subsurface.as_ref().post_error( - wl_subsurface::Error::BadSurface as u32, - "Provided surface is not a sibling or parent.".into(), - ) - } - } - wl_subsurface::Request::SetSync => with_subsurface_attributes::(&subsurface, |attrs| { - attrs.sync = true; - }), - wl_subsurface::Request::SetDesync => { - with_subsurface_attributes::(&subsurface, |attrs| { - attrs.sync = false; - }) - } - wl_subsurface::Request::Destroy => { - // Our destructor already handles it - } - _ => unreachable!(), + subsurface.quick_assign(|subsurface, request, _| { + match request { + wl_subsurface::Request::SetPosition { x, y } => { + with_subsurface_attributes::(&subsurface, |attrs| { + attrs.location = (x, y); + }) } - }, - Some(|subsurface| destroy_subsurface::(&subsurface)), - surface, - ) + wl_subsurface::Request::PlaceAbove { sibling } => { + let surface = subsurface + .as_ref() + .user_data() + .get::() + .unwrap(); + if let Err(()) = SurfaceData::::reorder(surface, Location::After, &sibling) { + subsurface.as_ref().post_error( + wl_subsurface::Error::BadSurface as u32, + "Provided surface is not a sibling or parent.".into(), + ) + } + } + wl_subsurface::Request::PlaceBelow { sibling } => { + let surface = subsurface + .as_ref() + .user_data() + .get::() + .unwrap(); + if let Err(()) = SurfaceData::::reorder(surface, Location::Before, &sibling) { + subsurface.as_ref().post_error( + wl_subsurface::Error::BadSurface as u32, + "Provided surface is not a sibling or parent.".into(), + ) + } + } + wl_subsurface::Request::SetSync => with_subsurface_attributes::(&subsurface, |attrs| { + attrs.sync = true; + }), + wl_subsurface::Request::SetDesync => with_subsurface_attributes::(&subsurface, |attrs| { + attrs.sync = false; + }), + wl_subsurface::Request::Destroy => { + // Our destructor already handles it + } + _ => unreachable!(), + } + }); + subsurface.assign_destructor(Filter::new(|subsurface, _, _| { + destroy_subsurface::(&subsurface) + })); + subsurface.as_ref().user_data().set_threadsafe(|| surface); + subsurface.deref().clone() } fn destroy_subsurface(subsurface: &wl_subsurface::WlSubsurface) where R: RoleType + Role + 'static, { - let surface = subsurface.as_ref().user_data::().unwrap(); + let surface = subsurface + .as_ref() + .user_data() + .get::() + .unwrap(); if surface.as_ref().is_alive() { SurfaceData::::unset_parent(&surface); } diff --git a/src/wayland/compositor/mod.rs b/src/wayland/compositor/mod.rs index 7e5a71f..3cf066d 100644 --- a/src/wayland/compositor/mod.rs +++ b/src/wayland/compositor/mod.rs @@ -35,8 +35,7 @@ //! // Declare the roles enum //! define_roles!(MyRoles); //! -//! # let mut event_loop = wayland_server::calloop::EventLoop::<()>::new().unwrap(); -//! # let mut display = wayland_server::Display::new(event_loop.handle()); +//! # let mut display = wayland_server::Display::new(); //! // Call the init function: //! let (token, _, _) = compositor_init::( //! &mut display, @@ -85,7 +84,7 @@ use wayland_server::{ protocol::{ wl_buffer, wl_callback, wl_compositor, wl_output, wl_region, wl_subcompositor, wl_surface::WlSurface, }, - Display, Global, NewResource, + Display, Filter, Global, Main, UserDataMap, }; /// Description of which part of a surface @@ -153,7 +152,7 @@ pub struct SurfaceAttributes { /// User-controlled data /// /// This is your field to host whatever you need. - pub user_data: ::wayland_commons::utils::UserDataMap, + pub user_data: UserDataMap, } impl Default for SurfaceAttributes { @@ -165,7 +164,7 @@ impl Default for SurfaceAttributes { opaque_region: None, input_region: None, damage: Damage::Full, - user_data: ::wayland_commons::utils::UserDataMap::new(), + user_data: UserDataMap::new(), } } } @@ -446,7 +445,7 @@ impl CompositorToken { /// If the region is not managed by the `CompositorGlobal` that provided this token, this /// will panic (having more than one compositor is not supported). pub fn get_region_attributes(self, region: &wl_region::WlRegion) -> RegionAttributes { - match region.as_ref().user_data::>() { + match region.as_ref().user_data().get::>() { Some(mutex) => mutex.lock().unwrap().clone(), None => panic!("Accessing the data of foreign regions is not supported."), } @@ -473,19 +472,25 @@ pub fn compositor_init( ) where L: Into>, - R: Default + RoleType + Role + 'static, + R: Default + RoleType + Role + Send + 'static, Impl: FnMut(SurfaceEvent, WlSurface, CompositorToken) + 'static, { let log = crate::slog_or_stdlog(logger).new(o!("smithay_module" => "compositor_handler")); let implem = Rc::new(RefCell::new(implem)); - let compositor = display.create_global(4, move |new_compositor, _version| { - self::handlers::implement_compositor::(new_compositor, log.clone(), implem.clone()); - }); + let compositor = display.create_global( + 4, + Filter::new(move |(new_compositor, _version), _, _| { + self::handlers::implement_compositor::(new_compositor, log.clone(), implem.clone()); + }), + ); - let subcompositor = display.create_global(1, move |new_subcompositor, _version| { - self::handlers::implement_subcompositor::(new_subcompositor); - }); + let subcompositor = display.create_global( + 1, + Filter::new(move |(new_subcompositor, _version), _, _| { + self::handlers::implement_subcompositor::(new_subcompositor); + }), + ); (CompositorToken::make(), compositor, subcompositor) } @@ -513,7 +518,7 @@ pub enum SurfaceEvent { /// for more details Frame { /// The created `WlCallback` - callback: NewResource, + callback: Main, }, } diff --git a/src/wayland/compositor/tree.rs b/src/wayland/compositor/tree.rs index 857c3af..e25a81c 100644 --- a/src/wayland/compositor/tree.rs +++ b/src/wayland/compositor/tree.rs @@ -54,7 +54,11 @@ where { /// Initializes the surface, must be called at creation for state coherence pub fn init(surface: &WlSurface) { - let my_data_mutex = surface.as_ref().user_data::>>().unwrap(); + let my_data_mutex = surface + .as_ref() + .user_data() + .get::>>() + .unwrap(); let mut my_data = my_data_mutex.lock().unwrap(); debug_assert!(my_data.children.is_empty()); my_data.children.push(surface.clone()); @@ -62,11 +66,19 @@ where /// Cleans the `as_ref().user_data` of that surface, must be called when it is destroyed pub fn cleanup(surface: &WlSurface) { - let my_data_mutex = surface.as_ref().user_data::>>().unwrap(); + let my_data_mutex = surface + .as_ref() + .user_data() + .get::>>() + .unwrap(); let mut my_data = my_data_mutex.lock().unwrap(); if let Some(old_parent) = my_data.parent.take() { // We had a parent, lets unregister ourselves from it - let old_parent_mutex = old_parent.as_ref().user_data::>>().unwrap(); + let old_parent_mutex = old_parent + .as_ref() + .user_data() + .get::>>() + .unwrap(); let mut old_parent_guard = old_parent_mutex.lock().unwrap(); old_parent_guard .children @@ -74,7 +86,7 @@ where } // orphan all our children for child in &my_data.children { - let child_mutex = child.as_ref().user_data::>>().unwrap(); + let child_mutex = child.as_ref().user_data().get::>>().unwrap(); if std::ptr::eq(child_mutex, my_data_mutex) { // This child is ourselves, don't do anything. continue; @@ -89,7 +101,11 @@ where impl SurfaceData { pub fn has_a_role(surface: &WlSurface) -> bool { debug_assert!(surface.as_ref().is_alive()); - let data_mutex = surface.as_ref().user_data::>>().unwrap(); + let data_mutex = surface + .as_ref() + .user_data() + .get::>>() + .unwrap(); let data_guard = data_mutex.lock().unwrap(); ::has_role(&data_guard.role) } @@ -100,7 +116,11 @@ impl SurfaceData { R: Role, { debug_assert!(surface.as_ref().is_alive()); - let data_mutex = surface.as_ref().user_data::>>().unwrap(); + let data_mutex = surface + .as_ref() + .user_data() + .get::>>() + .unwrap(); let data_guard = data_mutex.lock().unwrap(); >::has(&data_guard.role) } @@ -112,7 +132,11 @@ impl SurfaceData { RoleData: Default, { debug_assert!(surface.as_ref().is_alive()); - let data_mutex = surface.as_ref().user_data::>>().unwrap(); + let data_mutex = surface + .as_ref() + .user_data() + .get::>>() + .unwrap(); let mut data_guard = data_mutex.lock().unwrap(); >::set(&mut data_guard.role) } @@ -125,7 +149,11 @@ impl SurfaceData { R: Role, { debug_assert!(surface.as_ref().is_alive()); - let data_mutex = surface.as_ref().user_data::>>().unwrap(); + let data_mutex = surface + .as_ref() + .user_data() + .get::>>() + .unwrap(); let mut data_guard = data_mutex.lock().unwrap(); >::set_with(&mut data_guard.role, data) } @@ -139,7 +167,11 @@ impl SurfaceData { R: Role, { debug_assert!(surface.as_ref().is_alive()); - let data_mutex = surface.as_ref().user_data::>>().unwrap(); + let data_mutex = surface + .as_ref() + .user_data() + .get::>>() + .unwrap(); let mut data_guard = data_mutex.lock().unwrap(); >::unset(&mut data_guard.role) } @@ -151,7 +183,11 @@ impl SurfaceData { F: FnOnce(&mut RoleData) -> T, { debug_assert!(surface.as_ref().is_alive()); - let data_mutex = surface.as_ref().user_data::>>().unwrap(); + let data_mutex = surface + .as_ref() + .user_data() + .get::>>() + .unwrap(); let mut data_guard = data_mutex.lock().unwrap(); let data = >::data_mut(&mut data_guard.role)?; Ok(f(data)) @@ -161,7 +197,7 @@ impl SurfaceData { impl + 'static> SurfaceData { /// Checks if the first surface is an ancestor of the second pub fn is_ancestor(a: &WlSurface, b: &WlSurface) -> bool { - let b_mutex = b.as_ref().user_data::>>().unwrap(); + let b_mutex = b.as_ref().user_data().get::>>().unwrap(); let b_guard = b_mutex.lock().unwrap(); if let Some(ref parent) = b_guard.parent { if parent.as_ref().equals(a.as_ref()) { @@ -188,7 +224,7 @@ impl + 'static> SurfaceData { // change child's parent { - let child_mutex = child.as_ref().user_data::>>().unwrap(); + let child_mutex = child.as_ref().user_data().get::>>().unwrap(); let mut child_guard = child_mutex.lock().unwrap(); // if surface already has a role, it cannot become a subsurface >::set(&mut child_guard.role)?; @@ -197,7 +233,11 @@ impl + 'static> SurfaceData { } // register child to new parent { - let parent_mutex = parent.as_ref().user_data::>>().unwrap(); + let parent_mutex = parent + .as_ref() + .user_data() + .get::>>() + .unwrap(); let mut parent_guard = parent_mutex.lock().unwrap(); parent_guard.children.push(child.clone()) } @@ -210,7 +250,7 @@ impl + 'static> SurfaceData { pub fn unset_parent(child: &WlSurface) { debug_assert!(child.as_ref().is_alive()); let old_parent = { - let child_mutex = child.as_ref().user_data::>>().unwrap(); + let child_mutex = child.as_ref().user_data().get::>>().unwrap(); let mut child_guard = child_mutex.lock().unwrap(); let old_parent = child_guard.parent.take(); if old_parent.is_some() { @@ -222,7 +262,11 @@ impl + 'static> SurfaceData { }; // unregister from our parent if let Some(old_parent) = old_parent { - let parent_mutex = old_parent.as_ref().user_data::>>().unwrap(); + let parent_mutex = old_parent + .as_ref() + .user_data() + .get::>>() + .unwrap(); let mut parent_guard = parent_mutex.lock().unwrap(); parent_guard .children @@ -232,14 +276,18 @@ impl + 'static> SurfaceData { /// Retrieve the parent surface (if any) of this surface pub fn get_parent(child: &WlSurface) -> Option { - let child_mutex = child.as_ref().user_data::>>().unwrap(); + let child_mutex = child.as_ref().user_data().get::>>().unwrap(); let child_guard = child_mutex.lock().unwrap(); child_guard.parent.as_ref().cloned() } /// Retrieve the children surface (if any) of this surface pub fn get_children(parent: &WlSurface) -> Vec { - let parent_mutex = parent.as_ref().user_data::>>().unwrap(); + let parent_mutex = parent + .as_ref() + .user_data() + .get::>>() + .unwrap(); let parent_guard = parent_mutex.lock().unwrap(); parent_guard .children @@ -254,7 +302,11 @@ impl + 'static> SurfaceData { /// Fails if `relative_to` is not a sibling or parent of `surface`. pub fn reorder(surface: &WlSurface, to: Location, relative_to: &WlSurface) -> Result<(), ()> { let parent = { - let data_mutex = surface.as_ref().user_data::>>().unwrap(); + let data_mutex = surface + .as_ref() + .user_data() + .get::>>() + .unwrap(); let data_guard = data_mutex.lock().unwrap(); data_guard.parent.as_ref().cloned().unwrap() }; @@ -268,7 +320,11 @@ impl + 'static> SurfaceData { None } - let parent_mutex = parent.as_ref().user_data::>>().unwrap(); + let parent_mutex = parent + .as_ref() + .user_data() + .get::>>() + .unwrap(); let mut parent_guard = parent_mutex.lock().unwrap(); let my_index = index_of(surface, &parent_guard.children).unwrap(); let mut other_index = match index_of(relative_to, &parent_guard.children) { @@ -299,7 +355,8 @@ impl SurfaceData { { let data_mutex = surface .as_ref() - .user_data::>>() + .user_data() + .get::>>() .expect("Accessing the data of foreign surfaces is not supported."); let mut data_guard = data_mutex.lock().unwrap(); f(&mut data_guard.attributes) @@ -354,7 +411,11 @@ impl SurfaceData { F2: FnMut(&WlSurface, &mut SurfaceAttributes, &mut R, &T), F3: FnMut(&WlSurface, &mut SurfaceAttributes, &mut R, &T) -> bool, { - let data_mutex = surface.as_ref().user_data::>>().unwrap(); + let data_mutex = surface + .as_ref() + .user_data() + .get::>>() + .unwrap(); let mut data_guard = data_mutex.lock().unwrap(); let data_guard = &mut *data_guard; // call the filter on ourselves diff --git a/src/wayland/data_device/data_source.rs b/src/wayland/data_device/data_source.rs index 9b11685..1b90afd 100644 --- a/src/wayland/data_device/data_source.rs +++ b/src/wayland/data_device/data_source.rs @@ -1,11 +1,11 @@ -use std::cell::RefCell; +use std::{cell::RefCell, ops::Deref as _}; use wayland_server::{ protocol::{ wl_data_device_manager::DndAction, wl_data_source::{Request, WlDataSource}, }, - NewResource, + Main, }; /// The metadata describing a data source @@ -17,26 +17,27 @@ pub struct SourceMetadata { pub dnd_action: DndAction, } -pub(crate) fn implement_data_source(src: NewResource) -> WlDataSource { - src.implement_closure( - |req, me| { - let data: &RefCell = me.as_ref().user_data().unwrap(); - let mut guard = data.borrow_mut(); - match req { - Request::Offer { mime_type } => guard.mime_types.push(mime_type), - Request::SetActions { dnd_actions } => { - guard.dnd_action = DndAction::from_bits_truncate(dnd_actions); - } - Request::Destroy => {} - _ => unreachable!(), +pub(crate) fn implement_data_source(src: Main) -> WlDataSource { + src.quick_assign(|me, req, _| { + let data: &RefCell = me.as_ref().user_data().get().unwrap(); + let mut guard = data.borrow_mut(); + match req { + Request::Offer { mime_type } => guard.mime_types.push(mime_type), + Request::SetActions { dnd_actions } => { + guard.dnd_action = DndAction::from_bits_truncate(dnd_actions); } - }, - None::, + Request::Destroy => {} + _ => unreachable!(), + } + }); + src.as_ref().user_data().set(|| { RefCell::new(SourceMetadata { mime_types: Vec::new(), dnd_action: DndAction::None, - }), - ) + }) + }); + + src.deref().clone() } /// Access the metadata of a data source @@ -44,7 +45,7 @@ pub fn with_source_metadata T>( source: &WlDataSource, f: F, ) -> Result { - match source.as_ref().user_data::>() { + match source.as_ref().user_data().get::>() { Some(data) => Ok(f(&data.borrow())), None => Err(()), } diff --git a/src/wayland/data_device/dnd_grab.rs b/src/wayland/data_device/dnd_grab.rs index 7b9c1cd..6947a21 100644 --- a/src/wayland/data_device/dnd_grab.rs +++ b/src/wayland/data_device/dnd_grab.rs @@ -1,9 +1,8 @@ -use std::cell::RefCell; -use std::rc::Rc; +use std::{cell::RefCell, ops::Deref as _, rc::Rc}; use wayland_server::{ protocol::{wl_data_device_manager::DndAction, wl_data_offer, wl_data_source, wl_pointer, wl_surface}, - NewResource, + Main, }; use crate::wayland::{ @@ -107,7 +106,8 @@ impl + 'static> PointerGrab for DnDGrab { { let action_choice = device .as_ref() - .user_data::() + .user_data() + .get::() .unwrap() .action_choice .clone(); @@ -239,94 +239,91 @@ struct OfferData { } fn implement_dnd_data_offer( - offer: NewResource, + offer: Main, source: wl_data_source::WlDataSource, offer_data: Rc>, action_choice: Rc DndAction + 'static>>, ) -> wl_data_offer::WlDataOffer { use self::wl_data_offer::Request; - offer.implement_closure( - move |req, offer| { - let mut data = offer_data.borrow_mut(); - match req { - Request::Accept { mime_type, .. } => { - if let Some(mtype) = mime_type { - if let Err(()) = with_source_metadata(&source, |meta| { - data.accepted = meta.mime_types.contains(&mtype); - }) { - data.accepted = false; - } - } else { + offer.quick_assign(move |offer, req, _| { + let mut data = offer_data.borrow_mut(); + match req { + Request::Accept { mime_type, .. } => { + if let Some(mtype) = mime_type { + if let Err(()) = with_source_metadata(&source, |meta| { + data.accepted = meta.mime_types.contains(&mtype); + }) { data.accepted = false; } + } else { + data.accepted = false; } - Request::Receive { mime_type, fd } => { - // check if the source and associated mime type is still valid - let valid = with_source_metadata(&source, |meta| meta.mime_types.contains(&mime_type)) - .unwrap_or(false) - && source.as_ref().is_alive() - && data.active; - if valid { - source.send(mime_type, fd); - } - let _ = ::nix::unistd::close(fd); - } - Request::Destroy => {} - Request::Finish => { - if !data.active { - offer.as_ref().post_error( - wl_data_offer::Error::InvalidFinish as u32, - "Cannot finish a data offer that is no longer active.".into(), - ); - } - if !data.accepted { - offer.as_ref().post_error( - wl_data_offer::Error::InvalidFinish as u32, - "Cannot finish a data offer that has not been accepted.".into(), - ); - } - if !data.dropped { - offer.as_ref().post_error( - wl_data_offer::Error::InvalidFinish as u32, - "Cannot finish a data offer that has not been dropped.".into(), - ); - } - if data.chosen_action.is_empty() { - offer.as_ref().post_error( - wl_data_offer::Error::InvalidFinish as u32, - "Cannot finish a data offer with no valid action.".into(), - ); - } - source.dnd_finished(); - data.active = false; - } - Request::SetActions { - dnd_actions, - preferred_action, - } => { - let preferred_action = DndAction::from_bits_truncate(preferred_action); - if ![DndAction::Move, DndAction::Copy, DndAction::Ask].contains(&preferred_action) { - offer.as_ref().post_error( - wl_data_offer::Error::InvalidAction as u32, - "Invalid preferred action.".into(), - ); - } - let source_actions = with_source_metadata(&source, |meta| meta.dnd_action) - .unwrap_or_else(|_| DndAction::empty()); - let possible_actions = source_actions & DndAction::from_bits_truncate(dnd_actions); - data.chosen_action = - (&mut *action_choice.borrow_mut())(possible_actions, preferred_action); - // check that the user provided callback respects that one precise action should be chosen - debug_assert!( - [DndAction::Move, DndAction::Copy, DndAction::Ask].contains(&data.chosen_action) - ); - offer.action(data.chosen_action.to_raw()); - source.action(data.chosen_action.to_raw()); - } - _ => unreachable!(), } - }, - None::, - (), - ) + Request::Receive { mime_type, fd } => { + // check if the source and associated mime type is still valid + let valid = with_source_metadata(&source, |meta| meta.mime_types.contains(&mime_type)) + .unwrap_or(false) + && source.as_ref().is_alive() + && data.active; + if valid { + source.send(mime_type, fd); + } + let _ = ::nix::unistd::close(fd); + } + Request::Destroy => {} + Request::Finish => { + if !data.active { + offer.as_ref().post_error( + wl_data_offer::Error::InvalidFinish as u32, + "Cannot finish a data offer that is no longer active.".into(), + ); + } + if !data.accepted { + offer.as_ref().post_error( + wl_data_offer::Error::InvalidFinish as u32, + "Cannot finish a data offer that has not been accepted.".into(), + ); + } + if !data.dropped { + offer.as_ref().post_error( + wl_data_offer::Error::InvalidFinish as u32, + "Cannot finish a data offer that has not been dropped.".into(), + ); + } + if data.chosen_action.is_empty() { + offer.as_ref().post_error( + wl_data_offer::Error::InvalidFinish as u32, + "Cannot finish a data offer with no valid action.".into(), + ); + } + source.dnd_finished(); + data.active = false; + } + Request::SetActions { + dnd_actions, + preferred_action, + } => { + let preferred_action = DndAction::from_bits_truncate(preferred_action); + if ![DndAction::Move, DndAction::Copy, DndAction::Ask].contains(&preferred_action) { + offer.as_ref().post_error( + wl_data_offer::Error::InvalidAction as u32, + "Invalid preferred action.".into(), + ); + } + let source_actions = with_source_metadata(&source, |meta| meta.dnd_action) + .unwrap_or_else(|_| DndAction::empty()); + let possible_actions = source_actions & DndAction::from_bits_truncate(dnd_actions); + data.chosen_action = (&mut *action_choice.borrow_mut())(possible_actions, preferred_action); + // check that the user provided callback respects that one precise action should be chosen + debug_assert!( + [DndAction::Move, DndAction::Copy, DndAction::Ask].contains(&data.chosen_action) + ); + offer.action(data.chosen_action.to_raw()); + source.action(data.chosen_action.to_raw()); + } + _ => unreachable!(), + } + }); + + offer.deref().clone() } diff --git a/src/wayland/data_device/mod.rs b/src/wayland/data_device/mod.rs index 96996b3..ae8a01b 100644 --- a/src/wayland/data_device/mod.rs +++ b/src/wayland/data_device/mod.rs @@ -40,8 +40,7 @@ //! // to set a surface as a dnd icon //! define_roles!(Roles => [DnDIcon, DnDIconRole]); //! -//! # let mut event_loop = wayland_server::calloop::EventLoop::<()>::new().unwrap(); -//! # let mut display = wayland_server::Display::new(event_loop.handle()); +//! # let mut display = wayland_server::Display::new(); //! # let (compositor_token, _, _) = compositor_init::(&mut display, |_, _, _| {}, None); //! // init the data device: //! init_data_device( @@ -54,9 +53,7 @@ //! ); //! ``` -use std::cell::RefCell; -use std::os::unix::io::RawFd; -use std::rc::Rc; +use std::{cell::RefCell, ops::Deref as _, os::unix::io::RawFd, rc::Rc}; use wayland_server::{ protocol::{ @@ -64,7 +61,7 @@ use wayland_server::{ wl_data_device_manager::{self, DndAction}, wl_data_offer, wl_data_source, wl_surface, }, - Client, Display, Global, NewResource, + Client, Display, Filter, Global, Main, }; use crate::wayland::{ @@ -175,29 +172,24 @@ impl SeatData { // create a corresponding data offer let offer = client .create_resource::(dd.as_ref().version()) - .unwrap() - .implement_closure( - move |req, _offer| { - // selection data offers only care about the `receive` event - if let wl_data_offer::Request::Receive { fd, mime_type } = req { - // check if the source and associated mime type is still valid - let valid = with_source_metadata(&source, |meta| { - meta.mime_types.contains(&mime_type) - }) + .unwrap(); + offer.quick_assign(move |_offer, req, _| { + // selection data offers only care about the `receive` event + if let wl_data_offer::Request::Receive { fd, mime_type } = req { + // check if the source and associated mime type is still valid + let valid = + with_source_metadata(&source, |meta| meta.mime_types.contains(&mime_type)) .unwrap_or(false) - && source.as_ref().is_alive(); - if !valid { - // deny the receive - debug!(log, "Denying a wl_data_offer.receive with invalid source."); - } else { - source.send(mime_type, fd); - } - let _ = ::nix::unistd::close(fd); - } - }, - None::, - (), - ); + && source.as_ref().is_alive(); + if !valid { + // deny the receive + debug!(log, "Denying a wl_data_offer.receive with invalid source."); + } else { + source.send(mime_type, fd); + } + let _ = ::nix::unistd::close(fd); + } + }); // advertize the offer to the client dd.data_offer(&offer); with_source_metadata(data_source, |meta| { @@ -219,34 +211,31 @@ impl SeatData { let offer_meta = meta.clone(); let callback = dd .as_ref() - .user_data::() + .user_data() + .get::() .unwrap() .callback .clone(); // create a corresponding data offer let offer = client .create_resource::(dd.as_ref().version()) - .unwrap() - .implement_closure( - move |req, _offer| { - // selection data offers only care about the `receive` event - if let wl_data_offer::Request::Receive { fd, mime_type } = req { - // check if the associated mime type is valid - if !offer_meta.mime_types.contains(&mime_type) { - // deny the receive - debug!(log, "Denying a wl_data_offer.receive with invalid source."); - let _ = ::nix::unistd::close(fd); - } else { - (&mut *callback.borrow_mut())(DataDeviceEvent::SendSelection { - mime_type, - fd, - }); - } - } - }, - None::, - (), - ); + .unwrap(); + offer.quick_assign(move |_offer, req, _| { + // selection data offers only care about the `receive` event + if let wl_data_offer::Request::Receive { fd, mime_type } = req { + // check if the associated mime type is valid + if !offer_meta.mime_types.contains(&mime_type) { + // deny the receive + debug!(log, "Denying a wl_data_offer.receive with invalid source."); + let _ = ::nix::unistd::close(fd); + } else { + (&mut *callback.borrow_mut())(DataDeviceEvent::SendSelection { + mime_type, + fd, + }); + } + } + }); // advertize the offer to the client dd.data_offer(&offer); for mime_type in meta.mime_types.iter().cloned() { @@ -300,15 +289,12 @@ where let log = crate::slog_or_stdlog(logger).new(o!("smithay_module" => "data_device_mgr")); let action_choice = Rc::new(RefCell::new(action_choice)); let callback = Rc::new(RefCell::new(callback)); - display.create_global(3, move |new_ddm, _version| { - implement_ddm( - new_ddm, - callback.clone(), - action_choice.clone(), - token, - log.clone(), - ); - }) + display.create_global( + 3, + Filter::new(move |(ddm, _version), _, _| { + implement_ddm(ddm, callback.clone(), action_choice.clone(), token, log.clone()); + }), + ) } /// Set the data device focus to a certain client for a given seat @@ -384,7 +370,7 @@ pub fn start_dnd( } fn implement_ddm( - new_ddm: NewResource, + ddm: Main, callback: Rc>, action_choice: Rc>, token: CompositorToken, @@ -396,36 +382,34 @@ where R: Role + 'static, { use self::wl_data_device_manager::Request; - new_ddm.implement_closure( - move |req, _ddm| match req { - Request::CreateDataSource { id } => { - self::data_source::implement_data_source(id); + ddm.quick_assign(move |_ddm, req, _data| match req { + Request::CreateDataSource { id } => { + self::data_source::implement_data_source(id); + } + Request::GetDataDevice { id, seat } => match Seat::from_resource(&seat) { + Some(seat) => { + // ensure the seat user_data is ready + seat.user_data() + .insert_if_missing(|| RefCell::new(SeatData::new(log.clone()))); + let seat_data = seat.user_data().get::>().unwrap(); + let data_device = implement_data_device( + id, + seat.clone(), + callback.clone(), + action_choice.clone(), + token, + log.clone(), + ); + seat_data.borrow_mut().known_devices.push(data_device); + } + None => { + error!(log, "Unmanaged seat given to a data device."); } - Request::GetDataDevice { id, seat } => match Seat::from_resource(&seat) { - Some(seat) => { - // ensure the seat user_data is ready - seat.user_data() - .insert_if_missing(|| RefCell::new(SeatData::new(log.clone()))); - let seat_data = seat.user_data().get::>().unwrap(); - let data_device = implement_data_device( - id, - seat.clone(), - callback.clone(), - action_choice.clone(), - token, - log.clone(), - ); - seat_data.borrow_mut().known_devices.push(data_device); - } - None => { - error!(log, "Unmanaged seat given to a data device."); - } - }, - _ => unreachable!(), }, - None::, - (), - ) + _ => unreachable!(), + }); + + ddm.deref().clone() } struct DataDeviceData { @@ -434,7 +418,7 @@ struct DataDeviceData { } fn implement_data_device( - new_dd: NewResource, + dd: Main, seat: Seat, callback: Rc>, action_choice: Rc>, @@ -451,83 +435,82 @@ where callback: callback.clone(), action_choice, }; - new_dd.implement_closure( - move |req, dd| match req { - Request::StartDrag { - source, - origin, - icon, - serial, - } => { - /* TODO: handle the icon */ - if let Some(pointer) = seat.get_pointer() { - if pointer.has_grab(serial) { - if let Some(ref icon) = icon { - if token.give_role::(icon).is_err() { - dd.as_ref().post_error( - wl_data_device::Error::Role as u32, - "Given surface already has an other role".into(), - ); - return; - } + dd.quick_assign(move |dd, req, _| match req { + Request::StartDrag { + source, + origin, + icon, + serial, + } => { + /* TODO: handle the icon */ + if let Some(pointer) = seat.get_pointer() { + if pointer.has_grab(serial) { + if let Some(ref icon) = icon { + if token.give_role::(icon).is_err() { + dd.as_ref().post_error( + wl_data_device::Error::Role as u32, + "Given surface already has an other role".into(), + ); + return; } - // The StartDrag is in response to a pointer implicit grab, all is good - (&mut *callback.borrow_mut())(DataDeviceEvent::DnDStarted { - source: source.clone(), - icon: icon.clone(), - }); - let start_data = pointer.grab_start_data().unwrap(); - pointer.set_grab( - dnd_grab::DnDGrab::new( - start_data, - source, - origin, - seat.clone(), - icon, - token, - callback.clone(), - ), - serial, - ); - return; } + // The StartDrag is in response to a pointer implicit grab, all is good + (&mut *callback.borrow_mut())(DataDeviceEvent::DnDStarted { + source: source.clone(), + icon: icon.clone(), + }); + let start_data = pointer.grab_start_data().unwrap(); + pointer.set_grab( + dnd_grab::DnDGrab::new( + start_data, + source, + origin, + seat.clone(), + icon, + token, + callback.clone(), + ), + serial, + ); + return; } - debug!(log, "denying drag from client without implicit grab"); } - Request::SetSelection { source, .. } => { - if let Some(keyboard) = seat.get_keyboard() { - if dd - .as_ref() - .client() - .as_ref() - .map(|c| keyboard.has_focus(c)) - .unwrap_or(false) - { - let seat_data = seat.user_data().get::>().unwrap(); - (&mut *callback.borrow_mut())(DataDeviceEvent::NewSelection(source.clone())); - // The client has kbd focus, it can set the selection - seat_data - .borrow_mut() - .set_selection(source.map(Selection::Client).unwrap_or(Selection::Empty)); - return; - } + debug!(log, "denying drag from client without implicit grab"); + } + Request::SetSelection { source, .. } => { + if let Some(keyboard) = seat.get_keyboard() { + if dd + .as_ref() + .client() + .as_ref() + .map(|c| keyboard.has_focus(c)) + .unwrap_or(false) + { + let seat_data = seat.user_data().get::>().unwrap(); + (&mut *callback.borrow_mut())(DataDeviceEvent::NewSelection(source.clone())); + // The client has kbd focus, it can set the selection + seat_data + .borrow_mut() + .set_selection(source.map(Selection::Client).unwrap_or(Selection::Empty)); + return; } - debug!(log, "denying setting selection by a non-focused client"); } - Request::Release => { - // Clean up the known devices - seat.user_data() - .get::>() - .unwrap() - .borrow_mut() - .known_devices - .retain(|ndd| ndd.as_ref().is_alive() && (!ndd.as_ref().equals(&dd.as_ref()))) - } - _ => unreachable!(), - }, - None::, - dd_data, - ) + debug!(log, "denying setting selection by a non-focused client"); + } + Request::Release => { + // Clean up the known devices + seat.user_data() + .get::>() + .unwrap() + .borrow_mut() + .known_devices + .retain(|ndd| ndd.as_ref().is_alive() && (!ndd.as_ref().equals(&dd.as_ref()))) + } + _ => unreachable!(), + }); + dd.as_ref().user_data().set(|| dd_data); + + dd.deref().clone() } /// A simple action chooser for DnD negociation diff --git a/src/wayland/data_device/server_dnd_grab.rs b/src/wayland/data_device/server_dnd_grab.rs index a2ce916..f9152ef 100644 --- a/src/wayland/data_device/server_dnd_grab.rs +++ b/src/wayland/data_device/server_dnd_grab.rs @@ -1,10 +1,8 @@ -use std::cell::RefCell; -use std::os::unix::io::RawFd; -use std::rc::Rc; +use std::{cell::RefCell, ops::Deref as _, os::unix::io::RawFd, rc::Rc}; use wayland_server::{ protocol::{wl_data_device_manager::DndAction, wl_data_offer, wl_pointer, wl_surface}, - NewResource, + Main, }; use crate::wayland::seat::{AxisFrame, GrabStartData, PointerGrab, PointerInnerHandle, Seat}; @@ -120,7 +118,8 @@ where { let action_choice = device .as_ref() - .user_data::() + .user_data() + .get::() .unwrap() .action_choice .clone(); @@ -229,7 +228,7 @@ struct OfferData { } fn implement_dnd_data_offer( - offer: NewResource, + offer: Main, metadata: super::SourceMetadata, offer_data: Rc>, callback: Rc>, @@ -239,77 +238,74 @@ where C: FnMut(ServerDndEvent) + 'static, { use self::wl_data_offer::Request; - offer.implement_closure( - move |req, offer| { - let mut data = offer_data.borrow_mut(); - match req { - Request::Accept { mime_type, .. } => { - if let Some(mtype) = mime_type { - data.accepted = metadata.mime_types.contains(&mtype); - } else { - data.accepted = false; - } + offer.quick_assign(move |offer, req, _| { + let mut data = offer_data.borrow_mut(); + match req { + Request::Accept { mime_type, .. } => { + if let Some(mtype) = mime_type { + data.accepted = metadata.mime_types.contains(&mtype); + } else { + data.accepted = false; } - Request::Receive { mime_type, fd } => { - // check if the source and associated mime type is still valid - if metadata.mime_types.contains(&mime_type) && data.active { - (&mut *callback.borrow_mut())(ServerDndEvent::Send { mime_type, fd }); - } - } - Request::Destroy => {} - Request::Finish => { - if !data.active { - offer.as_ref().post_error( - wl_data_offer::Error::InvalidFinish as u32, - "Cannot finish a data offer that is no longer active.".into(), - ); - } - if !data.accepted { - offer.as_ref().post_error( - wl_data_offer::Error::InvalidFinish as u32, - "Cannot finish a data offer that has not been accepted.".into(), - ); - } - if !data.dropped { - offer.as_ref().post_error( - wl_data_offer::Error::InvalidFinish as u32, - "Cannot finish a data offer that has not been dropped.".into(), - ); - } - if data.chosen_action.is_empty() { - offer.as_ref().post_error( - wl_data_offer::Error::InvalidFinish as u32, - "Cannot finish a data offer with no valid action.".into(), - ); - } - (&mut *callback.borrow_mut())(ServerDndEvent::Finished); - data.active = false; - } - Request::SetActions { - dnd_actions, - preferred_action, - } => { - let preferred_action = DndAction::from_bits_truncate(preferred_action); - if ![DndAction::Move, DndAction::Copy, DndAction::Ask].contains(&preferred_action) { - offer.as_ref().post_error( - wl_data_offer::Error::InvalidAction as u32, - "Invalid preferred action.".into(), - ); - } - let possible_actions = metadata.dnd_action & DndAction::from_bits_truncate(dnd_actions); - data.chosen_action = - (&mut *action_choice.borrow_mut())(possible_actions, preferred_action); - // check that the user provided callback respects that one precise action should be chosen - debug_assert!( - [DndAction::Move, DndAction::Copy, DndAction::Ask].contains(&data.chosen_action) - ); - offer.action(data.chosen_action.to_raw()); - (&mut *callback.borrow_mut())(ServerDndEvent::Action(data.chosen_action)); - } - _ => unreachable!(), } - }, - None::, - (), - ) + Request::Receive { mime_type, fd } => { + // check if the source and associated mime type is still valid + if metadata.mime_types.contains(&mime_type) && data.active { + (&mut *callback.borrow_mut())(ServerDndEvent::Send { mime_type, fd }); + } + } + Request::Destroy => {} + Request::Finish => { + if !data.active { + offer.as_ref().post_error( + wl_data_offer::Error::InvalidFinish as u32, + "Cannot finish a data offer that is no longer active.".into(), + ); + } + if !data.accepted { + offer.as_ref().post_error( + wl_data_offer::Error::InvalidFinish as u32, + "Cannot finish a data offer that has not been accepted.".into(), + ); + } + if !data.dropped { + offer.as_ref().post_error( + wl_data_offer::Error::InvalidFinish as u32, + "Cannot finish a data offer that has not been dropped.".into(), + ); + } + if data.chosen_action.is_empty() { + offer.as_ref().post_error( + wl_data_offer::Error::InvalidFinish as u32, + "Cannot finish a data offer with no valid action.".into(), + ); + } + (&mut *callback.borrow_mut())(ServerDndEvent::Finished); + data.active = false; + } + Request::SetActions { + dnd_actions, + preferred_action, + } => { + let preferred_action = DndAction::from_bits_truncate(preferred_action); + if ![DndAction::Move, DndAction::Copy, DndAction::Ask].contains(&preferred_action) { + offer.as_ref().post_error( + wl_data_offer::Error::InvalidAction as u32, + "Invalid preferred action.".into(), + ); + } + let possible_actions = metadata.dnd_action & DndAction::from_bits_truncate(dnd_actions); + data.chosen_action = (&mut *action_choice.borrow_mut())(possible_actions, preferred_action); + // check that the user provided callback respects that one precise action should be chosen + debug_assert!( + [DndAction::Move, DndAction::Copy, DndAction::Ask].contains(&data.chosen_action) + ); + offer.action(data.chosen_action.to_raw()); + (&mut *callback.borrow_mut())(ServerDndEvent::Action(data.chosen_action)); + } + _ => unreachable!(), + } + }); + + offer.deref().clone() } diff --git a/src/wayland/dmabuf/mod.rs b/src/wayland/dmabuf/mod.rs index 63f1177..3329170 100644 --- a/src/wayland/dmabuf/mod.rs +++ b/src/wayland/dmabuf/mod.rs @@ -51,8 +51,7 @@ //! //! // Once this is defined, you can in your setup initialize the dmabuf global: //! -//! # let mut event_loop = wayland_server::calloop::EventLoop::<()>::new().unwrap(); -//! # let mut display = wayland_server::Display::new(event_loop.handle()); +//! # let mut display = wayland_server::Display::new(); //! // define your supported formats //! let formats = vec![ //! /* ... */ @@ -70,11 +69,11 @@ use std::{cell::RefCell, os::unix::io::RawFd, rc::Rc}; pub use wayland_protocols::unstable::linux_dmabuf::v1::server::zwp_linux_buffer_params_v1::Flags; use wayland_protocols::unstable::linux_dmabuf::v1::server::{ zwp_linux_buffer_params_v1::{ - Error as ParamError, RequestHandler as ParamRequestHandler, ZwpLinuxBufferParamsV1 as BufferParams, + Error as ParamError, Request as ParamsRequest, ZwpLinuxBufferParamsV1 as BufferParams, }, zwp_linux_dmabuf_v1, }; -use wayland_server::{protocol::wl_buffer, Display, Global, NewResource}; +use wayland_server::{protocol::wl_buffer, Display, Global, Main, Filter}; /// Representation of a Dmabuf format, as advertized to the client pub struct Format { @@ -161,9 +160,11 @@ pub trait DmabufHandler { fn create_buffer( &mut self, data: Self::BufferData, - buffer: NewResource, + buffer: Main, ) -> wl_buffer::WlBuffer { - buffer.implement_closure(|_, _| {}, None::, data) + buffer.quick_assign(|_, _, _| {}); + buffer.as_ref().user_data().set(|| data); + (*buffer).clone() } } @@ -193,29 +194,35 @@ where formats.len() ); - display.create_global(3, move |new_dmabuf, version| { + display.create_global(3, Filter::new(move |(dmabuf, version): (Main, u32), _, _| { let dma_formats = formats.clone(); let dma_handler = handler.clone(); let dma_log = log.clone(); - let dmabuf: zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1 = new_dmabuf.implement_closure( - move |req, _| { + dmabuf.quick_assign( + move |_, req, _| { if let zwp_linux_dmabuf_v1::Request::CreateParams { params_id } = req { - params_id.implement( - ParamsHandler { - pending_planes: Vec::new(), - max_planes, - used: false, - formats: dma_formats.clone(), - handler: dma_handler.clone(), - log: dma_log.clone(), + let mut handler = ParamsHandler { + pending_planes: Vec::new(), + max_planes, + used: false, + formats: dma_formats.clone(), + handler: dma_handler.clone(), + log: dma_log.clone(), + }; + params_id.quick_assign(move |params, req, _| match req { + ParamsRequest::Add { fd, plane_idx, offset, stride, modifier_hi, modifier_lo } => { + handler.add(&*params, fd, plane_idx, offset, stride, modifier_hi, modifier_lo) }, - None::, - (), - ); + ParamsRequest::Create { width, height, format, flags } => { + handler.create(&*params, width, height, format, flags) + }, + ParamsRequest::CreateImmed { buffer_id, width, height, format, flags } => { + handler.create_immed(&*params, buffer_id, width, height, format, flags) + } + _ => {} + }); } - }, - None::, - (), + } ); // send the supported formats @@ -225,7 +232,7 @@ where dmabuf.modifier(f.format.as_raw(), (f.modifier >> 32) as u32, f.modifier as u32); } } - }) + })) } struct ParamsHandler { @@ -237,10 +244,10 @@ struct ParamsHandler { log: ::slog::Logger, } -impl ParamRequestHandler for ParamsHandler { +impl ParamsHandler { fn add( &mut self, - params: BufferParams, + params: &BufferParams, fd: RawFd, plane_idx: u32, offset: u32, @@ -284,7 +291,7 @@ impl ParamRequestHandler for ParamsHandler { }); } - fn create(&mut self, params: BufferParams, width: i32, height: i32, format: u32, flags: u32) { + fn create(&mut self, params: &BufferParams, width: i32, height: i32, format: u32, flags: u32) { // Cannot reuse a params: if self.used { params.as_ref().post_error( @@ -331,8 +338,8 @@ impl ParamRequestHandler for ParamsHandler { fn create_immed( &mut self, - params: BufferParams, - buffer_id: NewResource, + params: &BufferParams, + buffer_id: Main, width: i32, height: i32, format: u32, diff --git a/src/wayland/explicit_synchronization/mod.rs b/src/wayland/explicit_synchronization/mod.rs index dfdf050..150ba87 100644 --- a/src/wayland/explicit_synchronization/mod.rs +++ b/src/wayland/explicit_synchronization/mod.rs @@ -28,8 +28,7 @@ //! use smithay::wayland::explicit_synchronization::*; //! # define_roles!(MyRoles); //! # -//! # let mut event_loop = wayland_server::calloop::EventLoop::<()>::new().unwrap(); -//! # let mut display = wayland_server::Display::new(event_loop.handle()); +//! # let mut display = wayland_server::Display::new(); //! # let (compositor_token, _, _) = smithay::wayland::compositor::compositor_init::( //! # &mut display, //! # |_, _, _| {}, @@ -71,16 +70,24 @@ //! # } //! ``` -use std::os::unix::io::RawFd; +use std::{ + cell::RefCell, + ops::{Deref as _, DerefMut as _}, + os::unix::io::RawFd, +}; -use wayland_protocols::unstable::linux_explicit_synchronization::v1::server::*; -use wayland_server::{protocol::wl_surface::WlSurface, Display, Global, NewResource}; +use wayland_protocols::unstable::linux_explicit_synchronization::v1::server::{ + zwp_linux_buffer_release_v1::ZwpLinuxBufferReleaseV1, + zwp_linux_explicit_synchronization_v1::{self, ZwpLinuxExplicitSynchronizationV1}, + zwp_linux_surface_synchronization_v1::{self, ZwpLinuxSurfaceSynchronizationV1}, +}; +use wayland_server::{protocol::wl_surface::WlSurface, Display, Filter, Global, Main}; use crate::wayland::compositor::{CompositorToken, SurfaceAttributes}; /// An object to signal end of use of a buffer pub struct ExplicitBufferRelease { - release: zwp_linux_buffer_release_v1::ZwpLinuxBufferReleaseV1, + release: ZwpLinuxBufferReleaseV1, } impl ExplicitBufferRelease { @@ -115,16 +122,16 @@ pub struct ExplicitSyncState { struct InternalState { sync_state: ExplicitSyncState, - sync_resource: zwp_linux_surface_synchronization_v1::ZwpLinuxSurfaceSynchronizationV1, + sync_resource: ZwpLinuxSurfaceSynchronizationV1, } struct ESUserData { - state: Option, + state: RefCell>, } impl ESUserData { - fn take_state(&mut self) -> Option { - if let Some(ref mut state) = self.state { + fn take_state(&self) -> Option { + if let Some(state) = self.state.borrow_mut().deref_mut() { Some(ExplicitSyncState { acquire: state.sync_state.acquire.take(), release: state.sync_state.release.take(), @@ -156,7 +163,7 @@ pub enum ExplicitSyncError { pub fn get_explicit_synchronization_state(attrs: &mut SurfaceAttributes) -> Result { attrs .user_data - .get_mut::() + .get::() .and_then(|s| s.take_state()) .ok_or(()) } @@ -168,7 +175,7 @@ pub fn get_explicit_synchronization_state(attrs: &mut SurfaceAttributes) -> Resu /// function. pub fn send_explicit_synchronization_error(attrs: &SurfaceAttributes, error: ExplicitSyncError) { if let Some(ref data) = attrs.user_data.get::() { - if let Some(ref state) = data.state { + if let Some(state) = data.state.borrow().deref() { match error { ExplicitSyncError::InvalidFence => state.sync_resource.as_ref().post_error( zwp_linux_surface_synchronization_v1::Error::InvalidFence as u32, @@ -194,29 +201,31 @@ pub fn init_explicit_synchronization_global( display: &mut Display, compositor: CompositorToken, logger: L, -) -> Global +) -> Global where L: Into>, R: 'static, { let _log = crate::slog_or_stdlog(logger).new(o!("smithay_module" => "wayland_explicit_synchronization")); - display.create_global::( + display.create_global::( 2, - move |new_sync, _version| { - new_sync.implement_closure( - move |req, explicit_sync| { + Filter::new( + move |(sync, _version): (Main, _), _, _| { + sync.quick_assign(move |explicit_sync, req, _| { if let zwp_linux_explicit_synchronization_v1::Request::GetSynchronization { id, surface, } = req { let exists = compositor.with_surface_data(&surface, |attrs| { - attrs.user_data.insert_if_missing(|| ESUserData { state: None }); + attrs.user_data.insert_if_missing(|| ESUserData { + state: RefCell::new(None), + }); attrs .user_data .get::() - .map(|ud| ud.state.is_some()) + .map(|ud| ud.state.borrow().is_some()) .unwrap() }); if exists { @@ -228,8 +237,8 @@ where } let surface_sync = implement_surface_sync(id, surface.clone(), compositor); compositor.with_surface_data(&surface, |attrs| { - let data = attrs.user_data.get_mut::().unwrap(); - data.state = Some(InternalState { + let data = attrs.user_data.get::().unwrap(); + *data.state.borrow_mut() = Some(InternalState { sync_state: ExplicitSyncState { acquire: None, release: None, @@ -238,79 +247,75 @@ where }); }); } - }, - None::, - (), - ); - }, + }); + }, + ), ) } fn implement_surface_sync( - id: NewResource, + id: Main, surface: WlSurface, compositor: CompositorToken, -) -> zwp_linux_surface_synchronization_v1::ZwpLinuxSurfaceSynchronizationV1 +) -> ZwpLinuxSurfaceSynchronizationV1 where R: 'static, { - id.implement_closure( - move |req, surface_sync| match req { - zwp_linux_surface_synchronization_v1::Request::SetAcquireFence { fd } => { - if !surface.as_ref().is_alive() { - surface_sync.as_ref().post_error( - zwp_linux_surface_synchronization_v1::Error::NoSurface as u32, - "The associated wl_surface was destroyed.".into(), - ) + id.quick_assign(move |surface_sync, req, _| match req { + zwp_linux_surface_synchronization_v1::Request::SetAcquireFence { fd } => { + if !surface.as_ref().is_alive() { + surface_sync.as_ref().post_error( + zwp_linux_surface_synchronization_v1::Error::NoSurface as u32, + "The associated wl_surface was destroyed.".into(), + ) + } + compositor.with_surface_data(&surface, |attrs| { + let data = attrs.user_data.get::().unwrap(); + if let Some(state) = data.state.borrow_mut().deref_mut() { + if state.sync_state.acquire.is_some() { + surface_sync.as_ref().post_error( + zwp_linux_surface_synchronization_v1::Error::DuplicateFence as u32, + "Multiple fences added for a single surface commit.".into(), + ) + } else { + state.sync_state.acquire = Some(fd); + } } - compositor.with_surface_data(&surface, |attrs| { - let data = attrs.user_data.get_mut::().unwrap(); - if let Some(ref mut state) = data.state { - if state.sync_state.acquire.is_some() { - surface_sync.as_ref().post_error( - zwp_linux_surface_synchronization_v1::Error::DuplicateFence as u32, - "Multiple fences added for a single surface commit.".into(), - ) - } else { - state.sync_state.acquire = Some(fd); - } - } - }); + }); + } + zwp_linux_surface_synchronization_v1::Request::GetRelease { release } => { + if !surface.as_ref().is_alive() { + surface_sync.as_ref().post_error( + zwp_linux_surface_synchronization_v1::Error::NoSurface as u32, + "The associated wl_surface was destroyed.".into(), + ) } - zwp_linux_surface_synchronization_v1::Request::GetRelease { release } => { - if !surface.as_ref().is_alive() { - surface_sync.as_ref().post_error( - zwp_linux_surface_synchronization_v1::Error::NoSurface as u32, - "The associated wl_surface was destroyed.".into(), - ) + compositor.with_surface_data(&surface, |attrs| { + let data = attrs.user_data.get::().unwrap(); + if let Some(state) = data.state.borrow_mut().deref_mut() { + if state.sync_state.acquire.is_some() { + surface_sync.as_ref().post_error( + zwp_linux_surface_synchronization_v1::Error::DuplicateRelease as u32, + "Multiple releases added for a single surface commit.".into(), + ) + } else { + release.quick_assign(|_, _, _| {}); + state.sync_state.release = Some(ExplicitBufferRelease { + release: release.deref().clone(), + }); + } } - compositor.with_surface_data(&surface, |attrs| { - let data = attrs.user_data.get_mut::().unwrap(); - if let Some(ref mut state) = data.state { - if state.sync_state.acquire.is_some() { - surface_sync.as_ref().post_error( - zwp_linux_surface_synchronization_v1::Error::DuplicateRelease as u32, - "Multiple releases added for a single surface commit.".into(), - ) - } else { - state.sync_state.release = Some(ExplicitBufferRelease { - release: release.implement_dummy(), - }); - } - } - }); - } - zwp_linux_surface_synchronization_v1::Request::Destroy => { - // disable the ESUserData - compositor.with_surface_data(&surface, |attrs| { - if let Some(ref mut data) = attrs.user_data.get_mut::() { - data.state = None; - } - }); - } - _ => (), - }, - None::, - (), - ) + }); + } + zwp_linux_surface_synchronization_v1::Request::Destroy => { + // disable the ESUserData + compositor.with_surface_data(&surface, |attrs| { + if let Some(ref mut data) = attrs.user_data.get::() { + *data.state.borrow_mut() = None; + } + }); + } + _ => (), + }); + id.deref().clone() } diff --git a/src/wayland/output/mod.rs b/src/wayland/output/mod.rs index 2340622..601feed 100644 --- a/src/wayland/output/mod.rs +++ b/src/wayland/output/mod.rs @@ -21,8 +21,7 @@ //! use smithay::wayland::output::{Output, PhysicalProperties, Mode}; //! use wayland_server::protocol::wl_output; //! -//! # let mut event_loop = wayland_server::calloop::EventLoop::<()>::new().unwrap(); -//! # let mut display = wayland_server::Display::new(event_loop.handle()); +//! # let mut display = wayland_server::Display::new(); //! // Create the Output with given name and physical properties //! let (output, _output_global) = Output::new( //! &mut display, // the display @@ -49,12 +48,15 @@ //! output.add_mode(Mode { width: 1024, height: 768, refresh: 60000 }); //! ``` -use std::sync::{Arc, Mutex}; +use std::{ + ops::Deref as _, + sync::{Arc, Mutex}, +}; use wayland_server::protocol::wl_output::{Subpixel, Transform}; use wayland_server::{ protocol::wl_output::{Mode as WMode, WlOutput}, - Display, Global, NewResource, + Display, Filter, Global, Main, }; /// An output mode @@ -191,21 +193,24 @@ impl Output { let output = Output { inner: inner.clone() }; - let global = display.create_global(3, move |new_output: NewResource<_>, _version| { - let output = new_output.implement_closure( - |_, _| {}, - Some(|output: WlOutput| { - let inner = output.as_ref().user_data::>>().unwrap(); + let global = display.create_global( + 3, + Filter::new(move |(output, _version): (Main, _), _, _| { + output.assign_destructor(Filter::new(|output: WlOutput, _, _| { + let inner = output.as_ref().user_data().get::>>().unwrap(); inner .lock() .unwrap() .instances .retain(|o| !o.as_ref().equals(&output.as_ref())); - }), - inner.clone(), - ); - inner.lock().unwrap().new_global(output); - }); + })); + output.as_ref().user_data().set_threadsafe({ + let inner = inner.clone(); + move || inner + }); + inner.lock().unwrap().new_global(output.deref().clone()); + }), + ); (output, global) } diff --git a/src/wayland/seat/keyboard.rs b/src/wayland/seat/keyboard.rs index 34fe188..67f325e 100644 --- a/src/wayland/seat/keyboard.rs +++ b/src/wayland/seat/keyboard.rs @@ -3,6 +3,7 @@ use std::{ cell::RefCell, default::Default, io::{Error as IoError, Write}, + ops::Deref as _, os::unix::io::AsRawFd, rc::Rc, }; @@ -12,7 +13,7 @@ use wayland_server::{ wl_keyboard::{KeyState as WlKeyState, KeymapFormat, Request, WlKeyboard}, wl_surface::WlSurface, }, - Client, NewResource, + Client, Filter, Main, }; use xkbcommon::xkb; pub use xkbcommon::xkb::{keysyms, Keysym}; @@ -448,32 +449,25 @@ impl KeyboardHandle { } } -pub(crate) fn implement_keyboard( - new_keyboard: NewResource, - handle: Option<&KeyboardHandle>, -) -> WlKeyboard { - let destructor = match handle { - Some(h) => { - let arc = h.arc.clone(); - Some(move |keyboard: WlKeyboard| { - arc.internal - .borrow_mut() - .known_kbds - .retain(|k| !k.as_ref().equals(&keyboard.as_ref())) - }) - } - None => None, - }; - new_keyboard.implement_closure( - |request, _keyboard| { - match request { - Request::Release => { - // Our destructors already handle it - } - _ => unreachable!(), +pub(crate) fn implement_keyboard(keyboard: Main, handle: Option<&KeyboardHandle>) -> WlKeyboard { + keyboard.quick_assign(|_keyboard, request, _data| { + match request { + Request::Release => { + // Our destructors already handle it } - }, - destructor, - (), - ) + _ => unreachable!(), + } + }); + + if let Some(h) = handle { + let arc = h.arc.clone(); + keyboard.assign_destructor(Filter::new(move |keyboard: WlKeyboard, _, _| { + arc.internal + .borrow_mut() + .known_kbds + .retain(|k| !k.as_ref().equals(&keyboard.as_ref())) + })); + } + + keyboard.deref().clone() } diff --git a/src/wayland/seat/mod.rs b/src/wayland/seat/mod.rs index 11f4b49..0eed676 100644 --- a/src/wayland/seat/mod.rs +++ b/src/wayland/seat/mod.rs @@ -17,8 +17,7 @@ //! // to set a surface as a cursor image //! define_roles!(Roles => [CursorImage, CursorImageRole]); //! -//! # let mut event_loop = wayland_server::calloop::EventLoop::<()>::new().unwrap(); -//! # let mut display = wayland_server::Display::new(event_loop.handle()); +//! # let mut display = wayland_server::Display::new(); //! # let (compositor_token, _, _) = compositor_init::(&mut display, |_, _, _| {}, None); //! // insert the seat: //! let (seat, seat_global) = Seat::new( @@ -41,7 +40,7 @@ //! These methods return handles that can be cloned and sent across thread, so you can keep one around //! in your event-handling code to forward inputs to your clients. -use std::{cell::RefCell, rc::Rc}; +use std::{cell::RefCell, ops::Deref as _, rc::Rc}; mod keyboard; mod pointer; @@ -56,11 +55,9 @@ pub use self::{ use crate::wayland::compositor::{roles::Role, CompositorToken}; -use wayland_commons::utils::UserDataMap; - use wayland_server::{ protocol::{wl_seat, wl_surface}, - Display, Global, NewResource, + Display, Filter, Global, Main, UserDataMap, }; struct Inner { @@ -142,22 +139,26 @@ impl Seat { user_data: UserDataMap::new(), }); let seat = Seat { arc: arc.clone() }; - let global = display.create_global(5, move |new_seat, _version| { - let seat = implement_seat(new_seat, arc.clone(), token); - let mut inner = arc.inner.borrow_mut(); - if seat.as_ref().version() >= 2 { - seat.name(arc.name.clone()); - } - seat.capabilities(inner.compute_caps()); - inner.known_seats.push(seat); - }); + let global = display.create_global( + 5, + Filter::new(move |(new_seat, _version), _, _| { + let seat = implement_seat(new_seat, arc.clone(), token); + let mut inner = arc.inner.borrow_mut(); + if seat.as_ref().version() >= 2 { + seat.name(arc.name.clone()); + } + seat.capabilities(inner.compute_caps()); + inner.known_seats.push(seat); + }), + ); (seat, global) } /// Attempt to retrieve a [`Seat`] from an existing resource pub fn from_resource(seat: &wl_seat::WlSeat) -> Option { seat.as_ref() - .user_data::>() + .user_data() + .get::>() .cloned() .map(|arc| Seat { arc }) } @@ -189,8 +190,7 @@ impl Seat { /// # /// # define_roles!(Roles => [CursorImage, CursorImageRole]); /// # - /// # let mut event_loop = wayland_server::calloop::EventLoop::<()>::new().unwrap(); - /// # let mut display = wayland_server::Display::new(event_loop.handle()); + /// # let mut display = wayland_server::Display::new(); /// # let (compositor_token, _, _) = compositor_init::(&mut display, |_, _, _| {}, None); /// # let (mut seat, seat_global) = Seat::new( /// # &mut display, @@ -332,7 +332,7 @@ impl ::std::cmp::PartialEq for Seat { } fn implement_seat( - new_seat: NewResource, + seat: Main, arc: Rc, token: CompositorToken, ) -> wl_seat::WlSeat @@ -340,44 +340,44 @@ where R: Role + 'static, { let dest_arc = arc.clone(); - new_seat.implement_closure( - move |request, seat| { - let arc = seat.as_ref().user_data::>().unwrap(); - let inner = arc.inner.borrow_mut(); - match request { - wl_seat::Request::GetPointer { id } => { - let pointer = self::pointer::implement_pointer(id, inner.pointer.as_ref(), token); - if let Some(ref ptr_handle) = inner.pointer { - ptr_handle.new_pointer(pointer); - } else { - // we should send a protocol error... but the protocol does not allow - // us, so this pointer will just remain inactive ¯\_(ツ)_/¯ - } + seat.quick_assign(move |seat, request, _| { + let arc = seat.as_ref().user_data().get::>().unwrap(); + let inner = arc.inner.borrow_mut(); + match request { + wl_seat::Request::GetPointer { id } => { + let pointer = self::pointer::implement_pointer(id, inner.pointer.as_ref(), token); + if let Some(ref ptr_handle) = inner.pointer { + ptr_handle.new_pointer(pointer); + } else { + // we should send a protocol error... but the protocol does not allow + // us, so this pointer will just remain inactive ¯\_(ツ)_/¯ } - wl_seat::Request::GetKeyboard { id } => { - let keyboard = self::keyboard::implement_keyboard(id, inner.keyboard.as_ref()); - if let Some(ref kbd_handle) = inner.keyboard { - kbd_handle.new_kbd(keyboard); - } else { - // same as pointer, should error but cannot - } - } - wl_seat::Request::GetTouch { id: _ } => { - // TODO - } - wl_seat::Request::Release => { - // Our destructors already handle it - } - _ => unreachable!(), } - }, - Some(move |seat: wl_seat::WlSeat| { - dest_arc - .inner - .borrow_mut() - .known_seats - .retain(|s| !s.as_ref().equals(&seat.as_ref())); - }), - arc, - ) + wl_seat::Request::GetKeyboard { id } => { + let keyboard = self::keyboard::implement_keyboard(id, inner.keyboard.as_ref()); + if let Some(ref kbd_handle) = inner.keyboard { + kbd_handle.new_kbd(keyboard); + } else { + // same as pointer, should error but cannot + } + } + wl_seat::Request::GetTouch { id: _ } => { + // TODO + } + wl_seat::Request::Release => { + // Our destructors already handle it + } + _ => unreachable!(), + } + }); + seat.assign_destructor(Filter::new(move |seat: wl_seat::WlSeat, _, _| { + dest_arc + .inner + .borrow_mut() + .known_seats + .retain(|s| !s.as_ref().equals(&seat.as_ref())); + })); + seat.as_ref().user_data().set(move || arc); + + seat.deref().clone() } diff --git a/src/wayland/seat/pointer.rs b/src/wayland/seat/pointer.rs index f86dc3a..767f753 100644 --- a/src/wayland/seat/pointer.rs +++ b/src/wayland/seat/pointer.rs @@ -1,12 +1,11 @@ -use std::cell::RefCell; -use std::rc::Rc; +use std::{cell::RefCell, ops::Deref as _, rc::Rc}; use wayland_server::{ protocol::{ wl_pointer::{self, Axis, AxisSource, ButtonState, Request, WlPointer}, wl_surface::WlSurface, }, - NewResource, + Filter, Main, }; use crate::wayland::compositor::{roles::Role, CompositorToken}; @@ -553,7 +552,7 @@ where } pub(crate) fn implement_pointer( - new_pointer: NewResource, + pointer: Main, handle: Option<&PointerHandle>, token: CompositorToken, ) -> WlPointer @@ -561,71 +560,70 @@ where R: Role + 'static, { let inner = handle.map(|h| h.inner.clone()); - let destructor = match inner.clone() { - Some(inner) => Some(move |pointer: WlPointer| { - inner - .borrow_mut() - .known_pointers - .retain(|p| !p.as_ref().equals(&pointer.as_ref())) - }), - None => None, - }; - new_pointer.implement_closure( - move |request, pointer: WlPointer| { - match request { - Request::SetCursor { - surface, - hotspot_x, - hotspot_y, - .. - } => { - if let Some(ref inner) = inner { - let mut guard = inner.borrow_mut(); - // only allow setting the cursor icon if the current pointer focus - // is of the same client - let PointerInternal { - ref mut image_callback, - ref focus, - .. - } = *guard; - if let Some((ref focus, _)) = *focus { - if focus.as_ref().same_client_as(&pointer.as_ref()) { - match surface { - Some(surface) => { - let role_data = CursorImageRole { - hotspot: (hotspot_x, hotspot_y), - }; - // we gracefully tolerate the client to provide a surface that - // already had the "CursorImage" role, as most clients will - // always reuse the same surface (and they are right to do so!) - if token.with_role_data(&surface, |data| *data = role_data).is_err() - && token.give_role_with(&surface, role_data).is_err() - { - pointer.as_ref().post_error( - wl_pointer::Error::Role as u32, - "Given wl_surface has another role.".into(), - ); - return; - } - image_callback(CursorImageStatus::Image(surface)); - } - None => { - image_callback(CursorImageStatus::Hidden); + pointer.quick_assign(move |pointer, request, _data| { + match request { + Request::SetCursor { + surface, + hotspot_x, + hotspot_y, + .. + } => { + if let Some(ref inner) = inner { + let mut guard = inner.borrow_mut(); + // only allow setting the cursor icon if the current pointer focus + // is of the same client + let PointerInternal { + ref mut image_callback, + ref focus, + .. + } = *guard; + if let Some((ref focus, _)) = *focus { + if focus.as_ref().same_client_as(&pointer.as_ref()) { + match surface { + Some(surface) => { + let role_data = CursorImageRole { + hotspot: (hotspot_x, hotspot_y), + }; + // we gracefully tolerate the client to provide a surface that + // already had the "CursorImage" role, as most clients will + // always reuse the same surface (and they are right to do so!) + if token.with_role_data(&surface, |data| *data = role_data).is_err() + && token.give_role_with(&surface, role_data).is_err() + { + pointer.as_ref().post_error( + wl_pointer::Error::Role as u32, + "Given wl_surface has another role.".into(), + ); + return; } + image_callback(CursorImageStatus::Image(surface)); + } + None => { + image_callback(CursorImageStatus::Hidden); } } } } } - Request::Release => { - // Our destructors already handle it - } - _ => unreachable!(), } - }, - destructor, - (), - ) + Request::Release => { + // Our destructors already handle it + } + _ => unreachable!(), + } + }); + + if let Some(h) = handle { + let inner = h.inner.clone(); + pointer.assign_destructor(Filter::new(move |pointer: WlPointer, _, _| { + inner + .borrow_mut() + .known_pointers + .retain(|p| !p.as_ref().equals(&pointer.as_ref())) + })) + } + + pointer.deref().clone() } /* diff --git a/src/wayland/shell/legacy/mod.rs b/src/wayland/shell/legacy/mod.rs index 575fd10..30eebf7 100644 --- a/src/wayland/shell/legacy/mod.rs +++ b/src/wayland/shell/legacy/mod.rs @@ -42,8 +42,7 @@ //! [ShellSurface, ShellSurfaceRole] //! ); //! -//! # let mut event_loop = wayland_server::calloop::EventLoop::<()>::new().unwrap(); -//! # let mut display = wayland_server::Display::new(event_loop.handle()); +//! # let mut display = wayland_server::Display::new(); //! # let (compositor_token, _, _) = smithay::wayland::compositor::compositor_init::( //! # &mut display, //! # |_, _, _| {}, @@ -71,7 +70,7 @@ use crate::wayland::compositor::{roles::Role, CompositorToken}; use wayland_server::{ protocol::{wl_output, wl_seat, wl_shell, wl_shell_surface, wl_surface}, - Display, Global, + Display, Filter, Global, }; mod wl_handlers; @@ -315,9 +314,9 @@ where })); let state2 = state.clone(); - let global = display.create_global(1, move |shell, _version| { + let global = display.create_global(1, Filter::new(move |(shell, _version), _, _data| { self::wl_handlers::implement_shell(shell, ctoken, implementation.clone(), state2.clone()); - }); + })); (state, global) } diff --git a/src/wayland/shell/legacy/wl_handlers.rs b/src/wayland/shell/legacy/wl_handlers.rs index 0392ffe..92c93a6 100644 --- a/src/wayland/shell/legacy/wl_handlers.rs +++ b/src/wayland/shell/legacy/wl_handlers.rs @@ -1,12 +1,13 @@ use std::{ cell::RefCell, + ops::Deref as _, rc::Rc, sync::{Arc, Mutex}, }; use wayland_server::{ protocol::{wl_shell, wl_shell_surface, wl_surface}, - NewResource, + Filter, Main, }; use crate::wayland::compositor::{roles::Role, CompositorToken}; @@ -14,7 +15,7 @@ use crate::wayland::compositor::{roles::Role, CompositorToken}; use super::{ShellRequest, ShellState, ShellSurface, ShellSurfaceKind, ShellSurfaceRole}; pub(crate) fn implement_shell( - shell: NewResource, + shell: Main, ctoken: CompositorToken, implementation: Rc>, state: Arc>>, @@ -22,8 +23,8 @@ pub(crate) fn implement_shell( R: Role + 'static, Impl: FnMut(ShellRequest) + 'static, { - shell.implement_closure( - move |req, shell| { + shell.quick_assign( + move |shell, req, _data| { let (id, surface) = match req { wl_shell::Request::GetShellSurface { id, surface } => (id, surface), _ => unreachable!(), @@ -51,8 +52,6 @@ pub(crate) fn implement_shell( surface: make_handle(&shell_surface, ctoken), }); }, - None::, - (), ); } @@ -65,7 +64,8 @@ where { let data = shell_surface .as_ref() - .user_data::>() + .user_data() + .get::>() .unwrap(); ShellSurface { wl_surface: data.surface.clone(), @@ -80,7 +80,7 @@ pub(crate) struct ShellSurfaceUserData { } fn implement_shell_surface( - shell_surface: NewResource, + shell_surface: Main, surface: wl_surface::WlSurface, implementation: Rc>, ctoken: CompositorToken, @@ -91,11 +91,12 @@ where Impl: FnMut(ShellRequest) + 'static, { use self::wl_shell_surface::Request; - shell_surface.implement_closure( - move |req, shell_surface| { + shell_surface.quick_assign( + move |shell_surface, req, _data| { let data = shell_surface .as_ref() - .user_data::>() + .user_data() + .get::>() .unwrap(); let mut user_impl = implementation.borrow_mut(); match req { @@ -185,13 +186,18 @@ where _ => unreachable!(), } }, - Some(|shell_surface: wl_shell_surface::WlShellSurface| { - let data = shell_surface - .as_ref() - .user_data::>() - .unwrap(); - data.state.lock().unwrap().cleanup_surfaces(); - }), - ShellSurfaceUserData { surface, state }, - ) + ); + + shell_surface.assign_destructor(Filter::new(|shell_surface: wl_shell_surface::WlShellSurface, _, _data| { + let data = shell_surface + .as_ref() + .user_data() + .get::>() + .unwrap(); + data.state.lock().unwrap().cleanup_surfaces(); + })); + + shell_surface.as_ref().user_data().set_threadsafe(|| ShellSurfaceUserData { surface, state }); + + shell_surface.deref().clone() } diff --git a/src/wayland/shell/xdg/mod.rs b/src/wayland/shell/xdg/mod.rs index ed757ad..99602b7 100644 --- a/src/wayland/shell/xdg/mod.rs +++ b/src/wayland/shell/xdg/mod.rs @@ -47,8 +47,7 @@ //! /* ... */ //! } //! -//! # let mut event_loop = wayland_server::calloop::EventLoop::<()>::new().unwrap(); -//! # let mut display = wayland_server::Display::new(event_loop.handle()); +//! # let mut display = wayland_server::Display::new(); //! # let (compositor_token, _, _) = smithay::wayland::compositor::compositor_init::( //! # &mut display, //! # |_, _, _| {}, @@ -94,14 +93,13 @@ use std::{ rc::Rc, sync::{Arc, Mutex}, }; -use wayland_commons::utils::UserDataMap; use wayland_protocols::{ unstable::xdg_shell::v6::server::{zxdg_popup_v6, zxdg_shell_v6, zxdg_surface_v6, zxdg_toplevel_v6}, xdg_shell::server::{xdg_popup, xdg_positioner, xdg_surface, xdg_toplevel, xdg_wm_base}, }; use wayland_server::{ protocol::{wl_output, wl_seat, wl_surface}, - Display, Global, + Display, Filter, Global, UserDataMap, }; // handlers for the xdg_shell protocol @@ -306,13 +304,13 @@ where let shell_data_z = shell_data.clone(); - let xdg_shell_global = display.create_global(1, move |shell, _version| { + let xdg_shell_global = display.create_global(1, Filter::new(move |(shell, _version), _, _data| { self::xdg_handlers::implement_wm_base(shell, &shell_data); - }); + })); - let zxdgv6_shell_global = display.create_global(1, move |shell, _version| { + let zxdgv6_shell_global = display.create_global(1, Filter::new(move |(shell, _version), _, _data| { self::zxdgv6_handlers::implement_shell(shell, &shell_data_z); - }); + })); (shell_state, xdg_shell_global, zxdgv6_shell_global) } @@ -418,7 +416,8 @@ where ShellClientKind::Xdg(ref shell) => { let user_data = shell .as_ref() - .user_data::>() + .user_data() + .get::>() .unwrap(); let mut guard = user_data.client_data.lock().unwrap(); if guard.pending_ping == 0 { @@ -430,7 +429,8 @@ where ShellClientKind::ZxdgV6(ref shell) => { let user_data = shell .as_ref() - .user_data::>() + .user_data() + .get::>() .unwrap(); let mut guard = user_data.client_data.lock().unwrap(); if guard.pending_ping == 0 { @@ -455,7 +455,8 @@ where ShellClientKind::Xdg(ref shell) => { let data = shell .as_ref() - .user_data::>() + .user_data() + .get::>() .unwrap(); let mut guard = data.client_data.lock().unwrap(); Ok(f(&mut guard.data)) @@ -463,7 +464,8 @@ where ShellClientKind::ZxdgV6(ref shell) => { let data = shell .as_ref() - .user_data::>() + .user_data() + .get::>() .unwrap(); let mut guard = data.client_data.lock().unwrap(); Ok(f(&mut guard.data)) @@ -526,14 +528,16 @@ where ToplevelKind::Xdg(ref s) => { let data = s .as_ref() - .user_data::>() + .user_data() + .get::>() .unwrap(); ShellClientKind::Xdg(data.wm_base.clone()) } ToplevelKind::ZxdgV6(ref s) => { let data = s .as_ref() - .user_data::>() + .user_data() + .get::>() .unwrap(); ShellClientKind::ZxdgV6(data.shell.clone()) } @@ -579,7 +583,8 @@ where ToplevelKind::Xdg(ref s) => { let data = s .as_ref() - .user_data::>() + .user_data() + .get::>() .unwrap(); data.xdg_surface.as_ref().post_error( xdg_surface::Error::NotConstructed as u32, @@ -589,7 +594,8 @@ where ToplevelKind::ZxdgV6(ref s) => { let data = s .as_ref() - .user_data::>() + .user_data() + .get::>() .unwrap(); data.xdg_surface.as_ref().post_error( zxdg_surface_v6::Error::NotConstructed as u32, @@ -682,14 +688,16 @@ where PopupKind::Xdg(ref p) => { let data = p .as_ref() - .user_data::>() + .user_data() + .get::>() .unwrap(); ShellClientKind::Xdg(data.wm_base.clone()) } PopupKind::ZxdgV6(ref p) => { let data = p .as_ref() - .user_data::>() + .user_data() + .get::>() .unwrap(); ShellClientKind::ZxdgV6(data.shell.clone()) } @@ -739,7 +747,8 @@ where PopupKind::Xdg(ref s) => { let data = s .as_ref() - .user_data::>() + .user_data() + .get::>() .unwrap(); data.xdg_surface.as_ref().post_error( xdg_surface::Error::NotConstructed as u32, @@ -749,7 +758,8 @@ where PopupKind::ZxdgV6(ref s) => { let data = s .as_ref() - .user_data::>() + .user_data() + .get::>() .unwrap(); data.xdg_surface.as_ref().post_error( zxdg_surface_v6::Error::NotConstructed as u32, diff --git a/src/wayland/shell/xdg/xdg_handlers.rs b/src/wayland/shell/xdg/xdg_handlers.rs index ea36f6e..87e85a5 100644 --- a/src/wayland/shell/xdg/xdg_handlers.rs +++ b/src/wayland/shell/xdg/xdg_handlers.rs @@ -1,10 +1,10 @@ -use std::{cell::RefCell, sync::Mutex}; +use std::{cell::RefCell, ops::Deref as _, sync::Mutex}; use crate::wayland::compositor::{roles::*, CompositorToken}; use wayland_protocols::xdg_shell::server::{ xdg_popup, xdg_positioner, xdg_surface, xdg_toplevel, xdg_wm_base, }; -use wayland_server::{protocol::wl_surface, NewResource}; +use wayland_server::{protocol::wl_surface, Filter, Main}; use crate::utils::Rectangle; @@ -15,15 +15,14 @@ use super::{ }; pub(crate) fn implement_wm_base( - shell: NewResource, + shell: Main, shell_data: &ShellData, ) -> xdg_wm_base::XdgWmBase where R: Role + 'static, { - let shell = shell.implement_closure( - wm_implementation::, - None::, + shell.quick_assign(|shell, req, _data| wm_implementation::(req, shell.deref().clone())); + shell.as_ref().user_data().set(|| ShellUserData { shell_data: shell_data.clone(), client_data: Mutex::new(make_shell_client_data()), @@ -33,7 +32,7 @@ where (&mut *user_impl)(XdgRequest::NewClient { client: make_shell_client(&shell, shell_data.compositor_token), }); - shell + shell.deref().clone() } /* @@ -59,7 +58,7 @@ fn wm_implementation(request: xdg_wm_base::Request, shell: xdg_wm_base::XdgWm where R: Role + 'static, { - let data = shell.as_ref().user_data::>().unwrap(); + let data = shell.as_ref().user_data().get::>().unwrap(); match request { xdg_wm_base::Request::Destroy => { // all is handled by destructor @@ -86,9 +85,11 @@ where ); return; } - id.implement_closure( - xdg_surface_implementation::, - Some(destroy_surface::), + id.quick_assign(|surface, req, _data| { + xdg_surface_implementation::(req, surface.deref().clone()) + }); + id.assign_destructor(Filter::new(|surface, _, _data| destroy_surface::(surface))); + id.as_ref().user_data().set(|| XdgSurfaceUserData { shell_data: data.shell_data.clone(), wl_surface: surface, @@ -121,14 +122,13 @@ where * xdg_positioner */ -fn implement_positioner( - positioner: NewResource, -) -> xdg_positioner::XdgPositioner { - positioner.implement_closure( - |request, positioner| { +fn implement_positioner(positioner: Main) -> xdg_positioner::XdgPositioner { + positioner.quick_assign( + |positioner, request, _data| { let mutex = positioner .as_ref() - .user_data::>() + .user_data() + .get::>() .unwrap(); let mut state = mutex.borrow_mut(); match request { @@ -174,9 +174,12 @@ fn implement_positioner( _ => unreachable!(), } }, - None::, + ); + positioner.as_ref().user_data().set(|| RefCell::new(PositionerState::new()), - ) + ); + + positioner.deref().clone() } /* @@ -193,7 +196,11 @@ fn destroy_surface(surface: xdg_surface::XdgSurface) where R: Role + 'static, { - let data = surface.as_ref().user_data::>().unwrap(); + let data = surface + .as_ref() + .user_data() + .get::>() + .unwrap(); if !data.wl_surface.as_ref().is_alive() { // the wl_surface is destroyed, this means the client is not // trying to change the role but it's a cleanup (possibly a @@ -219,7 +226,11 @@ fn xdg_surface_implementation(request: xdg_surface::Request, xdg_surface: xdg where R: Role + 'static, { - let data = xdg_surface.as_ref().user_data::>().unwrap(); + let data = xdg_surface + .as_ref() + .user_data() + .get::>() + .unwrap(); match request { xdg_surface::Request::Destroy => { // all is handled by our destructor @@ -237,9 +248,11 @@ where }); }) .expect("xdg_surface exists but surface has not shell_surface role?!"); - let toplevel = id.implement_closure( - toplevel_implementation::, - Some(destroy_toplevel::), + id.quick_assign( + |toplevel, req, _data| toplevel_implementation::(req, toplevel.deref().clone()), + ); + id.assign_destructor(Filter::new(|toplevel, _, _data| destroy_toplevel::(toplevel))); + id.as_ref().user_data().set(|| ShellSurfaceUserData { shell_data: data.shell_data.clone(), wl_surface: data.wl_surface.clone(), @@ -253,9 +266,9 @@ where .lock() .unwrap() .known_toplevels - .push(make_toplevel_handle(&toplevel)); + .push(make_toplevel_handle(&id)); - let handle = make_toplevel_handle(&toplevel); + let handle = make_toplevel_handle(&id); let mut user_impl = data.shell_data.user_impl.borrow_mut(); (&mut *user_impl)(XdgRequest::NewToplevel { surface: handle }); } @@ -266,11 +279,16 @@ where } => { let positioner_data = positioner .as_ref() - .user_data::>() + .user_data() + .get::>() .unwrap(); let parent_surface = parent.map(|parent| { - let parent_data = parent.as_ref().user_data::>().unwrap(); + let parent_data = parent + .as_ref() + .user_data() + .get::>() + .unwrap(); parent_data.wl_surface.clone() }); data.shell_data @@ -282,9 +300,9 @@ where }); }) .expect("xdg_surface exists but surface has not shell_surface role?!"); - let popup = id.implement_closure( - xg_popup_implementation::, - Some(destroy_popup::), + id.quick_assign(|popup, req, _data| xg_popup_implementation::(req, popup.deref().clone())); + id.assign_destructor(Filter::new(|popup, _, _data| destroy_popup::(popup))); + id.as_ref().user_data().set(|| ShellSurfaceUserData { shell_data: data.shell_data.clone(), wl_surface: data.wl_surface.clone(), @@ -298,9 +316,9 @@ where .lock() .unwrap() .known_popups - .push(make_popup_handle(&popup)); + .push(make_popup_handle(&id)); - let handle = make_popup_handle(&popup); + let handle = make_popup_handle(&id); let mut user_impl = data.shell_data.user_impl.borrow_mut(); (&mut *user_impl)(XdgRequest::NewPopup { surface: handle }); } @@ -361,7 +379,11 @@ where R: Role + 'static, F: FnOnce(&mut ToplevelState), { - let toplevel_data = toplevel.as_ref().user_data::>().unwrap(); + let toplevel_data = toplevel + .as_ref() + .user_data() + .get::>() + .unwrap(); shell_data .compositor_token .with_role_data::(&toplevel_data.wl_surface, |data| match data.pending_state { @@ -375,7 +397,11 @@ pub fn send_toplevel_configure(resource: &xdg_toplevel::XdgToplevel, configur where R: Role + 'static, { - let data = resource.as_ref().user_data::>().unwrap(); + let data = resource + .as_ref() + .user_data() + .get::>() + .unwrap(); let (width, height) = configure.size.unwrap_or((0, 0)); // convert the Vec (which is really a Vec) into Vec let states = { @@ -397,7 +423,11 @@ where } fn make_toplevel_handle(resource: &xdg_toplevel::XdgToplevel) -> super::ToplevelSurface { - let data = resource.as_ref().user_data::>().unwrap(); + let data = resource + .as_ref() + .user_data() + .get::>() + .unwrap(); super::ToplevelSurface { wl_surface: data.wl_surface.clone(), shell_surface: ToplevelKind::Xdg(resource.clone()), @@ -409,7 +439,11 @@ fn toplevel_implementation(request: xdg_toplevel::Request, toplevel: xdg_topl where R: Role + 'static, { - let data = toplevel.as_ref().user_data::>().unwrap(); + let data = toplevel + .as_ref() + .user_data() + .get::>() + .unwrap(); match request { xdg_toplevel::Request::Destroy => { // all it done by the destructor @@ -419,7 +453,8 @@ where toplevel_data.parent = parent.map(|toplevel_surface_parent| { toplevel_surface_parent .as_ref() - .user_data::>() + .user_data() + .get::>() .unwrap() .wl_surface .clone() @@ -456,7 +491,6 @@ where }); } xdg_toplevel::Request::Resize { seat, serial, edges } => { - let edges = xdg_toplevel::ResizeEdge::from_raw(edges).unwrap_or(xdg_toplevel::ResizeEdge::None); let handle = make_toplevel_handle(&toplevel); let mut user_impl = data.shell_data.user_impl.borrow_mut(); (&mut *user_impl)(XdgRequest::Resize { @@ -512,7 +546,11 @@ fn destroy_toplevel(toplevel: xdg_toplevel::XdgToplevel) where R: Role + 'static, { - let data = toplevel.as_ref().user_data::>().unwrap(); + let data = toplevel + .as_ref() + .user_data() + .get::>() + .unwrap(); if !data.wl_surface.as_ref().is_alive() { // the wl_surface is destroyed, this means the client is not // trying to change the role but it's a cleanup (possibly a @@ -543,7 +581,11 @@ pub(crate) fn send_popup_configure(resource: &xdg_popup::XdgPopup, configure: where R: Role + 'static, { - let data = resource.as_ref().user_data::>().unwrap(); + let data = resource + .as_ref() + .user_data() + .get::>() + .unwrap(); let (x, y) = configure.position; let (width, height) = configure.size; let serial = configure.serial; @@ -557,7 +599,11 @@ where } fn make_popup_handle(resource: &xdg_popup::XdgPopup) -> super::PopupSurface { - let data = resource.as_ref().user_data::>().unwrap(); + let data = resource + .as_ref() + .user_data() + .get::>() + .unwrap(); super::PopupSurface { wl_surface: data.wl_surface.clone(), shell_surface: PopupKind::Xdg(resource.clone()), @@ -569,7 +615,11 @@ fn xg_popup_implementation(request: xdg_popup::Request, popup: xdg_popup::Xdg where R: Role + 'static, { - let data = popup.as_ref().user_data::>().unwrap(); + let data = popup + .as_ref() + .user_data() + .get::>() + .unwrap(); match request { xdg_popup::Request::Destroy => { // all is handled by our destructor @@ -591,7 +641,11 @@ fn destroy_popup(popup: xdg_popup::XdgPopup) where R: Role + 'static, { - let data = popup.as_ref().user_data::>().unwrap(); + let data = popup + .as_ref() + .user_data() + .get::>() + .unwrap(); if !data.wl_surface.as_ref().is_alive() { // the wl_surface is destroyed, this means the client is not // trying to change the role but it's a cleanup (possibly a diff --git a/src/wayland/shell/xdg/zxdgv6_handlers.rs b/src/wayland/shell/xdg/zxdgv6_handlers.rs index 84499d4..15c2a94 100644 --- a/src/wayland/shell/xdg/zxdgv6_handlers.rs +++ b/src/wayland/shell/xdg/zxdgv6_handlers.rs @@ -1,4 +1,4 @@ -use std::{cell::RefCell, sync::Mutex}; +use std::{cell::RefCell, ops::Deref as _, sync::Mutex}; use crate::wayland::compositor::{roles::*, CompositorToken}; use wayland_protocols::{ @@ -7,7 +7,7 @@ use wayland_protocols::{ }, xdg_shell::server::{xdg_positioner, xdg_toplevel}, }; -use wayland_server::{protocol::wl_surface, NewResource}; +use wayland_server::{protocol::wl_surface, Filter, Main}; use crate::utils::Rectangle; @@ -18,15 +18,14 @@ use super::{ }; pub(crate) fn implement_shell( - shell: NewResource, + shell: Main, shell_data: &ShellData, ) -> zxdg_shell_v6::ZxdgShellV6 where R: Role + 'static, { - let shell = shell.implement_closure( - shell_implementation::, - None::, + shell.quick_assign(|shell, req, _data| shell_implementation::(req, shell.deref().clone())); + shell.as_ref().user_data().set(|| ShellUserData { shell_data: shell_data.clone(), client_data: Mutex::new(make_shell_client_data()), @@ -36,7 +35,7 @@ where (&mut *user_impl)(XdgRequest::NewClient { client: make_shell_client(&shell, shell_data.compositor_token), }); - shell + shell.deref().clone() } /* @@ -62,7 +61,7 @@ fn shell_implementation(request: zxdg_shell_v6::Request, shell: zxdg_shell_v6 where R: Role + 'static, { - let data = shell.as_ref().user_data::>().unwrap(); + let data = shell.as_ref().user_data().get::>().unwrap(); match request { zxdg_shell_v6::Request::Destroy => { // all is handled by destructor @@ -89,9 +88,9 @@ where ); return; } - id.implement_closure( - xdg_surface_implementation::, - Some(destroy_surface::), + id.quick_assign(|surface, req, _data| xdg_surface_implementation::(req, surface.deref().clone())); + id.assign_destructor(Filter::new(|surface, _, _data| destroy_surface::(surface))); + id.as_ref().user_data().set(|| XdgSurfaceUserData { shell_data: data.shell_data.clone(), wl_surface: surface, @@ -125,13 +124,14 @@ where */ fn implement_positioner( - positioner: NewResource, + positioner: Main, ) -> zxdg_positioner_v6::ZxdgPositionerV6 { - positioner.implement_closure( - |request, positioner| { + positioner.quick_assign( + |positioner, request, _data| { let mutex = positioner .as_ref() - .user_data::>() + .user_data() + .get::>() .unwrap(); let mut state = mutex.borrow_mut(); match request { @@ -191,9 +191,12 @@ fn implement_positioner( _ => unreachable!(), } }, - None::, + ); + positioner.as_ref().user_data().set(|| RefCell::new(PositionerState::new()), - ) + ); + + positioner.deref().clone() } /* @@ -210,7 +213,11 @@ fn destroy_surface(surface: zxdg_surface_v6::ZxdgSurfaceV6) where R: Role + 'static, { - let data = surface.as_ref().user_data::>().unwrap(); + let data = surface + .as_ref() + .user_data() + .get::>() + .unwrap(); if !data.wl_surface.as_ref().is_alive() { // the wl_surface is destroyed, this means the client is not // trying to change the role but it's a cleanup (possibly a @@ -238,7 +245,11 @@ fn xdg_surface_implementation( ) where R: Role + 'static, { - let data = xdg_surface.as_ref().user_data::>().unwrap(); + let data = xdg_surface + .as_ref() + .user_data() + .get::>() + .unwrap(); match request { zxdg_surface_v6::Request::Destroy => { // all is handled by our destructor @@ -256,9 +267,9 @@ fn xdg_surface_implementation( }); }) .expect("xdg_surface exists but surface has not shell_surface role?!"); - let toplevel = id.implement_closure( - toplevel_implementation::, - Some(destroy_toplevel::), + id.quick_assign(|toplevel, req, _data| toplevel_implementation::(req, toplevel.deref().clone())); + id.assign_destructor(Filter::new(|toplevel, _, _data| destroy_toplevel::(toplevel))); + id.as_ref().user_data().set(|| ShellSurfaceUserData { shell_data: data.shell_data.clone(), wl_surface: data.wl_surface.clone(), @@ -272,9 +283,9 @@ fn xdg_surface_implementation( .lock() .unwrap() .known_toplevels - .push(make_toplevel_handle(&toplevel)); + .push(make_toplevel_handle(&id)); - let handle = make_toplevel_handle(&toplevel); + let handle = make_toplevel_handle(&id); let mut user_impl = data.shell_data.user_impl.borrow_mut(); (&mut *user_impl)(XdgRequest::NewToplevel { surface: handle }); } @@ -285,10 +296,15 @@ fn xdg_surface_implementation( } => { let positioner_data = positioner .as_ref() - .user_data::>() + .user_data() + .get::>() .unwrap(); - let parent_data = parent.as_ref().user_data::>().unwrap(); + let parent_data = parent + .as_ref() + .user_data() + .get::>() + .unwrap(); data.shell_data .compositor_token .with_role_data::(&data.wl_surface, |data| { @@ -298,9 +314,9 @@ fn xdg_surface_implementation( }); }) .expect("xdg_surface exists but surface has not shell_surface role?!"); - let popup = id.implement_closure( - popup_implementation::, - Some(destroy_popup::), + id.quick_assign(|popup, req, _data| popup_implementation::(req, popup.deref().clone())); + id.assign_destructor(Filter::new(|popup, _, _data| destroy_popup::(popup))); + id.as_ref().user_data().set(|| ShellSurfaceUserData { shell_data: data.shell_data.clone(), wl_surface: data.wl_surface.clone(), @@ -314,9 +330,9 @@ fn xdg_surface_implementation( .lock() .unwrap() .known_popups - .push(make_popup_handle(&popup)); + .push(make_popup_handle(&id)); - let handle = make_popup_handle(&popup); + let handle = make_popup_handle(&id); let mut user_impl = data.shell_data.user_impl.borrow_mut(); (&mut *user_impl)(XdgRequest::NewPopup { surface: handle }); } @@ -377,7 +393,11 @@ where R: Role + 'static, F: FnOnce(&mut ToplevelState), { - let data = toplevel.as_ref().user_data::>().unwrap(); + let data = toplevel + .as_ref() + .user_data() + .get::>() + .unwrap(); data.shell_data .compositor_token .with_role_data::(&data.wl_surface, |data| match data.pending_state { @@ -391,7 +411,11 @@ pub fn send_toplevel_configure(resource: &zxdg_toplevel_v6::ZxdgToplevelV6, c where R: Role + 'static, { - let data = resource.as_ref().user_data::>().unwrap(); + let data = resource + .as_ref() + .user_data() + .get::>() + .unwrap(); let (width, height) = configure.size.unwrap_or((0, 0)); // convert the Vec (which is really a Vec) into Vec let states = { @@ -415,7 +439,11 @@ where fn make_toplevel_handle( resource: &zxdg_toplevel_v6::ZxdgToplevelV6, ) -> super::ToplevelSurface { - let data = resource.as_ref().user_data::>().unwrap(); + let data = resource + .as_ref() + .user_data() + .get::>() + .unwrap(); super::ToplevelSurface { wl_surface: data.wl_surface.clone(), shell_surface: ToplevelKind::ZxdgV6(resource.clone()), @@ -427,7 +455,11 @@ fn toplevel_implementation(request: zxdg_toplevel_v6::Request, toplevel: zxdg where R: Role + 'static, { - let data = toplevel.as_ref().user_data::>().unwrap(); + let data = toplevel + .as_ref() + .user_data() + .get::>() + .unwrap(); match request { zxdg_toplevel_v6::Request::Destroy => { // all it done by the destructor @@ -437,7 +469,8 @@ where toplevel_data.parent = parent.map(|toplevel_surface_parent| { let parent_data = toplevel_surface_parent .as_ref() - .user_data::>() + .user_data() + .get::>() .unwrap(); parent_data.wl_surface.clone() }) @@ -530,7 +563,11 @@ fn destroy_toplevel(toplevel: zxdg_toplevel_v6::ZxdgToplevelV6) where R: Role + 'static, { - let data = toplevel.as_ref().user_data::>().unwrap(); + let data = toplevel + .as_ref() + .user_data() + .get::>() + .unwrap(); if !data.wl_surface.as_ref().is_alive() { // the wl_surface is destroyed, this means the client is not // trying to change the role but it's a cleanup (possibly a @@ -561,7 +598,11 @@ pub(crate) fn send_popup_configure(resource: &zxdg_popup_v6::ZxdgPopupV6, con where R: Role + 'static, { - let data = resource.as_ref().user_data::>().unwrap(); + let data = resource + .as_ref() + .user_data() + .get::>() + .unwrap(); let (x, y) = configure.position; let (width, height) = configure.size; let serial = configure.serial; @@ -575,7 +616,11 @@ where } fn make_popup_handle(resource: &zxdg_popup_v6::ZxdgPopupV6) -> super::PopupSurface { - let data = resource.as_ref().user_data::>().unwrap(); + let data = resource + .as_ref() + .user_data() + .get::>() + .unwrap(); super::PopupSurface { wl_surface: data.wl_surface.clone(), shell_surface: PopupKind::ZxdgV6(resource.clone()), @@ -587,7 +632,11 @@ fn popup_implementation(request: zxdg_popup_v6::Request, popup: zxdg_popup_v6 where R: Role + 'static, { - let data = popup.as_ref().user_data::>().unwrap(); + let data = popup + .as_ref() + .user_data() + .get::>() + .unwrap(); match request { zxdg_popup_v6::Request::Destroy => { // all is handled by our destructor @@ -609,7 +658,11 @@ fn destroy_popup(popup: zxdg_popup_v6::ZxdgPopupV6) where R: Role + 'static, { - let data = popup.as_ref().user_data::>().unwrap(); + let data = popup + .as_ref() + .user_data() + .get::>() + .unwrap(); if !data.wl_surface.as_ref().is_alive() { // the wl_surface is destroyed, this means the client is not // trying to change the role but it's a cleanup (possibly a diff --git a/src/wayland/shm/mod.rs b/src/wayland/shm/mod.rs index 5114770..a6393d1 100644 --- a/src/wayland/shm/mod.rs +++ b/src/wayland/shm/mod.rs @@ -22,8 +22,7 @@ //! use smithay::wayland::shm::init_shm_global; //! use wayland_server::protocol::wl_shm::Format; //! -//! # let mut event_loop = wayland_server::calloop::EventLoop::<()>::new().unwrap(); -//! # let mut display = wayland_server::Display::new(event_loop.handle()); +//! # let mut display = wayland_server::Display::new(); //! // Insert the ShmGlobal into your event loop //! // Here, we specify that Yuyv and C8 format are supported //! // additionally to the standard Argb8888 and Xrgb8888. @@ -75,10 +74,10 @@ //! If you are already using an handler for this signal, you probably don't want to use this handler. use self::pool::{Pool, ResizeError}; -use std::{rc::Rc, sync::Arc}; +use std::{ops::Deref as _, rc::Rc, sync::Arc}; use wayland_server::{ protocol::{wl_buffer, wl_shm, wl_shm_pool}, - Display, Global, NewResource, + Display, Filter, Global, Main, }; mod pool; @@ -120,20 +119,20 @@ where log: log.new(o!("smithay_module" => "shm_handler")), }; - display.create_global::(1, move |shm_new: NewResource<_>, _version| { - let shm = shm_new.implement_closure( - { + display.create_global::( + 1, + Filter::new(move |(shm, _version): (Main, _), _, _| { + shm.quick_assign({ let mut data = data.clone(); - move |req, shm| data.receive_shm_message(req, shm) - }, - None::, - (), - ); - // send the formats - for &f in &data.formats[..] { - shm.format(f); - } - }) + move |shm, req, _| data.receive_shm_message(req, shm.deref().clone()) + }); + + // send the formats + for &f in &data.formats[..] { + shm.format(f); + } + }), + ) } /// Error that can occur when accessing an SHM buffer @@ -164,7 +163,7 @@ pub fn with_buffer_contents(buffer: &wl_buffer::WlBuffer, f: F) -> Result< where F: FnOnce(&[u8], BufferData) -> T, { - let data = match buffer.as_ref().user_data::() { + let data = match buffer.as_ref().user_data().get::() { Some(d) => d, None => return Err(BufferAccessError::NotManaged), }; @@ -207,14 +206,11 @@ impl ShmGlobalData { } }; let arc_pool = Arc::new(mmap_pool); - pool.implement_closure( - { - let mut data = self.clone(); - move |req, pool| data.receive_pool_message(req, pool) - }, - None::, - arc_pool, - ); + pool.quick_assign({ + let mut data = self.clone(); + move |pool, req, _| data.receive_pool_message(req, pool.deref().clone()) + }); + pool.as_ref().user_data().set(move || arc_pool); } } @@ -242,7 +238,7 @@ impl ShmGlobalData { fn receive_pool_message(&mut self, request: wl_shm_pool::Request, pool: wl_shm_pool::WlShmPool) { use self::wl_shm_pool::Request; - let arc_pool = pool.as_ref().user_data::>().unwrap(); + let arc_pool = pool.as_ref().user_data().get::>().unwrap(); match request { Request::CreateBuffer { @@ -270,7 +266,8 @@ impl ShmGlobalData { format, }, }; - buffer.implement_closure(|_, _| {}, None::, data); + buffer.quick_assign(|_,_,_| {}); + buffer.as_ref().user_data().set(|| data); } Request::Resize { size } => match arc_pool.resize(size) { Ok(()) => {} diff --git a/src/xwayland/xserver.rs b/src/xwayland/xserver.rs index 524cb04..555d0bb 100644 --- a/src/xwayland/xserver.rs +++ b/src/xwayland/xserver.rs @@ -25,6 +25,7 @@ * */ use std::{ + any::Any, cell::RefCell, env, ffi::CString, @@ -33,6 +34,12 @@ use std::{ net::UnixStream, }, rc::Rc, + sync::Arc, +}; + +use calloop::{ + signals::{Signal, Signals}, + LoopHandle, Source, }; use nix::{ @@ -42,13 +49,7 @@ use nix::{ Error as NixError, Result as NixResult, }; -use wayland_server::{ - calloop::{ - signals::{Signal, Signals}, - LoopHandle, Source, - }, - Client, Display, -}; +use wayland_server::{Client, Display, Filter}; use super::x11_sockets::{prepare_x11_sockets, X11Lock}; @@ -77,10 +78,11 @@ pub trait XWindowManager { impl XWayland { /// Start the XWayland server - pub fn init( + pub fn init( wm: WM, handle: LoopHandle, display: Rc>, + data: &mut T, logger: L, ) -> Result, ()> where @@ -104,7 +106,7 @@ impl XWayland { instance: None, log: log.new(o!("smithay_module" => "XWayland")), })); - launch(&inner)?; + launch(&inner, data)?; Ok(XWayland { inner }) } } @@ -136,7 +138,10 @@ struct Inner { // Launch an XWayland server // // Does nothing if there is already a launched instance -fn launch(inner: &Rc>>) -> Result<(), ()> { +fn launch( + inner: &Rc>>, + data: &mut T, +) -> Result<(), ()> { let mut guard = inner.borrow_mut(); if guard.instance.is_some() { return Ok(()); @@ -159,10 +164,12 @@ fn launch(inner: &Rc>>) -> Resul guard .wayland_display .borrow_mut() - .create_client(wl_me.into_raw_fd()) + .create_client(wl_me.into_raw_fd(), data) }; client.data_map().insert_if_missing(|| inner.clone()); - client.add_destructor(client_destroy::); + client.add_destructor(Filter::new(|e: Arc<_>, _, mut data| { + client_destroy::(&e, data.get().unwrap()) + })); // setup the SIGUSR1 handler let sigusr1_handler = (&mut *guard.source_maker)(inner.clone())?; @@ -245,7 +252,7 @@ impl Inner { if let Some(s) = instance.sigusr1_handler.take() { s.remove(); } - // All connexions and lockfiles are cleaned by their destructors + // All connections and lockfiles are cleaned by their destructors // Remove DISPLAY from the env ::std::env::remove_var("DISPLAY"); @@ -257,7 +264,7 @@ impl Inner { } } -fn client_destroy(map: &::wayland_server::UserDataMap) { +fn client_destroy(map: &::wayland_server::UserDataMap, data: &mut T) { let inner = map.get::>>>().unwrap(); // shutdown the server @@ -268,7 +275,7 @@ fn client_destroy(map: &::wayland_server::UserData // at startup there is no point if started_at.map(|t| t.elapsed().as_secs()).unwrap_or(10) > 5 { warn!(inner.borrow().log, "XWayland crashed, restarting."); - let _ = launch(&inner); + let _ = launch(&inner, data); } else { warn!( inner.borrow().log,