diff --git a/.travis.yml b/.travis.yml index 09a0917..93884a2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -53,7 +53,7 @@ env: matrix: include: # special features for lint & fmt - - rust: nightly + - rust: stable env: FEATURES="cargo-fmt" - rust: nightly env: FEATURES="cargo-clippy" @@ -81,17 +81,16 @@ script: vagga cargo-$TRAVIS_RUST_VERSION doc --no-deps ;; "cargo-fmt") - vagga cargo-$TRAVIS_RUST_VERSION fmt -- --write-mode=diff + vagga cargo-$TRAVIS_RUST_VERSION fmt --all -- --check ;; "cargo-clippy") - vagga cargo-$TRAVIS_RUST_VERSION install -f clippy && vagga cargo-$TRAVIS_RUST_VERSION clippy --all-features -- -D warnings ;; "anvil") vagga cargo-$TRAVIS_RUST_VERSION test -p anvil --all-features ;; *) - vagga cargo-$TRAVIS_RUST_VERSION test --lib --doc --tests --no-default-features --features "$FEATURES" && + vagga cargo-$TRAVIS_RUST_VERSION test --no-default-features --features "$FEATURES" && vagga cargo-$TRAVIS_RUST_VERSION doc --no-deps --no-default-features --features "$FEATURES" esac diff --git a/Cargo.toml b/Cargo.toml index cd370ca..1c0d209 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,12 +10,12 @@ repository = "https://github.com/Smithay/smithay" members = [ "anvil" ] [dependencies] -wayland-server = "0.20.5" -wayland-sys = "0.20.5" -nix = "0.10.0" +wayland-server = "0.21.1" +wayland-sys = "0.21.1" +nix = "0.11" xkbcommon = "0.2.1" tempfile = "2.1.5" -slog = { version = "2.1.1" } +slog = "2.1.1" slog-stdlog = "3.0.2" libloading = "0.4.0" wayland-client = { version = "0.20.5", optional = true } @@ -27,7 +27,7 @@ input = { version = "0.4.0", optional = true } udev = { version = "0.2.0", optional = true } dbus = { version = "0.6.1", optional = true } systemd = { version = "^0.2.0", optional = true } -wayland-protocols = { version = "0.20.5", features = ["unstable_protocols", "server"] } +wayland-protocols = { version = "0.21.1", features = ["unstable_protocols", "native_server"] } image = "0.17.0" error-chain = "0.11.0" lazy_static = "1.0.0" @@ -45,4 +45,4 @@ backend_session_udev = ["udev", "backend_session"] backend_session_logind = ["dbus", "systemd", "backend_session"] backend_udev = ["udev", "backend_drm", "backend_session_udev"] renderer_glium = ["glium"] -xwayland = [] +xwayland = [] \ No newline at end of file diff --git a/anvil/Cargo.toml b/anvil/Cargo.toml index c49841b..fec642d 100644 --- a/anvil/Cargo.toml +++ b/anvil/Cargo.toml @@ -11,7 +11,7 @@ slog-term = "2.3" slog-async = "2.2" rand = "0.3" glium = { version = "0.19.0", default-features = false } -wayland-server = "0.20" +wayland-server = "0.21" xkbcommon = "0.2.1" [dependencies.smithay] @@ -28,4 +28,3 @@ winit = [ "smithay/backend_winit" ] tty_launch = [ "smithay/backend_libinput", "smithay/backend_drm" ] udev = [ "tty_launch", "smithay/backend_udev" ] logind = [ "smithay/backend_session_logind" ] - diff --git a/anvil/src/glium_drawer.rs b/anvil/src/glium_drawer.rs index fca78ce..0520843 100644 --- a/anvil/src/glium_drawer.rs +++ b/anvil/src/glium_drawer.rs @@ -2,10 +2,11 @@ use glium; use glium::index::PrimitiveType; use glium::texture::{MipmapsOption, Texture2d, UncompressedFloatFormat}; use glium::{Frame, GlObject, Surface}; -use smithay::backend::graphics::egl::EGLGraphicsBackend; use smithay::backend::graphics::egl::error::Result as EGLResult; -use smithay::backend::graphics::egl::wayland::{BufferAccessError, EGLDisplay, EGLImages, - EGLWaylandExtensions, Format}; +use smithay::backend::graphics::egl::wayland::{ + BufferAccessError, EGLDisplay, EGLImages, EGLWaylandExtensions, Format, +}; +use smithay::backend::graphics::egl::EGLGraphicsBackend; use smithay::backend::graphics::glium::GliumGraphicsBackend; use smithay::wayland::compositor::roles::Role; use smithay::wayland::compositor::{SubsurfaceRole, TraversalAction}; @@ -199,8 +200,7 @@ impl GliumDrawer { blend: blending, ..Default::default() }, - ) - .unwrap(); + ).unwrap(); } #[inline] @@ -282,8 +282,7 @@ impl GliumDrawer { TraversalAction::SkipChildren } }, - ) - .unwrap(); + ).unwrap(); } }); } diff --git a/anvil/src/input_handler.rs b/anvil/src/input_handler.rs index 03d67c9..1d91554 100644 --- a/anvil/src/input_handler.rs +++ b/anvil/src/input_handler.rs @@ -1,16 +1,17 @@ use std::cell::RefCell; use std::process::Command; use std::rc::Rc; -use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::Arc; use slog::Logger; +use smithay::backend::input::{ + self, Event, InputBackend, InputHandler, KeyState, KeyboardKeyEvent, PointerAxisEvent, + PointerButtonEvent, PointerMotionAbsoluteEvent, PointerMotionEvent, +}; #[cfg(feature = "udev")] use smithay::backend::session::auto::AutoSession; -use smithay::backend::input::{self, Event, InputBackend, InputHandler, KeyState, KeyboardKeyEvent, - PointerAxisEvent, PointerButtonEvent, PointerMotionAbsoluteEvent, - PointerMotionEvent}; use smithay::wayland::seat::{keysyms as xkb, KeyboardHandle, Keysym, ModifiersState, PointerHandle}; use smithay::wayland_server::protocol::wl_pointer; @@ -160,7 +161,8 @@ impl InputHandler for AnvilInputHandler { // this event is never generated by winit so self.screen_size is relevant location.0 = (location.0).max(0.0).min(self.screen_size.0 as f64); location.1 = (location.1).max(0.0).min(self.screen_size.1 as f64); - let under = self.window_map + let under = self + .window_map .borrow() .get_surface_under((location.0, location.1)); self.pointer.motion( @@ -191,9 +193,7 @@ impl InputHandler for AnvilInputHandler { }; *self.pointer_location.borrow_mut() = (x, y); let serial = self.next_serial(); - let under = self.window_map - .borrow() - .get_surface_under((x as f64, y as f64)); + let under = self.window_map.borrow().get_surface_under((x as f64, y as f64)); self.pointer.motion( under.as_ref().map(|&(ref s, (x, y))| (s, x, y)), serial, @@ -212,7 +212,8 @@ impl InputHandler for AnvilInputHandler { let state = match evt.state() { input::MouseButtonState::Pressed => { // change the keyboard focus - let under = self.window_map + let under = self + .window_map .borrow_mut() .get_surface_and_bring_to_top(*self.pointer_location.borrow()); self.keyboard @@ -230,9 +231,11 @@ impl InputHandler for AnvilInputHandler { input::AxisSource::Finger => wl_pointer::AxisSource::Finger, input::AxisSource::Wheel | input::AxisSource::WheelTilt => wl_pointer::AxisSource::Wheel, }; - let horizontal_amount = evt.amount(&input::Axis::Horizontal) + let horizontal_amount = evt + .amount(&input::Axis::Horizontal) .unwrap_or_else(|| evt.amount_discrete(&input::Axis::Horizontal).unwrap() * 3.0); - let vertical_amount = evt.amount(&input::Axis::Vertical) + let vertical_amount = evt + .amount(&input::Axis::Vertical) .unwrap_or_else(|| evt.amount_discrete(&input::Axis::Vertical).unwrap() * 3.0); let horizontal_amount_discrete = evt.amount_discrete(&input::Axis::Horizontal); let vertical_amount_discrete = evt.amount_discrete(&input::Axis::Vertical); @@ -241,11 +244,7 @@ impl InputHandler for AnvilInputHandler { let mut event = self.pointer.axis(); event.source(source); if horizontal_amount != 0.0 { - event.value( - wl_pointer::Axis::HorizontalScroll, - horizontal_amount, - evt.time(), - ); + event.value(wl_pointer::Axis::HorizontalScroll, horizontal_amount, evt.time()); if let Some(discrete) = horizontal_amount_discrete { event.discrete(wl_pointer::Axis::HorizontalScroll, discrete as i32); } @@ -253,11 +252,7 @@ impl InputHandler for AnvilInputHandler { event.stop(wl_pointer::Axis::HorizontalScroll, evt.time()); } if vertical_amount != 0.0 { - event.value( - wl_pointer::Axis::VerticalScroll, - vertical_amount, - evt.time(), - ); + event.value(wl_pointer::Axis::VerticalScroll, vertical_amount, evt.time()); if let Some(discrete) = vertical_amount_discrete { event.discrete(wl_pointer::Axis::VerticalScroll, discrete as i32); } @@ -304,10 +299,11 @@ enum KeyAction { fn process_keyboard_shortcut(modifiers: &ModifiersState, keysym: Keysym) -> KeyAction { if modifiers.ctrl && modifiers.alt && keysym == xkb::KEY_BackSpace - || modifiers.logo && keysym == xkb::KEY_q { - // ctrl+alt+backspace = quit - // logo + q = quit - KeyAction::Quit + || modifiers.logo && keysym == xkb::KEY_q + { + // ctrl+alt+backspace = quit + // logo + q = quit + KeyAction::Quit } else if keysym >= xkb::KEY_XF86Switch_VT_1 && keysym <= xkb::KEY_XF86Switch_VT_12 { // VTSwicth KeyAction::VtSwitch((keysym - xkb::KEY_XF86Switch_VT_1 + 1) as i32) diff --git a/anvil/src/main.rs b/anvil/src/main.rs index de5af9a..2727f11 100644 --- a/anvil/src/main.rs +++ b/anvil/src/main.rs @@ -10,6 +10,7 @@ extern crate smithay; extern crate xkbcommon; use slog::Drain; +use smithay::wayland_server::calloop::EventLoop; use smithay::wayland_server::Display; #[macro_use] @@ -42,7 +43,8 @@ fn main() { o!(), ); - let (mut display, mut event_loop) = Display::new(); + let mut event_loop = EventLoop::<()>::new().unwrap(); + let mut display = Display::new(event_loop.handle()); let arg = ::std::env::args().nth(1); match arg.as_ref().map(|s| &s[..]) { diff --git a/anvil/src/raw_drm.rs b/anvil/src/raw_drm.rs index d90e176..d47ebf5 100644 --- a/anvil/src/raw_drm.rs +++ b/anvil/src/raw_drm.rs @@ -5,17 +5,18 @@ use std::os::unix::io::RawFd; use std::rc::Rc; use std::time::Duration; -use smithay::drm::Device as BasicDevice; -use smithay::drm::control::{Device as ControlDevice, ResourceInfo}; +use smithay::backend::drm::{drm_device_bind, DrmBackend, DrmDevice, DrmHandler}; +use smithay::backend::graphics::egl::wayland::EGLWaylandExtensions; use smithay::drm::control::connector::{Info as ConnectorInfo, State as ConnectorState}; use smithay::drm::control::crtc; use smithay::drm::control::encoder::Info as EncoderInfo; +use smithay::drm::control::{Device as ControlDevice, ResourceInfo}; use smithay::drm::result::Error as DrmError; -use smithay::backend::drm::{drm_device_bind, DrmBackend, DrmDevice, DrmHandler}; -use smithay::backend::graphics::egl::wayland::EGLWaylandExtensions; +use smithay::drm::Device as BasicDevice; use smithay::wayland::compositor::CompositorToken; use smithay::wayland::shm::init_shm_global; -use smithay::wayland_server::{Display, EventLoop}; +use smithay::wayland_server::calloop::EventLoop; +use smithay::wayland_server::Display; use glium::Surface; use slog::Logger; @@ -35,7 +36,7 @@ impl AsRawFd for Card { impl BasicDevice for Card {} impl ControlDevice for Card {} -pub fn run_raw_drm(mut display: Display, mut event_loop: EventLoop, log: Logger) -> Result<(), ()> { +pub fn run_raw_drm(mut display: Display, mut event_loop: EventLoop<()>, log: Logger) -> Result<(), ()> { /* * Initialize the drm backend */ @@ -43,10 +44,8 @@ pub fn run_raw_drm(mut display: Display, mut event_loop: EventLoop, log: Logger) let mut options = OpenOptions::new(); options.read(true); options.write(true); - let mut device = DrmDevice::new( - Card(options.clone().open("/dev/dri/card0").unwrap()), - log.clone(), - ).unwrap(); + let mut device = + DrmDevice::new(Card(options.clone().open("/dev/dri/card0").unwrap()), log.clone()).unwrap(); // Get a set of all modesetting resource handles (excluding planes): let res_handles = device.resource_handles().unwrap(); @@ -100,9 +99,9 @@ pub fn run_raw_drm(mut display: Display, mut event_loop: EventLoop, log: Logger) * Initialize the globals */ - init_shm_global(&mut display, event_loop.token(), vec![], log.clone()); + init_shm_global(&mut display, vec![], log.clone()); - let (compositor_token, _, _, window_map) = init_shell(&mut display, event_loop.token(), log.clone()); + let (compositor_token, _, _, window_map) = init_shell(&mut display, log.clone()); /* * Add a listening socket: @@ -114,7 +113,7 @@ pub fn run_raw_drm(mut display: Display, mut event_loop: EventLoop, log: Logger) * Register the DrmDevice on the EventLoop */ let _source = drm_device_bind( - &event_loop.token(), + &event_loop.handle(), device, DrmHandlerImpl { compositor_token, @@ -123,10 +122,12 @@ pub fn run_raw_drm(mut display: Display, mut event_loop: EventLoop, log: Logger) logger: log, }, ).map_err(|(err, _)| err) - .unwrap(); + .unwrap(); loop { - event_loop.dispatch(Some(16)).unwrap(); + event_loop + .dispatch(Some(::std::time::Duration::from_millis(16)), &mut ()) + .unwrap(); display.flush_clients(); window_map.borrow_mut().refresh(); @@ -148,11 +149,8 @@ impl DrmHandler for DrmHandlerImpl { _frame: u32, _duration: Duration, ) { - self.drawer.draw_windows( - &*self.window_map.borrow(), - self.compositor_token, - &self.logger, - ); + self.drawer + .draw_windows(&*self.window_map.borrow(), self.compositor_token, &self.logger); } fn error(&mut self, _device: &mut DrmDevice, error: DrmError) { diff --git a/anvil/src/shell.rs b/anvil/src/shell.rs index 51579c9..33a3686 100644 --- a/anvil/src/shell.rs +++ b/anvil/src/shell.rs @@ -5,12 +5,15 @@ use std::sync::{Arc, Mutex}; use rand; use smithay::wayland::compositor::{compositor_init, CompositorToken, SurfaceAttributes, SurfaceEvent}; -use smithay::wayland::shell::legacy::{wl_shell_init, ShellRequest, ShellState as WlShellState, - ShellSurfaceKind, ShellSurfaceRole}; -use smithay::wayland::shell::xdg::{xdg_shell_init, PopupConfigure, ShellState as XdgShellState, - ToplevelConfigure, XdgRequest, XdgSurfaceRole}; +use smithay::wayland::shell::legacy::{ + wl_shell_init, ShellRequest, ShellState as WlShellState, ShellSurfaceKind, ShellSurfaceRole, +}; +use smithay::wayland::shell::xdg::{ + xdg_shell_init, PopupConfigure, ShellState as XdgShellState, ToplevelConfigure, XdgRequest, + XdgSurfaceRole, +}; use smithay::wayland_server::protocol::{wl_buffer, wl_callback, wl_shell_surface, wl_surface}; -use smithay::wayland_server::{Display, LoopToken, Resource}; +use smithay::wayland_server::{Display, Resource}; use window_map::{Kind as SurfaceKind, WindowMap}; @@ -23,7 +26,6 @@ pub type MyCompositorToken = CompositorToken; pub fn init_shell( display: &mut Display, - looptoken: LoopToken, log: ::slog::Logger, ) -> ( CompositorToken, @@ -34,11 +36,10 @@ pub fn init_shell( // Create the compositor let (compositor_token, _, _) = compositor_init( display, - looptoken.clone(), - move |request, (surface, ctoken)| match request { + move |request, surface, ctoken| match request { SurfaceEvent::Commit => surface_commit(&surface, ctoken), SurfaceEvent::Frame { callback } => callback - .implement(|e, _| match e {}, None::) + .implement(|e, _| match e {}, None::, ()) .send(wl_callback::Event::Done { callback_data: 0 }), }, log.clone(), @@ -54,9 +55,8 @@ pub fn init_shell( let xdg_window_map = window_map.clone(); let (xdg_shell_state, _, _) = xdg_shell_init( display, - looptoken.clone(), compositor_token, - move |shell_event, ()| match shell_event { + move |shell_event| match shell_event { XdgRequest::NewToplevel { surface } => { // place the window at a random location in the [0;300]x[0;300] square use rand::distributions::{IndependentSample, Range}; @@ -87,13 +87,13 @@ pub fn init_shell( let shell_window_map = window_map.clone(); let (wl_shell_state, _) = wl_shell_init( display, - looptoken, compositor_token, - move |req: ShellRequest<_, _, ()>, ()| + move |req: ShellRequest<_, _, ()>| { if let ShellRequest::SetKind { surface, kind: ShellSurfaceKind::Toplevel, - } = req { + } = req + { // place the window at a random location in the [0;300]x[0;300] square use rand::distributions::{IndependentSample, Range}; let range = Range::new(0, 300); @@ -104,7 +104,8 @@ pub fn init_shell( shell_window_map .borrow_mut() .insert(SurfaceKind::Wl(surface), (x, y)); - }, + } + }, log.clone(), ); diff --git a/anvil/src/udev.rs b/anvil/src/udev.rs index 97e60ca..2c1e156 100644 --- a/anvil/src/udev.rs +++ b/anvil/src/udev.rs @@ -3,8 +3,8 @@ use std::collections::HashMap; use std::io::Error as IoError; use std::path::PathBuf; use std::rc::Rc; -use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::Arc; use std::time::Duration; use glium::Surface; @@ -13,33 +13,33 @@ use smithay::image::{ImageBuffer, Rgba}; use slog::Logger; -use smithay::drm::control::{Device as ControlDevice, ResourceInfo}; +use smithay::backend::drm::{DevPath, DrmBackend, DrmDevice, DrmHandler}; +use smithay::backend::graphics::egl::wayland::{EGLDisplay, EGLWaylandExtensions}; +use smithay::backend::graphics::GraphicsBackend; +use smithay::backend::input::InputBackend; +use smithay::backend::libinput::{libinput_bind, LibinputInputBackend, LibinputSessionInterface}; +use smithay::backend::session::auto::{auto_session_bind, AutoSession}; +use smithay::backend::session::{Session, SessionNotifier}; +use smithay::backend::udev::{primary_gpu, udev_backend_bind, SessionFdDrmDevice, UdevBackend, UdevHandler}; use smithay::drm::control::connector::{Info as ConnectorInfo, State as ConnectorState}; use smithay::drm::control::crtc; use smithay::drm::control::encoder::Info as EncoderInfo; +use smithay::drm::control::{Device as ControlDevice, ResourceInfo}; use smithay::drm::result::Error as DrmError; -use smithay::backend::drm::{DevPath, DrmBackend, DrmDevice, DrmHandler}; -use smithay::backend::graphics::GraphicsBackend; -use smithay::backend::graphics::egl::wayland::{EGLDisplay, EGLWaylandExtensions}; -use smithay::backend::input::InputBackend; -use smithay::backend::libinput::{libinput_bind, LibinputInputBackend, LibinputSessionInterface}; -use smithay::backend::session::{Session, SessionNotifier}; -use smithay::backend::session::auto::{auto_session_bind, AutoSession}; -use smithay::backend::udev::{primary_gpu, udev_backend_bind, SessionFdDrmDevice, UdevBackend, UdevHandler}; +use smithay::input::Libinput; use smithay::wayland::compositor::CompositorToken; use smithay::wayland::output::{Mode, Output, PhysicalProperties}; use smithay::wayland::seat::Seat; use smithay::wayland::shm::init_shm_global; -use smithay::wayland_server::{Display, EventLoop}; -use smithay::wayland_server::commons::downcast_impl; +use smithay::wayland_server::calloop::EventLoop; use smithay::wayland_server::protocol::wl_output; -use smithay::input::Libinput; +use smithay::wayland_server::Display; use glium_drawer::GliumDrawer; -use shell::{init_shell, MyWindowMap, Roles, SurfaceData}; use input_handler::AnvilInputHandler; +use shell::{init_shell, MyWindowMap, Roles, SurfaceData}; -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); @@ -51,18 +51,9 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop, log: Logger) -> /* * Initialize the compositor */ - init_shm_global( - &mut display.borrow_mut(), - event_loop.token(), - vec![], - log.clone(), - ); + init_shm_global(&mut display.borrow_mut(), vec![], log.clone()); - let (compositor_token, _, _, window_map) = init_shell( - &mut display.borrow_mut(), - event_loop.token(), - log.clone(), - ); + let (compositor_token, _, _, window_map) = init_shell(&mut display.borrow_mut(), log.clone()); /* * Initialize session @@ -83,7 +74,7 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop, log: Logger) -> let bytes = include_bytes!("../resources/cursor2.rgba"); let mut udev_backend = UdevBackend::new( - event_loop.token(), + event_loop.handle(), &context, session.clone(), UdevHandlerImpl { @@ -102,12 +93,7 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop, log: Logger) -> let udev_session_id = notifier.register(&mut udev_backend); - let (mut w_seat, _) = Seat::new( - &mut display.borrow_mut(), - event_loop.token(), - session.seat(), - log.clone(), - ); + let (mut w_seat, _) = Seat::new(&mut display.borrow_mut(), session.seat(), log.clone()); let pointer = w_seat.add_pointer(); let keyboard = w_seat @@ -116,13 +102,12 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop, log: Logger) -> let (output, _output_global) = Output::new( &mut display.borrow_mut(), - event_loop.token(), "Drm".into(), PhysicalProperties { width: 0, height: 0, subpixel: wl_output::Subpixel::Unknown, - maker: "Smithay".into(), + make: "Smithay".into(), model: "Generic DRM".into(), }, log.clone(), @@ -162,19 +147,20 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop, log: Logger) -> pointer_location, session, )); - let libinput_event_source = libinput_bind(libinput_backend, event_loop.token()) - .map_err(|(err, _)| err) + let libinput_event_source = libinput_bind(libinput_backend, event_loop.handle()) + .map_err(|(e, _)| e) .unwrap(); - let session_event_source = auto_session_bind(notifier, &event_loop.token()) - .map_err(|(err, _)| err) - .unwrap(); - let udev_event_source = udev_backend_bind(&event_loop.token(), udev_backend) - .map_err(|(err, _)| err) + let session_event_source = auto_session_bind(notifier, &event_loop.handle()) + .map_err(|(e, _)| e) .unwrap(); + let udev_event_source = udev_backend_bind(udev_backend).unwrap(); while running.load(Ordering::SeqCst) { - if event_loop.dispatch(Some(16)).is_err() { + if event_loop + .dispatch(Some(::std::time::Duration::from_millis(16)), &mut ()) + .is_err() + { running.store(false, Ordering::SeqCst); } else { display.borrow_mut().flush_clients(); @@ -187,14 +173,8 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop, log: Logger) -> notifier.unregister(libinput_session_id); libinput_event_source.remove(); + udev_event_source.remove(); - // destroy the udev backend freeing the drm devices - // - // udev_event_source.remove() returns a Box>, downcast_impl - // allows us to cast it back to its original type, storing it back into its original - // variable to simplify type inference. - udev_backend = *(downcast_impl(udev_event_source.remove()).unwrap_or_else(|_| unreachable!())); - udev_backend.close(); Ok(()) } @@ -281,10 +261,9 @@ impl UdevHandler for UdevHandlerImpl { *self.active_egl_context.borrow_mut() = device.bind_wl_display(&*self.display.borrow()).ok(); } - let backends = Rc::new(RefCell::new(self.scan_connectors( - device, - self.active_egl_context.clone(), - ))); + let backends = Rc::new(RefCell::new( + self.scan_connectors(device, self.active_egl_context.clone()), + )); self.backends.insert(device.device_id(), backends.clone()); Some(DrmHandlerImpl { @@ -341,11 +320,7 @@ impl DrmHandler for DrmHandlerImpl { .set_cursor_position(x.trunc().abs() as u32, y.trunc().abs() as u32); } - drawer.draw_windows( - &*self.window_map.borrow(), - self.compositor_token, - &self.logger, - ); + drawer.draw_windows(&*self.window_map.borrow(), self.compositor_token, &self.logger); } } diff --git a/anvil/src/window_map.rs b/anvil/src/window_map.rs index 529ecfe..962d41a 100644 --- a/anvil/src/window_map.rs +++ b/anvil/src/window_map.rs @@ -1,10 +1,10 @@ use smithay::utils::Rectangle; -use smithay::wayland::compositor::{CompositorToken, SubsurfaceRole, SurfaceAttributes, TraversalAction}; use smithay::wayland::compositor::roles::Role; -use smithay::wayland::shell::xdg::{ToplevelSurface, XdgSurfaceRole}; +use smithay::wayland::compositor::{CompositorToken, SubsurfaceRole, SurfaceAttributes, TraversalAction}; use smithay::wayland::shell::legacy::{ShellSurface, ShellSurfaceRole}; -use smithay::wayland_server::Resource; +use smithay::wayland::shell::xdg::{ToplevelSurface, XdgSurfaceRole}; use smithay::wayland_server::protocol::wl_surface; +use smithay::wayland_server::Resource; pub enum Kind { Xdg(ToplevelSurface), diff --git a/anvil/src/winit.rs b/anvil/src/winit.rs index 35ea288..83df04c 100644 --- a/anvil/src/winit.rs +++ b/anvil/src/winit.rs @@ -1,25 +1,26 @@ use std::cell::RefCell; use std::rc::Rc; -use std::sync::Arc; use std::sync::atomic::AtomicBool; +use std::sync::Arc; -use smithay::wayland::shm::init_shm_global; -use smithay::wayland::seat::Seat; -use smithay::wayland::output::{Mode, Output, PhysicalProperties}; +use smithay::backend::graphics::egl::wayland::EGLWaylandExtensions; +use smithay::backend::graphics::egl::EGLGraphicsBackend; use smithay::backend::input::InputBackend; use smithay::backend::winit; -use smithay::backend::graphics::egl::EGLGraphicsBackend; -use smithay::backend::graphics::egl::wayland::EGLWaylandExtensions; -use smithay::wayland_server::{Display, EventLoop}; +use smithay::wayland::output::{Mode, Output, PhysicalProperties}; +use smithay::wayland::seat::Seat; +use smithay::wayland::shm::init_shm_global; +use smithay::wayland_server::calloop::EventLoop; use smithay::wayland_server::protocol::wl_output; +use smithay::wayland_server::Display; use slog::Logger; use glium_drawer::GliumDrawer; -use shell::init_shell; use input_handler::AnvilInputHandler; +use shell::init_shell; -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(|_| ())?; let egl_display = Rc::new(RefCell::new( @@ -44,25 +45,25 @@ pub fn run_winit(display: &mut Display, event_loop: &mut EventLoop, log: Logger) * Initialize the globals */ - init_shm_global(display, event_loop.token(), vec![], log.clone()); + init_shm_global(display, vec![], log.clone()); - let (compositor_token, _, _, window_map) = init_shell(display, event_loop.token(), log.clone()); + let (compositor_token, _, _, window_map) = init_shell(display, log.clone()); - let (mut seat, _) = Seat::new(display, event_loop.token(), "winit".into(), log.clone()); + let (mut seat, _) = Seat::new(display, "winit".into(), log.clone()); let pointer = seat.add_pointer(); - let keyboard = seat.add_keyboard("", "fr", "oss", None, 1000, 500) + let keyboard = seat + .add_keyboard("", "fr", "oss", None, 1000, 500) .expect("Failed to initialize the keyboard"); let (output, _) = Output::new( display, - event_loop.token(), "Winit".into(), PhysicalProperties { width: 0, height: 0, subpixel: wl_output::Subpixel::Unknown, - maker: "Smithay".into(), + make: "Smithay".into(), model: "Winit".into(), }, log.clone(), @@ -100,7 +101,9 @@ pub fn run_winit(display: &mut Display, event_loop: &mut EventLoop, log: Logger) drawer.draw_windows(&*window_map.borrow(), compositor_token, &log); - event_loop.dispatch(Some(16)).unwrap(); + event_loop + .dispatch(Some(::std::time::Duration::from_millis(16)), &mut ()) + .unwrap(); display.flush_clients(); window_map.borrow_mut().refresh(); diff --git a/build.rs b/build.rs index 4a1cf1f..2ea7864 100644 --- a/build.rs +++ b/build.rs @@ -32,7 +32,7 @@ fn main() { "EGL_KHR_image_base", ], ).write_bindings(gl_generator::GlobalGenerator, &mut file) - .unwrap(); + .unwrap(); let mut file = File::create(&dest.join("gl_bindings.rs")).unwrap(); Registry::new( @@ -42,5 +42,5 @@ fn main() { Fallbacks::None, ["GL_OES_EGL_image"], ).write_bindings(gl_generator::GlobalGenerator, &mut file) - .unwrap(); + .unwrap(); } diff --git a/src/backend/drm/backend.rs b/src/backend/drm/backend.rs index 81ac918..9779bc6 100644 --- a/src/backend/drm/backend.rs +++ b/src/backend/drm/backend.rs @@ -1,15 +1,17 @@ -use super::DevPath; use super::error::*; -use backend::graphics::GraphicsBackend; -use backend::graphics::egl::{EGLContext, EGLGraphicsBackend, EGLSurface, PixelFormat, SwapBuffersError}; +use super::DevPath; use backend::graphics::egl::error::Result as EGLResult; use backend::graphics::egl::native::{Gbm, GbmSurfaceArguments}; use backend::graphics::egl::wayland::{EGLDisplay, EGLWaylandExtensions}; -use drm::Device as BasicDevice; -use drm::control::{Device, ResourceInfo}; +use backend::graphics::egl::{EGLContext, EGLGraphicsBackend, EGLSurface, PixelFormat, SwapBuffersError}; +use backend::graphics::GraphicsBackend; use drm::control::{connector, crtc, encoder, framebuffer, Mode}; -use gbm::{BufferObject, BufferObjectFlags, Device as GbmDevice, Format as GbmFormat, Surface as GbmSurface, - SurfaceBufferHandle}; +use drm::control::{Device, ResourceInfo}; +use drm::Device as BasicDevice; +use gbm::{ + BufferObject, BufferObjectFlags, Device as GbmDevice, Format as GbmFormat, Surface as GbmSurface, + SurfaceBufferHandle, +}; use image::{ImageBuffer, Rgba}; use nix::libc::c_void; use std::cell::Cell; @@ -54,19 +56,12 @@ impl DrmBackend { size: (w as u32, h as u32), format: GbmFormat::XRGB8888, flags: BufferObjectFlags::SCANOUT | BufferObjectFlags::RENDERING, - }) - .chain_err(|| ErrorKind::GbmInitFailed)?; + }).chain_err(|| ErrorKind::GbmInitFailed)?; // make it active for the first `crtc::set` // (which is needed before the first page_flip) - unsafe { - surface - .make_current() - .chain_err(|| ErrorKind::FailedToSwap)? - }; - surface - .swap_buffers() - .chain_err(|| ErrorKind::FailedToSwap)?; + unsafe { surface.make_current().chain_err(|| ErrorKind::FailedToSwap)? }; + surface.swap_buffers().chain_err(|| ErrorKind::FailedToSwap)?; // init the first screen // (must be done before calling page_flip for the first time) @@ -78,21 +73,11 @@ impl DrmBackend { // we need a framebuffer for the front buffer let fb = framebuffer::create(&*context, &*front_bo).chain_err(|| { - ErrorKind::DrmDev(format!( - "Error creating framebuffer on {:?}", - context.dev_path() - )) + ErrorKind::DrmDev(format!("Error creating framebuffer on {:?}", context.dev_path())) })?; debug!(log, "Initialize screen"); - crtc::set( - &*context, - crtc, - fb.handle(), - &connectors, - (0, 0), - Some(mode), - ).chain_err(|| { + crtc::set(&*context, crtc, fb.handle(), &connectors, (0, 0), Some(mode)).chain_err(|| { ErrorKind::DrmDev(format!( "Error setting crtc {:?} on {:?}", crtc, @@ -108,8 +93,7 @@ impl DrmBackend { 1, GbmFormat::ARGB8888, BufferObjectFlags::CURSOR | BufferObjectFlags::WRITE, - ) - .chain_err(|| ErrorKind::GbmInitFailed)?, + ).chain_err(|| ErrorKind::GbmInitFailed)?, (0, 0), )); @@ -149,7 +133,8 @@ impl DrmBackend { // check if the connector can handle the current mode if info.modes().contains(&self.mode) { // check if there is a valid encoder - let encoders = info.encoders() + let encoders = info + .encoders() .iter() .map(|encoder| { encoder::Info::load_from_device(&*self.backend.context, *encoder).chain_err(|| { @@ -158,8 +143,7 @@ impl DrmBackend { self.backend.context.dev_path() )) }) - }) - .collect::>>()?; + }).collect::>>()?; // and if any encoder supports the selected crtc let resource_handles = self.backend.context.resource_handles().chain_err(|| { @@ -171,11 +155,11 @@ impl DrmBackend { if !encoders .iter() .map(|encoder| encoder.possible_crtcs()) - .all(|crtc_list| + .all(|crtc_list| { resource_handles .filter_crtcs(crtc_list) .contains(&self.backend.crtc) - ) { + }) { bail!(ErrorKind::NoSuitableEncoder(info, self.backend.crtc)); } @@ -232,8 +216,7 @@ impl DrmBackend { "Error loading connector info on {:?}", self.backend.context.dev_path() )) - })? - .modes() + })?.modes() .contains(&mode) { bail!(ErrorKind::ModeNotSuitable(mode)); @@ -249,25 +232,19 @@ impl DrmBackend { self.backend.logger, "Reinitializing surface for new mode: {}:{}", w, h ); - let surface = self.backend + let surface = self + .backend .context .create_surface(GbmSurfaceArguments { size: (w as u32, h as u32), format: GbmFormat::XRGB8888, flags: BufferObjectFlags::SCANOUT | BufferObjectFlags::RENDERING, - }) - .chain_err(|| ErrorKind::GbmInitFailed)?; + }).chain_err(|| ErrorKind::GbmInitFailed)?; // make it active for the first `crtc::set` // (which is needed before the first page_flip) - unsafe { - surface - .make_current() - .chain_err(|| ErrorKind::FailedToSwap)? - }; - surface - .swap_buffers() - .chain_err(|| ErrorKind::FailedToSwap)?; + unsafe { surface.make_current().chain_err(|| ErrorKind::FailedToSwap)? }; + surface.swap_buffers().chain_err(|| ErrorKind::FailedToSwap)?; // Clean up next_buffer { @@ -412,11 +389,7 @@ impl GraphicsBackend for DrmBackend { fn set_cursor_position(&self, x: u32, y: u32) -> Result<()> { trace!(self.backend.logger, "Move the cursor to {},{}", x, y); - crtc::move_cursor( - &*self.backend.context, - self.backend.crtc, - (x as i32, y as i32), - ).chain_err(|| { + crtc::move_cursor(&*self.backend.context, self.backend.crtc, (x as i32, y as i32)).chain_err(|| { ErrorKind::DrmDev(format!( "Error moving cursor on {:?}", self.backend.context.dev_path() @@ -433,15 +406,15 @@ impl GraphicsBackend for DrmBackend { debug!(self.backend.logger, "Importing cursor"); // import the cursor into a buffer we can render - let mut cursor = self.backend + let mut cursor = self + .backend .context .create_buffer_object( w, h, GbmFormat::ARGB8888, BufferObjectFlags::CURSOR | BufferObjectFlags::WRITE, - ) - .chain_err(|| ErrorKind::GbmInitFailed)?; + ).chain_err(|| ErrorKind::GbmInitFailed)?; cursor .write(&**buffer) .chain_err(|| ErrorKind::GbmInitFailed)? @@ -495,7 +468,8 @@ impl EGLGraphicsBackend for DrmBackend { // would most likely result in a lot of flickering. // neither weston, wlc or wlroots bother with that as well. // so we just assume we got at least two buffers to do flipping. - let mut next_bo = self.surface + let mut next_bo = self + .surface .lock_front_buffer() .expect("Surface only has one front buffer. Not supported by smithay"); diff --git a/src/backend/drm/mod.rs b/src/backend/drm/mod.rs index 6849f5a..3a216b1 100644 --- a/src/backend/drm/mod.rs +++ b/src/backend/drm/mod.rs @@ -150,7 +150,8 @@ //! # //! # fn main() { //! # -//! # let (_display, mut event_loop) = wayland_server::Display::new(); +//! # let mut event_loop = wayland_server::calloop::EventLoop::<()>::new().unwrap(); +//! # let mut display = wayland_server::Display::new(event_loop.handle()); //! # //! # let mut options = OpenOptions::new(); //! # options.read(true); @@ -199,12 +200,12 @@ //! backend.swap_buffers().unwrap(); //! //! let (_source, _device_rc) = drm_device_bind( -//! &event_loop.token(), +//! &event_loop.handle(), //! device, //! MyDrmHandler(backend) //! ).map_err(|(err, _)| err).unwrap(); //! -//! event_loop.run().unwrap(); +//! /* And then run the event loop once all your setup is done */ //! # } //! ``` @@ -214,11 +215,11 @@ use backend::graphics::egl::native::Gbm; use backend::graphics::egl::wayland::{EGLDisplay, EGLWaylandExtensions}; #[cfg(feature = "backend_session")] use backend::session::{AsSessionObserver, SessionObserver}; -use drm::Device as BasicDevice; -use drm::control::{connector, crtc, encoder, Mode, ResourceInfo}; -use drm::control::Device as ControlDevice; use drm::control::framebuffer; +use drm::control::Device as ControlDevice; +use drm::control::{connector, crtc, encoder, Mode, ResourceInfo}; use drm::result::Error as DrmError; +use drm::Device as BasicDevice; use gbm::{BufferObject, Device as GbmDevice}; use nix; use nix::sys::stat::{self, dev_t, fstat}; @@ -229,12 +230,13 @@ use std::io::Error as IoError; use std::os::unix::io::{AsRawFd, RawFd}; use std::path::PathBuf; use std::rc::{Rc, Weak}; -use std::sync::{Arc, Once, ONCE_INIT}; use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::{Arc, Once, ONCE_INIT}; use std::time::Duration; -use wayland_server::{Display, LoopToken}; -use wayland_server::commons::Implementation; -use wayland_server::sources::{FdEvent, FdInterest, Source}; + +use wayland_server::calloop::generic::{EventedRawFd, Generic}; +use wayland_server::calloop::{LoopHandle, Ready, Source}; +use wayland_server::Display; mod backend; pub mod error; @@ -306,17 +308,19 @@ impl DrmDevice { let mut drm = DrmDevice { // Open the gbm device from the drm device and create a context based on that - context: Rc::new(EGLContext::new( - { - debug!(log, "Creating gbm device"); - let gbm = GbmDevice::new(dev).chain_err(|| ErrorKind::GbmInitFailed)?; - debug!(log, "Creating egl context from gbm device"); - gbm - }, - attributes, - Default::default(), - log.clone(), - ).map_err(Error::from)?), + context: Rc::new( + EGLContext::new( + { + debug!(log, "Creating gbm device"); + let gbm = GbmDevice::new(dev).chain_err(|| ErrorKind::GbmInitFailed)?; + debug!(log, "Creating egl context from gbm device"); + gbm + }, + attributes, + Default::default(), + log.clone(), + ).map_err(Error::from)?, + ), backends: Rc::new(RefCell::new(HashMap::new())), device_id, old_state: HashMap::new(), @@ -329,32 +333,20 @@ impl DrmDevice { // we want to mode-set, so we better be the master, if we run via a tty session if drm.set_master().is_err() { - warn!( - log, - "Unable to become drm master, assuming unpriviledged mode" - ); + warn!(log, "Unable to become drm master, assuming unpriviledged mode"); drm.priviledged = false; }; let res_handles = drm.resource_handles().chain_err(|| { - ErrorKind::DrmDev(format!( - "Error loading drm resources on {:?}", - drm.dev_path() - )) + ErrorKind::DrmDev(format!("Error loading drm resources on {:?}", drm.dev_path())) })?; for &con in res_handles.connectors() { let con_info = connector::Info::load_from_device(&drm, con).chain_err(|| { - ErrorKind::DrmDev(format!( - "Error loading connector info on {:?}", - drm.dev_path() - )) + ErrorKind::DrmDev(format!("Error loading connector info on {:?}", drm.dev_path())) })?; if let Some(enc) = con_info.current_encoder() { let enc_info = encoder::Info::load_from_device(&drm, enc).chain_err(|| { - ErrorKind::DrmDev(format!( - "Error loading encoder info on {:?}", - drm.dev_path() - )) + ErrorKind::DrmDev(format!("Error loading encoder info on {:?}", drm.dev_path())) })?; if let Some(crtc) = enc_info.current_crtc() { let info = crtc::Info::load_from_device(&drm, crtc).chain_err(|| { @@ -400,10 +392,7 @@ impl DrmDevice { // check if we have an encoder for every connector and the mode mode for connector in &connectors { let con_info = connector::Info::load_from_device(self, *connector).chain_err(|| { - ErrorKind::DrmDev(format!( - "Error loading connector info on {:?}", - self.dev_path() - )) + ErrorKind::DrmDev(format!("Error loading connector info on {:?}", self.dev_path())) })?; // check the mode @@ -417,20 +406,13 @@ impl DrmDevice { .iter() .map(|encoder| { encoder::Info::load_from_device(self, *encoder).chain_err(|| { - ErrorKind::DrmDev(format!( - "Error loading encoder info on {:?}", - self.dev_path() - )) + ErrorKind::DrmDev(format!("Error loading encoder info on {:?}", self.dev_path())) }) - }) - .collect::>>()?; + }).collect::>>()?; // and if any encoder supports the selected crtc let resource_handles = self.resource_handles().chain_err(|| { - ErrorKind::DrmDev(format!( - "Error loading drm resources on {:?}", - self.dev_path() - )) + ErrorKind::DrmDev(format!("Error loading drm resources on {:?}", self.dev_path())) })?; if !encoders .iter() @@ -512,18 +494,12 @@ impl Drop for DrmDevice { info.position(), info.mode(), ) { - error!( - self.logger, - "Failed to reset crtc ({:?}). Error: {}", handle, err - ); + error!(self.logger, "Failed to reset crtc ({:?}). Error: {}", handle, err); } } if self.priviledged { if let Err(err) = self.drop_master() { - error!( - self.logger, - "Failed to drop drm master state. Error: {}", err - ); + error!(self.logger, "Failed to drop drm master state. Error: {}", err); } } } @@ -546,84 +522,59 @@ pub trait DrmHandler { /// Bind a `DrmDevice` to an `EventLoop`, /// /// This will cause it to recieve events and feed them into an `DrmHandler` -pub fn drm_device_bind( - token: &LoopToken, +pub fn drm_device_bind( + handle: &LoopHandle, device: DrmDevice, - handler: H, -) -> ::std::result::Result<(Source, Rc>>), (IoError, (DrmDevice, H))> + mut handler: H, +) -> ::std::result::Result<(Source>, Rc>>), (IoError, DrmDevice)> where A: ControlDevice + 'static, H: DrmHandler + 'static, { let fd = device.as_raw_fd(); let device = Rc::new(RefCell::new(device)); - match token.add_fd_event_source( - fd, - FdInterest::READ, - DrmFdImpl { - device: device.clone(), - handler, - }, - ) { + + let mut source = Generic::from_raw_fd(fd); + source.set_interest(Ready::readable()); + + match handle.insert_source(source, { + let device = device.clone(); + move |_evt, _| { + let mut device = device.borrow_mut(); + process_events(&mut *device, &mut handler); + } + }) { Ok(source) => Ok((source, device)), - Err(( - ioerror, - DrmFdImpl { - device: device2, - handler, - }, - )) => { - // make the Rc unique again - ::std::mem::drop(device2); + Err(e) => { let device = Rc::try_unwrap(device).unwrap_or_else(|_| unreachable!()); - Err((ioerror, (device.into_inner(), handler))) + Err((e, device.into_inner())) } } } -struct DrmFdImpl { - device: Rc>>, - handler: H, -} - -impl Implementation<(), FdEvent> for DrmFdImpl +fn process_events(device: &mut DrmDevice, handler: &mut H) where A: ControlDevice + 'static, H: DrmHandler + 'static, { - fn receive(&mut self, event: FdEvent, (): ()) { - let mut device = self.device.borrow_mut(); - match event { - FdEvent::Ready { .. } => match crtc::receive_events(&*device) { - Ok(events) => for event in events { - if let crtc::Event::PageFlip(event) = event { - if device.active.load(Ordering::SeqCst) { - let backends = device.backends.borrow().clone(); - if let Some(backend) = backends - .get(&event.crtc) - .iter() - .flat_map(|x| x.upgrade()) - .next() - { - // we can now unlock the buffer - backend.unlock_buffer(); - trace!(device.logger, "Handling event for backend {:?}", event.crtc); - // and then call the user to render the next frame - self.handler - .ready(&mut device, event.crtc, event.frame, event.duration); - } else { - device.backends.borrow_mut().remove(&event.crtc); - } - } + match crtc::receive_events(&*device) { + Ok(events) => for event in events { + if let crtc::Event::PageFlip(event) = event { + if device.active.load(Ordering::SeqCst) { + let backends = device.backends.borrow().clone(); + if let Some(backend) = backends.get(&event.crtc).iter().flat_map(|x| x.upgrade()).next() { + // we can now unlock the buffer + backend.unlock_buffer(); + trace!(device.logger, "Handling event for backend {:?}", event.crtc); + // and then call the user to render the next frame + handler.ready(device, event.crtc, event.frame, event.duration); + } else { + device.backends.borrow_mut().remove(&event.crtc); } - }, - Err(err) => self.handler.error(&mut device, err), - }, - FdEvent::Error { error, .. } => { - warn!(device.logger, "DrmDevice errored: {}", error); - self.handler.error(&mut device, error.into()); + } } - } + }, + Err(err) => handler.error(device, err), } } @@ -671,10 +622,7 @@ impl SessionObserver for DrmDeviceObserver { info.position(), info.mode(), ) { - error!( - self.logger, - "Failed to reset crtc ({:?}). Error: {}", handle, err - ); + error!(self.logger, "Failed to reset crtc ({:?}). Error: {}", handle, err); } } } @@ -682,10 +630,7 @@ impl SessionObserver for DrmDeviceObserver { if self.priviledged { if let Some(device) = self.context.upgrade() { if let Err(err) = device.drop_master() { - error!( - self.logger, - "Failed to drop drm master state. Error: {}", err - ); + error!(self.logger, "Failed to drop drm master state. Error: {}", err); } } } @@ -707,11 +652,7 @@ impl SessionObserver for DrmDeviceObserver { if self.priviledged { if let Some(device) = self.context.upgrade() { if let Err(err) = device.set_master() { - crit!( - self.logger, - "Failed to acquire drm master again. Error: {}", - err - ); + crit!(self.logger, "Failed to acquire drm master again. Error: {}", err); } } } diff --git a/src/backend/graphics/egl/context.rs b/src/backend/graphics/egl/context.rs index d1abf19..26ef24d 100644 --- a/src/backend/graphics/egl/context.rs +++ b/src/backend/graphics/egl/context.rs @@ -1,13 +1,13 @@ //! EGL context related structs -use super::{ffi, EGLSurface, PixelFormat}; use super::error::*; use super::native; -#[cfg(feature = "backend_drm")] -use drm::Device as BasicDevice; +use super::{ffi, EGLSurface, PixelFormat}; #[cfg(feature = "backend_drm")] use drm::control::Device as ControlDevice; #[cfg(feature = "backend_drm")] +use drm::Device as BasicDevice; +#[cfg(feature = "backend_drm")] use gbm::Device as GbmDevice; use nix::libc::{c_int, c_void}; use slog; @@ -89,17 +89,15 @@ impl> EGLContext { mut attributes: GlAttributes, reqs: PixelFormatRequirements, log: ::slog::Logger, - ) -> Result< - ( - Rc, - Rc, - ffi::egl::types::EGLConfig, - Vec, - PixelFormat, - bool, - bool, - ), - > { + ) -> Result<( + Rc, + Rc, + ffi::egl::types::EGLConfig, + Vec, + PixelFormat, + bool, + bool, + )> { // If no version is given, try OpenGLES 3.0, if available, // fallback to 2.0 otherwise let version = match attributes.version { @@ -119,10 +117,7 @@ impl> EGLContext { } } Some((1, x)) => { - error!( - log, - "OpenGLES 1.* is not supported by the EGL renderer backend" - ); + error!(log, "OpenGLES 1.* is not supported by the EGL renderer backend"); bail!(ErrorKind::OpenGlVersionNotSupported((1, x))); } Some(version) => { @@ -178,11 +173,7 @@ impl> EGLContext { debug!(log, "EGL No-Display Extensions: {:?}", dp_extensions); - let display = B::get_display( - ptr, - |e: &str| dp_extensions.iter().any(|s| s == e), - log.clone(), - ); + let display = B::get_display(ptr, |e: &str| dp_extensions.iter().any(|s| s == e), log.clone()); if display == ffi::egl::NO_DISPLAY { error!(log, "EGL Display is not valid"); bail!(ErrorKind::DisplayNotSupported); @@ -215,10 +206,7 @@ impl> EGLContext { info!(log, "EGL Extensions: {:?}", extensions); if egl_version >= (1, 2) && ffi::egl::BindAPI(ffi::egl::OPENGL_ES_API) == 0 { - error!( - log, - "OpenGLES not supported by the underlying EGL implementation" - ); + error!(log, "OpenGLES not supported by the underlying EGL implementation"); bail!(ErrorKind::OpenGlesNotSupported); } @@ -339,14 +327,7 @@ impl> EGLContext { // calling `eglChooseConfig` let mut config_id = mem::uninitialized(); let mut num_configs = mem::uninitialized(); - if ffi::egl::ChooseConfig( - display, - descriptor.as_ptr(), - &mut config_id, - 1, - &mut num_configs, - ) == 0 - { + if ffi::egl::ChooseConfig(display, descriptor.as_ptr(), &mut config_id, 1, &mut num_configs) == 0 { bail!(ErrorKind::ConfigFailed); } if num_configs == 0 { @@ -356,17 +337,14 @@ impl> EGLContext { // analyzing each config macro_rules! attrib { - ($display:expr, $config:expr, $attr:expr) => ( - { - let mut value = mem::uninitialized(); - let res = ffi::egl::GetConfigAttrib($display, $config, - $attr as ffi::egl::types::EGLint, &mut value); - if res == 0 { - bail!(ErrorKind::ConfigFailed); - } - value + ($display:expr, $config:expr, $attr:expr) => {{ + let mut value = mem::uninitialized(); + let res = ffi::egl::GetConfigAttrib($display, $config, $attr as ffi::egl::types::EGLint, &mut value); + if res == 0 { + bail!(ErrorKind::ConfigFailed); } - ) + value + }}; }; let desc = PixelFormat { @@ -450,12 +428,7 @@ impl> EGLContext { info!(log, "EGL context created"); // make current and get list of gl extensions - ffi::egl::MakeCurrent( - display as *const _, - ptr::null(), - ptr::null(), - context as *const _, - ); + ffi::egl::MakeCurrent(display as *const _, ptr::null(), ptr::null(), context as *const _); // the list of gl extensions supported by the context let gl_extensions = { @@ -474,9 +447,7 @@ impl> EGLContext { config_id, surface_attributes, desc, - extensions - .iter() - .any(|s| *s == "EGL_WL_bind_wayland_display"), + extensions.iter().any(|s| *s == "EGL_WL_bind_wayland_display"), gl_extensions .iter() .any(|s| *s == "GL_OES_EGL_image" || *s == "GL_OES_EGL_image_base"), diff --git a/src/backend/graphics/egl/ffi.rs b/src/backend/graphics/egl/ffi.rs index 2dc0181..edc8e27 100644 --- a/src/backend/graphics/egl/ffi.rs +++ b/src/backend/graphics/egl/ffi.rs @@ -25,9 +25,7 @@ pub mod egl { use std::sync::{Once, ONCE_INIT}; lazy_static! { - pub static ref LIB: Library = { - Library::new("libEGL.so.1").expect("Failed to load LibEGL") - }; + pub static ref LIB: Library = { Library::new("libEGL.so.1").expect("Failed to load LibEGL") }; } pub static LOAD: Once = ONCE_INIT; @@ -101,9 +99,9 @@ pub mod egl { #[allow(non_snake_case)] pub mod BindWaylandDisplayWL { - use super::{metaloadfn, wayland_storage}; use super::FnPtr; use super::__gl_imports::raw; + use super::{metaloadfn, wayland_storage}; #[inline] #[allow(dead_code)] @@ -125,9 +123,9 @@ pub mod egl { #[allow(non_snake_case)] pub mod UnbindWaylandDisplayWL { - use super::{metaloadfn, wayland_storage}; use super::FnPtr; use super::__gl_imports::raw; + use super::{metaloadfn, wayland_storage}; #[inline] #[allow(dead_code)] @@ -149,9 +147,9 @@ pub mod egl { #[allow(non_snake_case)] pub mod QueryWaylandBufferWL { - use super::{metaloadfn, wayland_storage}; use super::FnPtr; use super::__gl_imports::raw; + use super::{metaloadfn, wayland_storage}; #[inline] #[allow(dead_code)] diff --git a/src/backend/graphics/egl/mod.rs b/src/backend/graphics/egl/mod.rs index a4256f5..270ba38 100644 --- a/src/backend/graphics/egl/mod.rs +++ b/src/backend/graphics/egl/mod.rs @@ -13,7 +13,12 @@ use std::fmt; pub mod context; pub use self::context::EGLContext; pub mod error; -#[allow(non_camel_case_types, dead_code, unused_mut, non_upper_case_globals)] +#[allow( + non_camel_case_types, + dead_code, + unused_mut, + non_upper_case_globals +)] pub mod ffi; pub mod native; pub mod surface; diff --git a/src/backend/graphics/egl/native.rs b/src/backend/graphics/egl/native.rs index 029713c..983a8f4 100644 --- a/src/backend/graphics/egl/native.rs +++ b/src/backend/graphics/egl/native.rs @@ -15,9 +15,9 @@ use std::ptr; #[cfg(feature = "backend_winit")] use wayland_client::egl as wegl; #[cfg(feature = "backend_winit")] -use winit::Window as WinitWindow; -#[cfg(feature = "backend_winit")] use winit::os::unix::WindowExt; +#[cfg(feature = "backend_winit")] +use winit::Window as WinitWindow; /// Trait for typed backend variants (X11/Wayland/GBM) pub trait Backend { @@ -53,26 +53,12 @@ impl Backend for Wayland { F: Fn(&str) -> bool, { if has_dp_extension("EGL_KHR_platform_wayland") && ffi::egl::GetPlatformDisplay::is_loaded() { - trace!( - log, - "EGL Display Initialization via EGL_KHR_platform_wayland" - ); - ffi::egl::GetPlatformDisplay( - ffi::egl::PLATFORM_WAYLAND_KHR, - display as *mut _, - ptr::null(), - ) + trace!(log, "EGL Display Initialization via EGL_KHR_platform_wayland"); + ffi::egl::GetPlatformDisplay(ffi::egl::PLATFORM_WAYLAND_KHR, display as *mut _, ptr::null()) } else if has_dp_extension("EGL_EXT_platform_wayland") && ffi::egl::GetPlatformDisplayEXT::is_loaded() { - trace!( - log, - "EGL Display Initialization via EGL_EXT_platform_wayland" - ); - ffi::egl::GetPlatformDisplayEXT( - ffi::egl::PLATFORM_WAYLAND_EXT, - display as *mut _, - ptr::null(), - ) + trace!(log, "EGL Display Initialization via EGL_EXT_platform_wayland"); + ffi::egl::GetPlatformDisplayEXT(ffi::egl::PLATFORM_WAYLAND_EXT, display as *mut _, ptr::null()) } else { trace!(log, "Default EGL Display Initialization via GetDisplay"); ffi::egl::GetDisplay(display as *mut _) diff --git a/src/backend/graphics/egl/surface.rs b/src/backend/graphics/egl/surface.rs index f754e20..b9bc87d 100644 --- a/src/backend/graphics/egl/surface.rs +++ b/src/backend/graphics/egl/surface.rs @@ -1,9 +1,9 @@ //! EGL surface related structs -use super::{EGLContext, SwapBuffersError}; use super::error::*; use super::ffi; use super::native; +use super::{EGLContext, SwapBuffersError}; use std::ops::{Deref, DerefMut}; use std::rc::{Rc, Weak}; diff --git a/src/backend/graphics/egl/wayland.rs b/src/backend/graphics/egl/wayland.rs index 845d0fa..adf4c4e 100644 --- a/src/backend/graphics/egl/wayland.rs +++ b/src/backend/graphics/egl/wayland.rs @@ -10,14 +10,14 @@ //! You may then use the resulting `EGLDisplay` to recieve `EGLImages` of an egl-based `WlBuffer` //! for rendering. -use backend::graphics::egl::{ffi, native, EGLContext, EglExtensionNotSupportedError}; use backend::graphics::egl::error::*; use backend::graphics::egl::ffi::egl::types::EGLImage; +use backend::graphics::egl::{ffi, native, EGLContext, EglExtensionNotSupportedError}; use nix::libc::c_uint; use std::fmt; use std::rc::{Rc, Weak}; -use wayland_server::{Display, Resource}; use wayland_server::protocol::wl_buffer::{self, WlBuffer}; +use wayland_server::{Display, Resource}; use wayland_sys::server::wl_display; /// Error that can occur when accessing an EGL buffer @@ -110,12 +110,9 @@ impl fmt::Display for TextureCreationError { match *self { TextureCreationError::ContextLost => write!(formatter, "{}", self.description()), TextureCreationError::PlaneIndexOutOfBounds => write!(formatter, "{}", self.description()), - TextureCreationError::TextureBindingFailed(code) => write!( - formatter, - "{}. Gl error code: {:?}", - self.description(), - code - ), + TextureCreationError::TextureBindingFailed(code) => { + write!(formatter, "{}. Gl error code: {:?}", self.description(), code) + } } } } @@ -203,7 +200,8 @@ impl EGLImages { ffi::gl::BindTexture(ffi::gl::TEXTURE_2D, tex_id); ffi::gl::EGLImageTargetTexture2DOES( ffi::gl::TEXTURE_2D, - *self.images + *self + .images .get(plane) .ok_or(TextureCreationError::PlaneIndexOutOfBounds)?, ); diff --git a/src/backend/graphics/glium.rs b/src/backend/graphics/glium.rs index efd1cf6..3a44bbd 100644 --- a/src/backend/graphics/glium.rs +++ b/src/backend/graphics/glium.rs @@ -1,12 +1,12 @@ //! Glium compatibility module -use backend::graphics::egl::{EGLGraphicsBackend, SwapBuffersError}; use backend::graphics::egl::error::Result as EGLResult; use backend::graphics::egl::wayland::{EGLDisplay, EGLWaylandExtensions}; -use glium::Frame; -use glium::SwapBuffersError as GliumSwapBuffersError; +use backend::graphics::egl::{EGLGraphicsBackend, SwapBuffersError}; use glium::backend::{Backend, Context, Facade}; use glium::debug::DebugCallbackBehavior; +use glium::Frame; +use glium::SwapBuffersError as GliumSwapBuffersError; use std::cell::{Ref, RefCell, RefMut}; use std::os::raw::c_void; use std::rc::Rc; @@ -51,10 +51,7 @@ impl GliumGraphicsBackend { /// Note that destroying a `Frame` is immediate, even if vsync is enabled. #[inline] pub fn draw(&self) -> Frame { - Frame::new( - self.context.clone(), - self.backend.get_framebuffer_dimensions(), - ) + Frame::new(self.context.clone(), self.backend.get_framebuffer_dimensions()) } /// Borrow the underlying backend. diff --git a/src/backend/graphics/mod.rs b/src/backend/graphics/mod.rs index 6da8e5b..ecffe07 100644 --- a/src/backend/graphics/mod.rs +++ b/src/backend/graphics/mod.rs @@ -36,7 +36,7 @@ pub trait GraphicsBackend { ) -> Result<(), Self::Error>; } -pub mod software; pub mod egl; #[cfg(feature = "renderer_glium")] pub mod glium; +pub mod software; diff --git a/src/backend/libinput.rs b/src/backend/libinput.rs index c6d311d..f29a344 100644 --- a/src/backend/libinput.rs +++ b/src/backend/libinput.rs @@ -6,14 +6,17 @@ use backend::input::Axis; use backend::session::{AsErrno, Session, SessionObserver}; use input as libinput; use input::event; + +use std::cell::RefCell; use std::collections::hash_map::{DefaultHasher, Entry, HashMap}; use std::hash::{Hash, Hasher}; use std::io::Error as IoError; use std::os::unix::io::RawFd; use std::path::Path; -use wayland_server::LoopToken; -use wayland_server::commons::Implementation; -use wayland_server::sources::{FdEvent, FdInterest, Source}; +use std::rc::Rc; + +use wayland_server::calloop::generic::{EventedRawFd, Generic}; +use wayland_server::calloop::{LoopHandle, Ready, Source}; // No idea if this is the same across unix platforms // Lets make this linux exclusive for now, once someone tries to build it for @@ -355,15 +358,18 @@ impl backend::InputBackend for LibinputInputBackend { // update capabilities, so they appear correctly on `on_seat_changed` and `on_seat_destroyed`. if let Some(seat) = self.seats.get_mut(&device_seat) { let caps = seat.capabilities_mut(); - caps.pointer = self.devices + caps.pointer = self + .devices .iter() .filter(|x| x.seat() == device_seat) .any(|x| x.has_capability(libinput::DeviceCapability::Pointer)); - caps.keyboard = self.devices + caps.keyboard = self + .devices .iter() .filter(|x| x.seat() == device_seat) .any(|x| x.has_capability(libinput::DeviceCapability::Keyboard)); - caps.touch = self.devices + caps.touch = self + .devices .iter() .filter(|x| x.seat() == device_seat) .any(|x| x.has_capability(libinput::DeviceCapability::Touch)); @@ -411,11 +417,7 @@ impl backend::InputBackend for LibinputInputBackend { handler.on_touch_down(seat, down_event) } TouchEvent::Motion(motion_event) => { - trace!( - self.logger, - "Calling on_touch_motion with {:?}", - motion_event - ); + trace!(self.logger, "Calling on_touch_motion with {:?}", motion_event); handler.on_touch_motion(seat, motion_event) } TouchEvent::Up(up_event) => { @@ -423,11 +425,7 @@ impl backend::InputBackend for LibinputInputBackend { handler.on_touch_up(seat, up_event) } TouchEvent::Cancel(cancel_event) => { - trace!( - self.logger, - "Calling on_touch_cancel with {:?}", - cancel_event - ); + trace!(self.logger, "Calling on_touch_cancel with {:?}", cancel_event); handler.on_touch_cancel(seat, cancel_event) } TouchEvent::Frame(frame_event) => { @@ -463,11 +461,7 @@ impl backend::InputBackend for LibinputInputBackend { if let Some(ref seat) = self.seats.get(&device_seat) { match pointer_event { PointerEvent::Motion(motion_event) => { - trace!( - self.logger, - "Calling on_pointer_move with {:?}", - motion_event - ); + trace!(self.logger, "Calling on_pointer_move with {:?}", motion_event); handler.on_pointer_move(seat, motion_event); } PointerEvent::MotionAbsolute(motion_abs_event) => { @@ -483,11 +477,7 @@ impl backend::InputBackend for LibinputInputBackend { handler.on_pointer_axis(seat, axis_event); } PointerEvent::Button(button_event) => { - trace!( - self.logger, - "Calling on_pointer_button with {:?}", - button_event - ); + trace!(self.logger, "Calling on_pointer_button with {:?}", button_event); handler.on_pointer_button(seat, button_event); } } @@ -600,26 +590,25 @@ impl libinput::LibinputInterface for LibinputSessionInterface { /// /// Automatically feeds the backend with incoming events without any manual calls to /// `dispatch_new_events`. Should be used to achieve the smallest possible latency. -pub fn libinput_bind( +pub fn libinput_bind( backend: LibinputInputBackend, - token: LoopToken, -) -> ::std::result::Result, (IoError, LibinputInputBackend)> { - let fd = unsafe { backend.context.fd() }; - token.add_fd_event_source(fd, FdInterest::READ, backend) -} - -impl Implementation<(), FdEvent> for LibinputInputBackend { - fn receive(&mut self, event: FdEvent, (): ()) { - match event { - FdEvent::Ready { .. } => { - use backend::input::InputBackend; - if let Err(error) = self.dispatch_new_events() { - warn!(self.logger, "Libinput errored: {}", error); - } + handle: LoopHandle, +) -> ::std::result::Result>, (IoError, LibinputInputBackend)> { + let mut source = Generic::from_raw_fd(unsafe { backend.context.fd() }); + source.set_interest(Ready::readable()); + let backend = Rc::new(RefCell::new(backend)); + let fail_backend = backend.clone(); + handle + .insert_source(source, move |_, _| { + use backend::input::InputBackend; + if let Err(error) = backend.borrow_mut().dispatch_new_events() { + warn!(backend.borrow().logger, "Libinput errored: {}", error); } - FdEvent::Error { error, .. } => { - warn!(self.logger, "Libinput fd errored: {}", error); - } - } - } + }).map_err(move |e| { + // the backend in the closure should already have been dropped + let backend = Rc::try_unwrap(fail_backend) + .unwrap_or_else(|_| unreachable!()) + .into_inner(); + (e, backend) + }) } diff --git a/src/backend/mod.rs b/src/backend/mod.rs index f73914a..328f605 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -14,11 +14,9 @@ //! - winit //! - libinput -pub mod input; pub mod graphics; +pub mod input; -#[cfg(feature = "backend_winit")] -pub mod winit; #[cfg(feature = "backend_drm")] pub mod drm; #[cfg(feature = "backend_libinput")] @@ -27,3 +25,5 @@ pub mod libinput; pub mod session; #[cfg(feature = "backend_udev")] pub mod udev; +#[cfg(feature = "backend_winit")] +pub mod winit; diff --git a/src/backend/session/auto.rs b/src/backend/session/auto.rs index b1440e8..652d11b 100644 --- a/src/backend/session/auto.rs +++ b/src/backend/session/auto.rs @@ -1,4 +1,3 @@ -//! //! Implementation of the `Session` trait through various implementations //! automatically choosing the best available interface. //! @@ -29,19 +28,18 @@ //! automatically by the `UdevBackend`, if not done manually). //! ``` -use super::{AsErrno, AsSessionObserver, Session, SessionNotifier, SessionObserver}; -use super::direct::{self, direct_session_bind, DirectSession, DirectSessionNotifier}; +use super::direct::{self, direct_session_bind, BoundDirectSession, DirectSession, DirectSessionNotifier}; #[cfg(feature = "backend_session_logind")] use super::logind::{self, logind_session_bind, BoundLogindSession, LogindSession, LogindSessionNotifier}; +use super::{AsErrno, AsSessionObserver, Session, SessionNotifier, SessionObserver}; use nix::fcntl::OFlag; use std::cell::RefCell; use std::io::Error as IoError; use std::os::unix::io::RawFd; use std::path::Path; use std::rc::Rc; -use wayland_server::LoopToken; -use wayland_server::commons::downcast_impl; -use wayland_server::sources::{SignalEvent, Source}; + +use wayland_server::calloop::LoopHandle; /// `Session` using the best available inteface #[derive(Clone)] @@ -62,7 +60,7 @@ pub enum AutoSessionNotifier { Direct(DirectSessionNotifier), } -/// Bound session that is driven by the `wayland_server::EventLoop`. +/// Bound session that is driven by the `calloop::EventLoop`. /// /// See `auto_session_bind` for details. /// @@ -72,7 +70,7 @@ pub enum BoundAutoSession { #[cfg(feature = "backend_session_logind")] Logind(BoundLogindSession), /// Bound direct / tty session - Direct(Source), + Direct(BoundDirectSession), } /// Id's used by the `AutoSessionNotifier` internally. @@ -111,10 +109,7 @@ impl AutoSession { )), Err(err) => { warn!(logger, "Failed to create direct session: {}", err); - error!( - logger, - "Could not create any session, possibilities exhausted" - ); + error!(logger, "Could not create any session, possibilities exhausted"); None } } @@ -138,10 +133,7 @@ impl AutoSession { )), Err(err) => { warn!(logger, "Failed to create direct session: {}", err); - error!( - logger, - "Could not create any session, possibilities exhausted" - ); + error!(logger, "Could not create any session, possibilities exhausted"); None } } @@ -153,16 +145,18 @@ impl AutoSession { /// Allows the `AutoSessionNotifier` to listen for incoming signals signalling the session state. /// If you don't use this function `AutoSessionNotifier` will not correctly tell you the /// session state and call it's `SessionObservers`. -pub fn auto_session_bind( +pub fn auto_session_bind( notifier: AutoSessionNotifier, - token: &LoopToken, + handle: &LoopHandle, ) -> ::std::result::Result { Ok(match notifier { #[cfg(feature = "backend_session_logind")] - AutoSessionNotifier::Logind(logind) => BoundAutoSession::Logind(logind_session_bind(logind, token) - .map_err(|(error, notifier)| (error, AutoSessionNotifier::Logind(notifier)))?), - AutoSessionNotifier::Direct(direct) => BoundAutoSession::Direct(direct_session_bind(direct, token) - .map_err(|(error, notifier)| (error, AutoSessionNotifier::Direct(notifier)))?), + AutoSessionNotifier::Logind(logind) => BoundAutoSession::Logind( + logind_session_bind(logind, handle).map_err(|(e, n)| (e, AutoSessionNotifier::Logind(n)))?, + ), + AutoSessionNotifier::Direct(direct) => BoundAutoSession::Direct( + direct_session_bind(direct, handle).map_err(|(e, n)| (e, AutoSessionNotifier::Direct(n)))?, + ), }) } @@ -225,7 +219,9 @@ impl SessionNotifier for AutoSessionNotifier { } } } + fn unregister(&mut self, signal: Self::Id) { + #[allow(unreachable_patterns)] match (self, signal) { #[cfg(feature = "backend_session_logind")] (&mut AutoSessionNotifier::Logind(ref mut logind), AutoId(AutoIdInternal::Logind(signal))) => { @@ -234,6 +230,7 @@ impl SessionNotifier for AutoSessionNotifier { (&mut AutoSessionNotifier::Direct(ref mut direct), AutoId(AutoIdInternal::Direct(signal))) => { direct.unregister(signal) } + // this pattern is needed when the logind backend is activated _ => unreachable!(), } } @@ -260,9 +257,7 @@ impl BoundAutoSession { match self { #[cfg(feature = "backend_session_logind")] BoundAutoSession::Logind(logind) => AutoSessionNotifier::Logind(logind.unbind()), - BoundAutoSession::Direct(source) => { - AutoSessionNotifier::Direct(*downcast_impl(source.remove()).unwrap_or_else(|_| unreachable!())) - } + BoundAutoSession::Direct(direct) => AutoSessionNotifier::Direct(direct.unbind()), } } } diff --git a/src/backend/session/dbus/logind.rs b/src/backend/session/dbus/logind.rs index 959c373..625802c 100644 --- a/src/backend/session/dbus/logind.rs +++ b/src/backend/session/dbus/logind.rs @@ -31,8 +31,10 @@ //! ``` use backend::session::{AsErrno, AsSessionObserver, Session, SessionNotifier, SessionObserver}; -use dbus::{BusName, BusType, Connection, ConnectionItem, ConnectionItems, Interface, Member, Message, - MessageItem, OwnedFd, Path as DbusPath, Watch, WatchEvent}; +use dbus::{ + BusName, BusType, Connection, ConnectionItem, ConnectionItems, Interface, Member, Message, MessageItem, + OwnedFd, Path as DbusPath, Watch, WatchEvent, +}; use nix::fcntl::OFlag; use nix::sys::stat::{fstat, major, minor, stat}; use std::cell::RefCell; @@ -42,9 +44,9 @@ use std::path::Path; use std::rc::{Rc, Weak}; use std::sync::atomic::{AtomicBool, Ordering}; use systemd::login; -use wayland_server::LoopToken; -use wayland_server::commons::Implementation; -use wayland_server::sources::{FdEvent, FdInterest, Source}; + +use wayland_server::calloop::generic::{Event, EventedRawFd, Generic}; +use wayland_server::calloop::{LoopHandle, Ready, Source}; struct LogindSessionImpl { conn: RefCell, @@ -93,7 +95,7 @@ impl LogindSession { "GetSession", Some(vec![session_id.clone().into()]), )?.get1::>() - .chain_err(|| ErrorKind::UnexpectedMethodReturn)?; + .chain_err(|| ErrorKind::UnexpectedMethodReturn)?; // Match all signals that we want to receive and handle let match1 = String::from( @@ -212,15 +214,14 @@ impl LogindSessionImpl { message.append_items(&arguments) }; - let mut message = conn.send_with_reply_and_block(message, 1000) - .chain_err(|| { - ErrorKind::FailedToSendDbusCall( - destination.clone(), - path.clone(), - interface.clone(), - method.clone(), - ) - })?; + let mut message = conn.send_with_reply_and_block(message, 1000).chain_err(|| { + ErrorKind::FailedToSendDbusCall( + destination.clone(), + path.clone(), + interface.clone(), + method.clone(), + ) + })?; match message.as_result() { Ok(_) => Ok(message), @@ -290,8 +291,7 @@ impl LogindSessionImpl { let (major, minor, fd) = message.get3::(); let major = major.chain_err(|| ErrorKind::UnexpectedMethodReturn)?; let minor = minor.chain_err(|| ErrorKind::UnexpectedMethodReturn)?; - let fd = fd.chain_err(|| ErrorKind::UnexpectedMethodReturn)? - .into_fd(); + let fd = fd.chain_err(|| ErrorKind::UnexpectedMethodReturn)?.into_fd(); debug!(self.logger, "Reactivating device ({},{})", major, minor); for signal in &mut *self.signals.borrow_mut() { if let &mut Some(ref mut signal) = signal { @@ -336,8 +336,7 @@ impl Session for LogindSession { (minor(stat.st_rdev) as u32).into(), ]), )?.get2::(); - let fd = fd.chain_err(|| ErrorKind::UnexpectedMethodReturn)? - .into_fd(); + let fd = fd.chain_err(|| ErrorKind::UnexpectedMethodReturn)?.into_fd(); Ok(fd) } else { bail!(ErrorKind::SessionLost) @@ -429,7 +428,7 @@ impl SessionNotifier for LogindSessionNotifier { pub struct BoundLogindSession { notifier: LogindSessionNotifier, _watches: Vec, - sources: Vec>, + sources: Vec>>, } /// Bind a `LogindSessionNotifier` to an `EventLoop`. @@ -437,9 +436,9 @@ pub struct BoundLogindSession { /// Allows the `LogindSessionNotifier` to listen for incoming signals signalling the session state. /// If you don't use this function `LogindSessionNotifier` will not correctly tell you the logind /// session state and call it's `SessionObservers`. -pub fn logind_session_bind( +pub fn logind_session_bind( notifier: LogindSessionNotifier, - token: &LoopToken, + handle: &LoopHandle, ) -> ::std::result::Result { let watches = notifier.internal.conn.borrow().watch_fds(); @@ -448,13 +447,14 @@ pub fn logind_session_bind( .clone() .into_iter() .map(|watch| { - let mut interest = FdInterest::empty(); - interest.set(FdInterest::READ, watch.readable()); - interest.set(FdInterest::WRITE, watch.writable()); - token.add_fd_event_source(watch.fd(), interest, notifier.clone()) - }) - .collect::<::std::result::Result>, (IoError, _)>>() - .map_err(|(err, _)| { + let mut source = Generic::from_raw_fd(watch.fd()); + source.set_interest(Ready::readable() | Ready::writable()); + handle.insert_source(source, { + let mut notifier = notifier.clone(); + move |evt, _| notifier.event(evt) + }) + }).collect::<::std::result::Result>>, IoError>>() + .map_err(|err| { ( err, LogindSessionNotifier { @@ -495,39 +495,25 @@ impl Drop for LogindSessionNotifier { } } -impl Implementation<(), FdEvent> for LogindSessionNotifier { - fn receive(&mut self, event: FdEvent, (): ()) { - match event { - FdEvent::Ready { fd, mask } => { - let conn = self.internal.conn.borrow(); - let items = conn.watch_handle( - fd, - match mask { - x if x.contains(FdInterest::READ) && x.contains(FdInterest::WRITE) => { - WatchEvent::Readable as u32 | WatchEvent::Writable as u32 - } - x if x.contains(FdInterest::READ) => WatchEvent::Readable as u32, - x if x.contains(FdInterest::WRITE) => WatchEvent::Writable as u32, - _ => return, - }, - ); - if let Err(err) = self.internal.handle_signals(items) { - error!(self.internal.logger, "Error handling dbus signals: {}", err); - } - } - FdEvent::Error { fd, error } => { - warn!( - self.internal.logger, - "Error on dbus connection: {:?}", error - ); - // handle the remaining messages, they might contain the SessionRemoved event - // in case the server did close the connection. - let conn = self.internal.conn.borrow(); - let items = conn.watch_handle(fd, WatchEvent::Error as u32); - if let Err(err) = self.internal.handle_signals(items) { - error!(self.internal.logger, "Error handling dbus signals: {}", err); - } - } +impl LogindSessionNotifier { + 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() { + WatchEvent::Readable as u32 | WatchEvent::Writable as u32 + } else if readiness.is_readable() { + WatchEvent::Readable as u32 + } else if readiness.is_writable() { + WatchEvent::Writable as u32 + } else { + return; + }, + ); + if let Err(err) = self.internal.handle_signals(items) { + error!(self.internal.logger, "Error handling dbus signals: {}", err); } } } diff --git a/src/backend/session/direct.rs b/src/backend/session/direct.rs index 87dd653..c987e13 100644 --- a/src/backend/session/direct.rs +++ b/src/backend/session/direct.rs @@ -46,42 +46,43 @@ //! automatically by the `UdevBackend`, if not done manually). use super::{AsErrno, AsSessionObserver, Session, SessionNotifier, SessionObserver}; -use nix::{Error as NixError, Result as NixResult}; use nix::fcntl::{self, open, OFlag}; use nix::libc::c_int; use nix::sys::signal::{self, Signal}; use nix::sys::stat::{dev_t, fstat, major, minor, Mode}; use nix::unistd::{close, dup}; +use nix::{Error as NixError, Result as NixResult}; +use std::cell::RefCell; use std::io::Error as IoError; use std::os::unix::io::RawFd; use std::path::Path; -use std::sync::Arc; +use std::rc::Rc; use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::Arc; #[cfg(feature = "backend_session_udev")] use udev::Context; -use wayland_server::LoopToken; -use wayland_server::commons::Implementation; -use wayland_server::sources::{SignalEvent, Source}; +use wayland_server::calloop::signals::Signals; +use wayland_server::calloop::{LoopHandle, Source}; #[allow(dead_code)] mod tty { - ioctl!(bad read kd_get_mode with 0x4B3B; i16); - ioctl!(bad write_int kd_set_mode with 0x4B3A); + ioctl_read_bad!(kd_get_mode, 0x4B3B, i16); + ioctl_write_int_bad!(kd_set_mode, 0x4B3A); pub const KD_TEXT: i16 = 0x00; pub const KD_GRAPHICS: i16 = 0x00; - ioctl!(bad read kd_get_kb_mode with 0x4B44; i32); - ioctl!(bad write_int kd_set_kb_mode with 0x4B45); + ioctl_read_bad!(kd_get_kb_mode, 0x4B44, i32); + ioctl_write_int_bad!(kd_set_kb_mode, 0x4B45); pub const K_RAW: i32 = 0x00; pub const K_XLATE: i32 = 0x01; pub const K_MEDIUMRAW: i32 = 0x02; pub const K_UNICODE: i32 = 0x03; pub const K_OFF: i32 = 0x04; - ioctl!(bad write_int vt_activate with 0x5606); - ioctl!(bad write_int vt_wait_active with 0x5607); - ioctl!(bad write_ptr vt_set_mode with 0x5602; VtMode); - ioctl!(bad write_int vt_rel_disp with 0x5605); + ioctl_write_int_bad!(vt_activate, 0x5606); + ioctl_write_int_bad!(vt_wait_active, 0x5607); + ioctl_write_ptr_bad!(vt_set_mode, 0x5602, VtMode); + ioctl_write_int_bad!(vt_rel_disp, 0x5605); #[repr(C)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] pub struct VtMode { @@ -171,13 +172,16 @@ impl DirectSession { let logger = ::slog_or_stdlog(logger) .new(o!("smithay_module" => "backend_session", "session_type" => "direct/vt")); - let fd = tty.map(|path| { - open( - path, - fcntl::OFlag::O_RDWR | fcntl::OFlag::O_CLOEXEC, - Mode::empty(), - ).chain_err(|| ErrorKind::FailedToOpenTTY(String::from(path.to_string_lossy()))) - }).unwrap_or_else(|| dup(0 /*stdin*/).chain_err(|| ErrorKind::FailedToOpenTTY(String::from(""))))?; + let fd = tty + .map(|path| { + open( + path, + fcntl::OFlag::O_RDWR | fcntl::OFlag::O_CLOEXEC, + Mode::empty(), + ).chain_err(|| ErrorKind::FailedToOpenTTY(String::from(path.to_string_lossy()))) + }).unwrap_or_else(|| { + dup(0 /*stdin*/).chain_err(|| ErrorKind::FailedToOpenTTY(String::from(""))) + })?; let active = Arc::new(AtomicBool::new(true)); @@ -310,16 +314,10 @@ impl Drop for DirectSession { info!(self.logger, "Deallocating tty {}", self.tty); if let Err(err) = unsafe { tty::kd_set_kb_mode(self.tty, self.old_keyboard_mode) } { - warn!( - self.logger, - "Unable to restore vt keyboard mode. Error: {}", err - ); + warn!(self.logger, "Unable to restore vt keyboard mode. Error: {}", err); } if let Err(err) = unsafe { tty::kd_set_mode(self.tty, tty::KD_TEXT as i32) } { - warn!( - self.logger, - "Unable to restore vt text mode. Error: {}", err - ); + warn!(self.logger, "Unable to restore vt text mode. Error: {}", err); } if let Err(err) = unsafe { tty::vt_set_mode( @@ -333,10 +331,7 @@ impl Drop for DirectSession { error!(self.logger, "Failed to reset vt handling. Error: {}", err); } if let Err(err) = close(self.tty) { - error!( - self.logger, - "Failed to close tty file descriptor. Error: {}", err - ); + error!(self.logger, "Failed to close tty file descriptor. Error: {}", err); } } } @@ -367,8 +362,8 @@ impl SessionNotifier for DirectSessionNotifier { } } -impl Implementation<(), SignalEvent> for DirectSessionNotifier { - fn receive(&mut self, _signal: SignalEvent, (): ()) { +impl DirectSessionNotifier { + fn signal_received(&mut self) { if self.is_active() { info!(self.logger, "Session shall become inactive."); for signal in &mut self.signals { @@ -397,18 +392,54 @@ impl Implementation<(), SignalEvent> for DirectSessionNotifier { } } +/// Bound logind session that is driven by the `wayland_server::EventLoop`. +/// +/// See `direct_session_bind` for details. +pub struct BoundDirectSession { + source: Source, + notifier: Rc>, +} + +impl BoundDirectSession { + /// Unbind the direct session from the `EventLoop` + pub fn unbind(self) -> DirectSessionNotifier { + let BoundDirectSession { source, notifier } = self; + source.remove(); + match Rc::try_unwrap(notifier) { + Ok(notifier) => notifier.into_inner(), + Err(_) => panic!("Notifier should have been freed from the event loop!"), + } + } +} + /// Bind a `DirectSessionNotifier` to an `EventLoop`. /// /// Allows the `DirectSessionNotifier` to listen for incoming signals signalling the session state. /// If you don't use this function `DirectSessionNotifier` will not correctly tell you the current /// session state and call it's `SessionObservers`. -pub fn direct_session_bind( +pub fn direct_session_bind( notifier: DirectSessionNotifier, - token: &LoopToken, -) -> ::std::result::Result, (IoError, DirectSessionNotifier)> { + handle: &LoopHandle, +) -> ::std::result::Result { let signal = notifier.signal; - - token.add_signal_event_source(signal, notifier) + let source = match Signals::new(&[signal]) { + Ok(s) => s, + Err(e) => return Err((e, notifier)), + }; + let notifier = Rc::new(RefCell::new(notifier)); + let fail_notifier = notifier.clone(); + let source = handle + .insert_source(source, { + let notifier = notifier.clone(); + move |_, _| notifier.borrow_mut().signal_received() + }).map_err(move |e| { + // the backend in the closure should already have been dropped + let notifier = Rc::try_unwrap(fail_notifier) + .unwrap_or_else(|_| unreachable!()) + .into_inner(); + (e, notifier) + })?; + Ok(BoundDirectSession { source, notifier }) } error_chain! { diff --git a/src/backend/session/mod.rs b/src/backend/session/mod.rs index de8b430..23d0ea3 100644 --- a/src/backend/session/mod.rs +++ b/src/backend/session/mod.rs @@ -181,6 +181,6 @@ impl AsErrno for () { } pub mod auto; -pub mod direct; mod dbus; +pub mod direct; pub use self::dbus::*; diff --git a/src/backend/udev.rs b/src/backend/udev.rs index 6032059..4bfcc60 100644 --- a/src/backend/udev.rs +++ b/src/backend/udev.rs @@ -11,8 +11,8 @@ use backend::drm::{drm_device_bind, DrmDevice, DrmHandler}; use backend::session::{AsSessionObserver, Session, SessionObserver}; -use drm::Device as BasicDevice; use drm::control::Device as ControlDevice; +use drm::Device as BasicDevice; use nix::fcntl; use nix::sys::stat::dev_t; use std::cell::RefCell; @@ -24,9 +24,9 @@ use std::os::unix::io::{AsRawFd, RawFd}; use std::path::{Path, PathBuf}; use std::rc::{Rc, Weak}; use udev::{Context, Enumerator, Event, EventType, MonitorBuilder, MonitorSocket, Result as UdevResult}; -use wayland_server::LoopToken; -use wayland_server::commons::Implementation; -use wayland_server::sources::{FdEvent, FdInterest, Source}; + +use wayland_server::calloop::generic::{EventedRawFd, Generic}; +use wayland_server::calloop::{LoopHandle, Ready, Source}; /// Udev's `DrmDevice` type based on the underlying session pub struct SessionFdDrmDevice(RawFd); @@ -48,18 +48,33 @@ pub struct UdevBackend< H: DrmHandler + 'static, S: Session + 'static, T: UdevHandler + 'static, + Data: 'static, > { _handler: ::std::marker::PhantomData, - devices: Rc, Rc>>)>>>, + devices: Rc< + RefCell< + HashMap< + dev_t, + ( + Source>, + Rc>>, + ), + >, + >, + >, monitor: MonitorSocket, session: S, handler: T, logger: ::slog::Logger, - token: LoopToken, + handle: LoopHandle, } -impl + 'static, S: Session + 'static, T: UdevHandler + 'static> - UdevBackend +impl< + H: DrmHandler + 'static, + S: Session + 'static, + T: UdevHandler + 'static, + Data: 'static, + > UdevBackend { /// Creates a new `UdevBackend` and adds it to the given `EventLoop`'s state. /// @@ -70,12 +85,12 @@ impl + 'static, S: Session + 'static, T: UdevH /// `handler` - User-provided handler to respond to any detected changes /// `logger` - slog Logger to be used by the backend and its `DrmDevices`. pub fn new( - token: LoopToken, + handle: LoopHandle, context: &Context, mut session: S, mut handler: T, logger: L, - ) -> Result> + ) -> Result> where L: Into>, { @@ -103,9 +118,9 @@ impl + 'static, S: Session + 'static, T: UdevH let fd = device.as_raw_fd(); match handler.device_added(&mut device) { Some(drm_handler) => { - match drm_device_bind(&token, device, drm_handler) { + match drm_device_bind(&handle, device, drm_handler) { Ok((event_source, device)) => Some((devnum, (event_source, device))), - Err((err, (mut device, _))) => { + Err((err, mut device)) => { warn!(logger, "Failed to bind device. Error: {:?}.", err); handler.device_removed(&mut device); drop(device); @@ -137,9 +152,7 @@ impl + 'static, S: Session + 'static, T: UdevH builder .match_subsystem("drm") .chain_err(|| ErrorKind::FailedToInitMonitor)?; - let monitor = builder - .listen() - .chain_err(|| ErrorKind::FailedToInitMonitor)?; + let monitor = builder.listen().chain_err(|| ErrorKind::FailedToInitMonitor)?; Ok(UdevBackend { _handler: ::std::marker::PhantomData, @@ -148,7 +161,7 @@ impl + 'static, S: Session + 'static, T: UdevH session, handler, logger, - token, + handle, }) } @@ -164,27 +177,47 @@ impl + 'static, S: Session + 'static, T: UdevH let fd = device.as_raw_fd(); drop(device); if let Err(err) = self.session.close(fd) { - warn!( - self.logger, - "Failed to close device. Error: {:?}. Ignoring", err - ); + warn!(self.logger, "Failed to close device. Error: {:?}. Ignoring", err); }; } info!(self.logger, "All devices closed"); } } +impl< + H: DrmHandler + 'static, + S: Session + 'static, + T: UdevHandler + 'static, + Data: 'static, + > Drop for UdevBackend +{ + fn drop(&mut self) { + self.close(); + } +} + /// `SessionObserver` linked to the `UdevBackend` it was created from. pub struct UdevBackendObserver { - devices: Weak, Rc>>)>>>, + devices: Weak< + RefCell< + HashMap< + dev_t, + ( + Source>, + Rc>>, + ), + >, + >, + >, logger: ::slog::Logger, } impl< - H: DrmHandler + 'static, - S: Session + 'static, - T: UdevHandler + 'static, -> AsSessionObserver for UdevBackend + H: DrmHandler + 'static, + S: Session + 'static, + T: UdevHandler + 'static, + Data: 'static, + > AsSessionObserver for UdevBackend { fn observer(&mut self) -> UdevBackendObserver { UdevBackendObserver { @@ -218,152 +251,141 @@ impl SessionObserver for UdevBackendObserver { /// /// Allows the backend to recieve kernel events and thus to drive the `UdevHandler`. /// No runtime functionality can be provided without using this function. -pub fn udev_backend_bind( - token: &LoopToken, - udev: UdevBackend, -) -> ::std::result::Result, (IoError, UdevBackend)> +pub fn udev_backend_bind( + mut udev: UdevBackend, +) -> ::std::result::Result>, IoError> where H: DrmHandler + 'static, T: UdevHandler + 'static, S: Session + 'static, { let fd = udev.monitor.as_raw_fd(); - token.add_fd_event_source(fd, FdInterest::READ, udev) + let handle = udev.handle.clone(); + let mut source = Generic::from_raw_fd(fd); + source.set_interest(Ready::readable()); + handle.insert_source(source, move |_, _| { + udev.process_events(); + }) } -impl Implementation<(), FdEvent> for UdevBackend +impl UdevBackend where H: DrmHandler + 'static, T: UdevHandler + 'static, S: Session + 'static, + Data: 'static, { - fn receive(&mut self, event: FdEvent, (): ()) { - match event { - FdEvent::Ready { .. } => { - let events = self.monitor.clone().collect::>(); - for event in events { - match event.event_type() { - // New device - EventType::Add => { - info!(self.logger, "Device Added"); - if let (Some(path), Some(devnum)) = (event.devnode(), event.devnum()) { - let mut device = { - match DrmDevice::new( - { - let logger = self.logger.clone(); - match self.session.open( - path, - fcntl::OFlag::O_RDWR | fcntl::OFlag::O_CLOEXEC - | fcntl::OFlag::O_NOCTTY - | fcntl::OFlag::O_NONBLOCK, - ) { - Ok(fd) => SessionFdDrmDevice(fd), - Err(err) => { - warn!( - logger, - "Unable to open drm device {:?}, Error: {:?}. Skipping", - path, - err - ); - continue; - } - } - }, - self.logger.clone(), + fn process_events(&mut self) { + let events = self.monitor.clone().collect::>(); + for event in events { + match event.event_type() { + // New device + EventType::Add => { + info!(self.logger, "Device Added"); + if let (Some(path), Some(devnum)) = (event.devnode(), event.devnum()) { + let mut device = { + match DrmDevice::new( + { + let logger = self.logger.clone(); + match self.session.open( + path, + fcntl::OFlag::O_RDWR + | fcntl::OFlag::O_CLOEXEC + | fcntl::OFlag::O_NOCTTY + | fcntl::OFlag::O_NONBLOCK, ) { - Ok(dev) => dev, + Ok(fd) => SessionFdDrmDevice(fd), Err(err) => { warn!( - self.logger, - "Failed to initialize device {:?}. Error: {}. Skipping", + logger, + "Unable to open drm device {:?}, Error: {:?}. Skipping", path, err ); continue; } } - }; - let fd = device.as_raw_fd(); - match self.handler.device_added(&mut device) { - Some(drm_handler) => { - match drm_device_bind(&self.token, device, drm_handler) { - Ok(fd_event_source) => { - self.devices.borrow_mut().insert(devnum, fd_event_source); - } - Err((err, (mut device, _))) => { - warn!( - self.logger, - "Failed to bind device. Error: {:?}.", err - ); - self.handler.device_removed(&mut device); - drop(device); - if let Err(err) = self.session.close(fd) { - warn!( - self.logger, - "Failed to close dropped device. Error: {:?}. Ignoring", err - ); - }; - } - } - } - None => { - self.handler.device_removed(&mut device); - drop(device); - if let Err(err) = self.session.close(fd) { - warn!( - self.logger, - "Failed to close unused device. Error: {:?}", err - ); - } - } - }; + }, + self.logger.clone(), + ) { + Ok(dev) => dev, + Err(err) => { + warn!( + self.logger, + "Failed to initialize device {:?}. Error: {}. Skipping", path, err + ); + continue; + } } - } - // Device removed - EventType::Remove => { - info!(self.logger, "Device Remove"); - if let Some(devnum) = event.devnum() { - if let Some((fd_event_source, device)) = - self.devices.borrow_mut().remove(&devnum) - { - fd_event_source.remove(); - let mut device = Rc::try_unwrap(device) - .unwrap_or_else(|_| unreachable!()) - .into_inner(); + }; + let fd = device.as_raw_fd(); + match self.handler.device_added(&mut device) { + Some(drm_handler) => match drm_device_bind(&self.handle, device, drm_handler) { + Ok(fd_event_source) => { + self.devices.borrow_mut().insert(devnum, fd_event_source); + } + Err((err, mut device)) => { + warn!(self.logger, "Failed to bind device. Error: {:?}.", err); self.handler.device_removed(&mut device); - let fd = device.as_raw_fd(); drop(device); if let Err(err) = self.session.close(fd) { warn!( self.logger, - "Failed to close device {:?}. Error: {:?}. Ignoring", - event.sysname(), - err + "Failed to close dropped device. Error: {:?}. Ignoring", err ); }; } + }, + None => { + self.handler.device_removed(&mut device); + drop(device); + if let Err(err) = self.session.close(fd) { + warn!(self.logger, "Failed to close unused device. Error: {:?}", err); + } } - } - // New connector - EventType::Change => { - info!(self.logger, "Device Changed"); - if let Some(devnum) = event.devnum() { - info!(self.logger, "Devnum: {:b}", devnum); - if let Some(&(_, ref device)) = self.devices.borrow_mut().get(&devnum) { - let handler = &mut self.handler; - handler.device_changed(&mut device.borrow_mut()); - } else { - info!(self.logger, "changed, but device not tracked by backend"); - }; - } else { - info!(self.logger, "changed, but no devnum"); - } - } - _ => {} + }; } } + // Device removed + EventType::Remove => { + info!(self.logger, "Device Remove"); + if let Some(devnum) = event.devnum() { + if let Some((fd_event_source, device)) = self.devices.borrow_mut().remove(&devnum) { + fd_event_source.remove(); + let mut device = Rc::try_unwrap(device) + .unwrap_or_else(|_| unreachable!()) + .into_inner(); + self.handler.device_removed(&mut device); + let fd = device.as_raw_fd(); + drop(device); + if let Err(err) = self.session.close(fd) { + warn!( + self.logger, + "Failed to close device {:?}. Error: {:?}. Ignoring", + event.sysname(), + err + ); + }; + } + } + } + // New connector + EventType::Change => { + info!(self.logger, "Device Changed"); + if let Some(devnum) = event.devnum() { + info!(self.logger, "Devnum: {:b}", devnum); + if let Some(&(_, ref device)) = self.devices.borrow_mut().get(&devnum) { + let handler = &mut self.handler; + handler.device_changed(&mut device.borrow_mut()); + } else { + info!(self.logger, "changed, but device not tracked by backend"); + }; + } else { + info!(self.logger, "changed, but no devnum"); + } + } + _ => {} } - FdEvent::Error { error, .. } => self.handler.error(error), } } } @@ -413,7 +435,8 @@ pub fn primary_gpu>(context: &Context, seat: S) -> UdevResult>(context: &Context, seat: S) -> UdevResult u32 { cmp::max( - (self.x * width as f64 - / self.window - .window() - .get_inner_size() - .unwrap_or((width, 0)) - .0 as f64) as i32, + (self.x * width as f64 / self.window.window().get_inner_size().unwrap_or((width, 0)).0 as f64) + as i32, 0, ) as u32 } fn y_transformed(&self, height: u32) -> u32 { cmp::max( - (self.y * height as f64 - / self.window - .window() - .get_inner_size() - .unwrap_or((0, height)) - .1 as f64) as i32, + (self.y * height as f64 / self.window.window().get_inner_size().unwrap_or((0, height)).1 as f64) + as i32, 0, ) as u32 } @@ -483,11 +477,7 @@ impl TouchDownEvent for WinitTouchStartedEvent { fn x_transformed(&self, width: u32) -> u32 { cmp::min( self.location.0 as i32 * width as i32 - / self.window - .window() - .get_inner_size() - .unwrap_or((width, 0)) - .0 as i32, + / self.window.window().get_inner_size().unwrap_or((width, 0)).0 as i32, 0, ) as u32 } @@ -495,11 +485,7 @@ impl TouchDownEvent for WinitTouchStartedEvent { fn y_transformed(&self, height: u32) -> u32 { cmp::min( self.location.1 as i32 * height as i32 - / self.window - .window() - .get_inner_size() - .unwrap_or((0, height)) - .1 as i32, + / self.window.window().get_inner_size().unwrap_or((0, height)).1 as i32, 0, ) as u32 } @@ -534,21 +520,11 @@ impl TouchMotionEvent for WinitTouchMovedEvent { } fn x_transformed(&self, width: u32) -> u32 { - self.location.0 as u32 * width - / self.window - .window() - .get_inner_size() - .unwrap_or((width, 0)) - .0 + self.location.0 as u32 * width / self.window.window().get_inner_size().unwrap_or((width, 0)).0 } fn y_transformed(&self, height: u32) -> u32 { - self.location.1 as u32 * height - / self.window - .window() - .get_inner_size() - .unwrap_or((0, height)) - .1 + self.location.1 as u32 * height / self.window.window().get_inner_size().unwrap_or((0, height)).1 } } @@ -644,11 +620,7 @@ impl InputBackend for WinitInputBackend { fn clear_handler(&mut self) { if let Some(mut handler) = self.handler.take() { - trace!( - self.logger, - "Calling on_seat_destroyed with {:?}", - self.seat - ); + trace!(self.logger, "Calling on_seat_destroyed with {:?}", self.seat); handler.on_seat_destroyed(&self.seat); } info!(self.logger, "Removing input handler"); @@ -714,10 +686,7 @@ impl InputBackend for WinitInputBackend { } ( WindowEvent::KeyboardInput { - input: - KeyboardInput { - scancode, state, .. - }, + input: KeyboardInput { scancode, state, .. }, .. }, Some(handler), @@ -729,11 +698,7 @@ impl InputBackend for WinitInputBackend { *key_counter = key_counter.checked_sub(1).unwrap_or(0) } }; - trace!( - logger, - "Calling on_keyboard_key with {:?}", - (scancode, state) - ); + trace!(logger, "Calling on_keyboard_key with {:?}", (scancode, state)); handler.on_keyboard_key( seat, WinitKeyboardInputEvent { @@ -744,13 +709,7 @@ impl InputBackend for WinitInputBackend { }, ) } - ( - WindowEvent::CursorMoved { - position: (x, y), .. - }, - Some(handler), - _, - ) => { + (WindowEvent::CursorMoved { position: (x, y), .. }, Some(handler), _) => { trace!(logger, "Calling on_pointer_move_absolute with {:?}", (x, y)); handler.on_pointer_move_absolute( seat, @@ -768,19 +727,8 @@ impl InputBackend for WinitInputBackend { handler.on_pointer_axis(seat, event); } (WindowEvent::MouseInput { state, button, .. }, Some(handler), _) => { - trace!( - logger, - "Calling on_pointer_button with {:?}", - (button, state) - ); - handler.on_pointer_button( - seat, - WinitMouseInputEvent { - time, - button, - state, - }, - ) + trace!(logger, "Calling on_pointer_button with {:?}", (button, state)); + handler.on_pointer_button(seat, WinitMouseInputEvent { time, button, state }) } ( WindowEvent::Touch(Touch { diff --git a/src/lib.rs b/src/lib.rs index 28f7707..5a4a379 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -49,8 +49,8 @@ extern crate error_chain; extern crate lazy_static; pub mod backend; -pub mod wayland; pub mod utils; +pub mod wayland; #[cfg(feature = "xwayland")] pub mod xwayland; diff --git a/src/wayland/compositor/handlers.rs b/src/wayland/compositor/handlers.rs index 1555e64..367489f 100644 --- a/src/wayland/compositor/handlers.rs +++ b/src/wayland/compositor/handlers.rs @@ -1,11 +1,15 @@ -use super::{CompositorToken, Damage, Rectangle, RectangleKind, Role, RoleType, SubsurfaceRole, SurfaceEvent}; -use super::region::RegionData; -use super::tree::{Location, SurfaceData}; use std::cell::RefCell; use std::rc::Rc; -use wayland_server::{LoopToken, NewResource, Resource}; -use wayland_server::commons::Implementation; +use std::sync::Mutex; + use wayland_server::protocol::{wl_compositor, wl_region, wl_subcompositor, wl_subsurface, wl_surface}; +use wayland_server::{DisplayToken, NewResource, Resource}; + +use super::tree::{Location, SurfaceData}; +use super::{ + CompositorToken, Damage, Rectangle, RectangleKind, RegionAttributes, Role, RoleType, SubsurfaceRole, + SurfaceEvent, +}; /* * wl_compositor @@ -13,14 +17,14 @@ use wayland_server::protocol::{wl_compositor, wl_region, wl_subcompositor, wl_su pub(crate) fn implement_compositor( compositor: NewResource, - token: LoopToken, + token: DisplayToken, log: ::slog::Logger, implem: Rc>, ) -> Resource where U: Default + 'static, R: Default + 'static, - Impl: Implementation<(Resource, CompositorToken), SurfaceEvent> + 'static, + Impl: FnMut(SurfaceEvent, Resource, CompositorToken) + 'static, { let my_token = token.clone(); compositor.implement_nonsend( @@ -34,7 +38,8 @@ where implement_region(id, &token); } }, - None::, + None::, + (), &my_token, ) } @@ -46,95 +51,74 @@ where // Internal implementation data of surfaces pub(crate) struct SurfaceImplem { log: ::slog::Logger, - implem: - Rc, CompositorToken), SurfaceEvent>>>, + implem: Rc, CompositorToken)>>, } impl SurfaceImplem { fn make(log: ::slog::Logger, implem: Rc>) -> SurfaceImplem where - Impl: Implementation<(Resource, CompositorToken), SurfaceEvent> - + 'static, + Impl: FnMut(SurfaceEvent, Resource, CompositorToken) + 'static, { - SurfaceImplem { - log, - implem, - } + SurfaceImplem { log, implem } } } -impl Implementation, wl_surface::Request> for SurfaceImplem +impl SurfaceImplem where U: 'static, R: 'static, { - fn receive(&mut self, req: wl_surface::Request, surface: Resource) { + fn receive_surface_request( + &mut self, + req: wl_surface::Request, + surface: Resource, + ) { match req { - wl_surface::Request::Attach { buffer, x, y } => unsafe { + wl_surface::Request::Attach { buffer, x, y } => { SurfaceData::::with_data(&surface, |d| { d.buffer = Some(buffer.map(|b| (b.clone(), (x, y)))) }); - }, - wl_surface::Request::Damage { - x, - y, - width, - height, - } => unsafe { + } + wl_surface::Request::Damage { x, y, width, height } => { SurfaceData::::with_data(&surface, |d| { - d.damage = Damage::Surface(Rectangle { - x, - y, - width, - height, - }) + d.damage = Damage::Surface(Rectangle { x, y, width, height }) }); - }, + } wl_surface::Request::Frame { callback } => { let mut user_impl = self.implem.borrow_mut(); trace!(self.log, "Calling user implementation for wl_surface.frame"); - user_impl.receive( - SurfaceEvent::Frame { callback }, - (surface, CompositorToken::make()), - ); + (&mut *user_impl)(SurfaceEvent::Frame { callback }, surface, CompositorToken::make()); } - wl_surface::Request::SetOpaqueRegion { region } => unsafe { - let attributes = region.map(|r| RegionData::get_attributes(&r)); + wl_surface::Request::SetOpaqueRegion { region } => { + let attributes = region.map(|r| { + let attributes_mutex = r.user_data::>().unwrap(); + attributes_mutex.lock().unwrap().clone() + }); SurfaceData::::with_data(&surface, |d| d.opaque_region = attributes); - }, - wl_surface::Request::SetInputRegion { region } => unsafe { - let attributes = region.map(|r| RegionData::get_attributes(&r)); + } + wl_surface::Request::SetInputRegion { region } => { + let attributes = region.map(|r| { + let attributes_mutex = r.user_data::>().unwrap(); + attributes_mutex.lock().unwrap().clone() + }); SurfaceData::::with_data(&surface, |d| d.input_region = attributes); - }, + } wl_surface::Request::Commit => { let mut user_impl = self.implem.borrow_mut(); - trace!( - self.log, - "Calling user implementation for wl_surface.commit" - ); - user_impl.receive(SurfaceEvent::Commit, (surface, CompositorToken::make())); + trace!(self.log, "Calling user implementation for wl_surface.commit"); + (&mut *user_impl)(SurfaceEvent::Commit, surface, CompositorToken::make()); } - wl_surface::Request::SetBufferTransform { transform } => unsafe { + wl_surface::Request::SetBufferTransform { transform } => { SurfaceData::::with_data(&surface, |d| d.buffer_transform = transform); - }, - wl_surface::Request::SetBufferScale { scale } => unsafe { + } + wl_surface::Request::SetBufferScale { scale } => { SurfaceData::::with_data(&surface, |d| d.buffer_scale = scale); - }, - wl_surface::Request::DamageBuffer { - x, - y, - width, - height, - } => unsafe { + } + wl_surface::Request::DamageBuffer { x, y, width, height } => { SurfaceData::::with_data(&surface, |d| { - d.damage = Damage::Buffer(Rectangle { - x, - y, - width, - height, - }) + d.damage = Damage::Buffer(Rectangle { x, y, width, height }) }); - }, + } wl_surface::Request::Destroy => { // All is already handled by our destructor } @@ -144,25 +128,24 @@ where fn implement_surface( surface: NewResource, - token: &LoopToken, + token: &DisplayToken, log: ::slog::Logger, implem: Rc>, ) -> Resource where U: Default + 'static, R: Default + 'static, - Impl: Implementation<(Resource, CompositorToken), SurfaceEvent> + 'static, + Impl: FnMut(SurfaceEvent, Resource, CompositorToken) + 'static, { let surface = surface.implement_nonsend( - SurfaceImplem::make(log, implem), - Some(|surface, _| unsafe { - SurfaceData::::cleanup(&surface); - }), + { + let mut implem = SurfaceImplem::make(log, implem); + move |req, surface| implem.receive_surface_request(req, surface) + }, + Some(|surface| SurfaceData::::cleanup(&surface)), + SurfaceData::::new(), token, ); - unsafe { - SurfaceData::::init(&surface); - } surface } @@ -170,63 +153,32 @@ where * wl_region */ -pub(crate) struct RegionImplem; - -impl Implementation, wl_region::Request> for RegionImplem { - fn receive(&mut self, request: wl_region::Request, region: Resource) { - unsafe { - match request { - wl_region::Request::Add { - x, - y, - width, - height, - } => RegionData::add_rectangle( - ®ion, - RectangleKind::Add, - Rectangle { - x, - y, - width, - height, - }, - ), - wl_region::Request::Subtract { - x, - y, - width, - height, - } => RegionData::add_rectangle( - ®ion, - RectangleKind::Subtract, - Rectangle { - x, - y, - width, - height, - }, - ), - wl_region::Request::Destroy => { - // all is handled by our destructor - } - } +fn region_implem(request: wl_region::Request, region: Resource) { + let attributes_mutex = region.user_data::>().unwrap(); + let mut guard = attributes_mutex.lock().unwrap(); + match request { + wl_region::Request::Add { x, y, width, height } => guard + .rects + .push((RectangleKind::Add, Rectangle { x, y, width, height })), + wl_region::Request::Subtract { x, y, width, height } => guard + .rects + .push((RectangleKind::Subtract, Rectangle { x, y, width, height })), + wl_region::Request::Destroy => { + // all is handled by our destructor } } } fn implement_region( region: NewResource, - token: &LoopToken, + token: &DisplayToken, ) -> Resource { - let region = region.implement_nonsend( - RegionImplem, - Some(|region, _| unsafe { RegionData::cleanup(®ion) }), + region.implement_nonsend( + region_implem, + None::, + Mutex::new(RegionAttributes::default()), token, - ); - unsafe { - RegionData::init(®ion); - } - region + ) } /* @@ -235,7 +187,7 @@ fn implement_region( pub(crate) fn implement_subcompositor( subcompositor: NewResource, - token: LoopToken, + token: DisplayToken, ) -> Resource where R: RoleType + Role + 'static, @@ -244,24 +196,20 @@ where let my_token = token.clone(); subcompositor.implement_nonsend( move |request, subcompositor: Resource<_>| match request { - wl_subcompositor::Request::GetSubsurface { - id, - surface, - parent, - } => { - if let Err(()) = unsafe { SurfaceData::::set_parent(&surface, &parent) } { + wl_subcompositor::Request::GetSubsurface { id, surface, parent } => { + if let Err(()) = SurfaceData::::set_parent(&surface, &parent) { subcompositor.post_error( wl_subcompositor::Error::BadSurface as u32, "Surface already has a role.".into(), ); return; } - let subsurface = implement_subsurface::(id, &token); - subsurface.set_user_data(Box::into_raw(Box::new(surface.clone())) as *mut ()); + implement_subsurface::(id, surface.clone(), &token); } wl_subcompositor::Request::Destroy => {} }, - None::, + None::, + (), &my_token, ) } @@ -270,28 +218,28 @@ where * wl_subsurface */ -unsafe fn with_subsurface_attributes(subsurface: &Resource, f: F) +fn with_subsurface_attributes(subsurface: &Resource, f: F) where F: FnOnce(&mut SubsurfaceRole), U: 'static, R: RoleType + Role + 'static, { - let ptr = subsurface.get_user_data(); - let surface = &*(ptr as *mut Resource); + let surface = subsurface.user_data::>().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, - token: &LoopToken, + surface: Resource, + token: &DisplayToken, ) -> Resource where U: 'static, R: RoleType + Role + 'static, { subsurface.implement_nonsend( - |request, subsurface| unsafe { + |request, subsurface| { match request { wl_subsurface::Request::SetPosition { x, y } => { with_subsurface_attributes::(&subsurface, |attrs| { @@ -299,7 +247,7 @@ where }) } wl_subsurface::Request::PlaceAbove { sibling } => { - let surface = &*(subsurface.get_user_data() as *mut Resource); + let surface = subsurface.user_data::>().unwrap(); if let Err(()) = SurfaceData::::reorder(surface, Location::After, &sibling) { subsurface.post_error( wl_subsurface::Error::BadSurface as u32, @@ -308,7 +256,7 @@ where } } wl_subsurface::Request::PlaceBelow { sibling } => { - let surface = &*(subsurface.get_user_data() as *mut Resource); + let surface = subsurface.user_data::>().unwrap(); if let Err(()) = SurfaceData::::reorder(surface, Location::Before, &sibling) { subsurface.post_error( wl_subsurface::Error::BadSurface as u32, @@ -331,21 +279,18 @@ where } } }, - Some(|subsurface, _| unsafe { - destroy_subsurface::(&subsurface); - }), + Some(|subsurface| destroy_subsurface::(&subsurface)), + surface, token, ) } -unsafe fn destroy_subsurface(subsurface: &Resource) +fn destroy_subsurface(subsurface: &Resource) where U: 'static, R: RoleType + Role + 'static, { - let ptr = subsurface.get_user_data(); - subsurface.set_user_data(::std::ptr::null_mut()); - let surface = Box::from_raw(ptr as *mut Resource); + let surface = subsurface.user_data::>().unwrap(); if surface.is_alive() { SurfaceData::::unset_parent(&surface); } diff --git a/src/wayland/compositor/mod.rs b/src/wayland/compositor/mod.rs index e9c8f90..2d70ad2 100644 --- a/src/wayland/compositor/mod.rs +++ b/src/wayland/compositor/mod.rs @@ -43,15 +43,14 @@ //! define_roles!(MyRoles); //! //! # fn main() { -//! # let (mut display, event_loop) = wayland_server::Display::new(); +//! # let mut event_loop = wayland_server::calloop::EventLoop::<()>::new().unwrap(); +//! # let mut display = wayland_server::Display::new(event_loop.handle()); //! // Call the init function: //! let (token, _, _) = compositor_init::( //! &mut display, -//! event_loop.token(), -//! |request, (surface, compositor_token)| { +//! |request, surface, compositor_token| { //! /* -//! Your handling of the user requests. This closure can also -//! be a struct implementing the appropriate Implementation trait. +//! Your handling of the user requests. //! */ //! }, //! None // put a logger here @@ -79,21 +78,21 @@ use std::cell::RefCell; use std::rc::Rc; +use std::sync::Mutex; mod handlers; -mod tree; -mod region; pub mod roles; +mod tree; -use self::region::RegionData; use self::roles::{Role, RoleType, WrongRole}; use self::tree::SurfaceData; pub use self::tree::TraversalAction; use utils::Rectangle; -use wayland_server::{Display, Global, LoopToken, NewResource, Resource}; -use wayland_server::commons::Implementation; -use wayland_server::protocol::{wl_buffer, wl_callback, wl_compositor, wl_output, wl_region, wl_subcompositor}; use wayland_server::protocol::wl_surface::WlSurface; +use wayland_server::protocol::{ + wl_buffer, wl_callback, wl_compositor, wl_output, wl_region, wl_subcompositor, +}; +use wayland_server::{Display, Global, NewResource, Resource}; /// Description of which part of a surface /// should be considered damaged and needs to be redrawn @@ -271,11 +270,7 @@ impl CompositorToken { where F: FnOnce(&mut SurfaceAttributes) -> T, { - assert!( - surface.is_implemented_with::>(), - "Accessing the data of foreign surfaces is not supported." - ); - unsafe { SurfaceData::::with_data(surface, f) } + SurfaceData::::with_data(surface, f) } } @@ -309,13 +304,7 @@ where where F: FnMut(&Resource, &mut SurfaceAttributes, &mut R, &T) -> TraversalAction, { - assert!( - surface.is_implemented_with::>(), - "Accessing the data of foreign surfaces is not supported." - ); - unsafe { - SurfaceData::::map_tree(surface, initial, f, false); - } + SurfaceData::::map_tree(surface, initial, f, false); Ok(()) } @@ -335,13 +324,7 @@ where where F: FnMut(&Resource, &mut SurfaceAttributes, &mut R, &T) -> TraversalAction, { - assert!( - surface.is_implemented_with::>(), - "Accessing the data of foreign surfaces is not supported." - ); - unsafe { - SurfaceData::::map_tree(surface, initial, f, true); - } + SurfaceData::::map_tree(surface, initial, f, true); Ok(()) } @@ -352,11 +335,7 @@ where /// If the surface is not managed by the CompositorGlobal that provided this token, this /// will panic (having more than one compositor is not supported). pub fn get_parent(&self, surface: &Resource) -> Option> { - assert!( - surface.is_implemented_with::>(), - "Accessing the data of foreign surfaces is not supported." - ); - unsafe { SurfaceData::::get_parent(surface) } + SurfaceData::::get_parent(surface) } /// Retrieve the children of this surface @@ -364,11 +343,7 @@ where /// If the surface is not managed by the CompositorGlobal that provided this token, this /// will panic (having more than one compositor is not supported). pub fn get_children(&self, surface: &Resource) -> Vec> { - assert!( - surface.is_implemented_with::>(), - "Accessing the data of foreign surfaces is not supported." - ); - unsafe { SurfaceData::::get_children(surface) } + SurfaceData::::get_children(surface) } } @@ -378,11 +353,7 @@ impl CompositorToken { /// If the surface is not managed by the CompositorGlobal that provided this token, this /// will panic (having more than one compositor is not supported). pub fn has_a_role(&self, surface: &Resource) -> bool { - assert!( - surface.is_implemented_with::>(), - "Accessing the data of foreign surfaces is not supported." - ); - unsafe { SurfaceData::::has_a_role(surface) } + SurfaceData::::has_a_role(surface) } /// Check wether this surface as a specific role @@ -393,11 +364,7 @@ impl CompositorToken { where R: Role, { - assert!( - surface.is_implemented_with::>(), - "Accessing the data of foreign surfaces is not supported." - ); - unsafe { SurfaceData::::has_role::(surface) } + SurfaceData::::has_role::(surface) } /// Register that this surface has given role with default data @@ -411,11 +378,7 @@ impl CompositorToken { R: Role, RoleData: Default, { - assert!( - surface.is_implemented_with::>(), - "Accessing the data of foreign surfaces is not supported." - ); - unsafe { SurfaceData::::give_role::(surface) } + SurfaceData::::give_role::(surface) } /// Register that this surface has given role with given data @@ -432,11 +395,7 @@ impl CompositorToken { where R: Role, { - assert!( - surface.is_implemented_with::>(), - "Accessing the data of foreign surfaces is not supported." - ); - unsafe { SurfaceData::::give_role_with::(surface, data) } + SurfaceData::::give_role_with::(surface, data) } /// Access the role data of a surface @@ -450,11 +409,7 @@ impl CompositorToken { R: Role, F: FnOnce(&mut RoleData) -> T, { - assert!( - surface.is_implemented_with::>(), - "Accessing the data of foreign surfaces is not supported." - ); - unsafe { SurfaceData::::with_role_data::(surface, f) } + SurfaceData::::with_role_data::(surface, f) } /// Register that this surface does not have a role any longer and retrieve the data @@ -467,11 +422,7 @@ impl CompositorToken { where R: Role, { - assert!( - surface.is_implemented_with::>(), - "Accessing the data of foreign surfaces is not supported." - ); - unsafe { SurfaceData::::remove_role::(surface) } + SurfaceData::::remove_role::(surface) } /// Retrieve the metadata associated with a wl_region @@ -479,11 +430,10 @@ 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: &Resource) -> RegionAttributes { - assert!( - region.is_implemented_with::(), - "Accessing the data of foreign regions is not supported." - ); - unsafe { RegionData::get_attributes(region) } + match region.user_data::>() { + Some(mutex) => mutex.lock().unwrap().clone(), + None => panic!("Accessing the data of foreign regions is not supported."), + } } } @@ -497,7 +447,6 @@ impl CompositorToken { /// globals from the event loop in the future. pub fn compositor_init( display: &mut Display, - token: LoopToken, implem: Impl, logger: L, ) -> ( @@ -509,15 +458,15 @@ where L: Into>, U: Default + 'static, R: Default + RoleType + Role + 'static, - Impl: Implementation<(Resource, CompositorToken), SurfaceEvent> + 'static, + Impl: FnMut(SurfaceEvent, Resource, CompositorToken) + 'static, { let log = ::slog_or_stdlog(logger).new(o!("smithay_module" => "compositor_handler")); let implem = Rc::new(RefCell::new(implem)); - let comp_token = token.clone(); - let sub_token = token.clone(); + let comp_token = display.get_token(); + let sub_token = display.get_token(); - let compositor = display.create_global(&token, 4, move |_version, new_compositor| { + let compositor = display.create_global(4, move |new_compositor, _version| { self::handlers::implement_compositor::( new_compositor, comp_token.clone(), @@ -526,7 +475,7 @@ where ); }); - let subcompositor = display.create_global(&token, 1, move |_version, new_subcompositor| { + let subcompositor = display.create_global(1, move |new_subcompositor, _version| { self::handlers::implement_subcompositor::(new_subcompositor, sub_token.clone()); }); diff --git a/src/wayland/compositor/region.rs b/src/wayland/compositor/region.rs deleted file mode 100644 index 62d93b5..0000000 --- a/src/wayland/compositor/region.rs +++ /dev/null @@ -1,44 +0,0 @@ -use super::{Rectangle, RectangleKind, RegionAttributes}; -use std::sync::Mutex; -use wayland_server::Resource; -use wayland_server::protocol::wl_region; - -#[derive(Default)] -pub struct RegionData { - attributes: RegionAttributes, -} - -impl RegionData { - /// Initialize the user_data of a region, must be called right when the surface is created - pub unsafe fn init(region: &Resource) { - region.set_user_data(Box::into_raw(Box::new(Mutex::new(RegionData::default()))) as *mut _) - } - - /// Cleans the user_data of that surface, must be called when it is destroyed - pub unsafe fn cleanup(region: &Resource) { - let ptr = region.get_user_data(); - region.set_user_data(::std::ptr::null_mut()); - let _my_data_mutex: Box> = Box::from_raw(ptr as *mut _); - } - - unsafe fn get_data(region: &Resource) -> &Mutex { - let ptr = region.get_user_data(); - &*(ptr as *mut _) - } - - pub unsafe fn get_attributes(region: &Resource) -> RegionAttributes { - let data_mutex = Self::get_data(region); - let data_guard = data_mutex.lock().unwrap(); - data_guard.attributes.clone() - } - - pub unsafe fn add_rectangle( - region: &Resource, - kind: RectangleKind, - rect: Rectangle, - ) { - let data_mutex = Self::get_data(region); - let mut data_guard = data_mutex.lock().unwrap(); - data_guard.attributes.rects.push((kind, rect)); - } -} diff --git a/src/wayland/compositor/tree.rs b/src/wayland/compositor/tree.rs index 94547e0..f69701e 100644 --- a/src/wayland/compositor/tree.rs +++ b/src/wayland/compositor/tree.rs @@ -1,8 +1,8 @@ -use super::{SubsurfaceRole, SurfaceAttributes}; use super::roles::*; +use super::{SubsurfaceRole, SurfaceAttributes}; use std::sync::Mutex; -use wayland_server::Resource; use wayland_server::protocol::wl_surface::WlSurface; +use wayland_server::Resource; /// Node of a subsurface tree, holding some user specified data type U /// at each node @@ -20,9 +20,6 @@ use wayland_server::protocol::wl_surface::WlSurface; /// a tree, but with loops allowed. This is because the wayland protocol does not /// have a failure case to forbid this. Note that if any node in such a graph does not /// have a parent, then the graph is a tree and this node is its root. -/// -/// All the methods here are unsafe, because they assume the provided `wl_surface` object -/// is correctly initialized regarding its `user_data`. pub struct SurfaceData { parent: Option>, children: Vec>, @@ -46,18 +43,13 @@ pub enum TraversalAction { } impl SurfaceData { - fn new() -> SurfaceData { - SurfaceData { + pub fn new() -> Mutex> { + Mutex::new(SurfaceData { parent: None, children: Vec::new(), role: Default::default(), attributes: Default::default(), - } - } - - /// Initialize the user_data of a surface, must be called right when the surface is created - pub unsafe fn init(surface: &Resource) { - surface.set_user_data(Box::into_raw(Box::new(Mutex::new(SurfaceData::::new()))) as *mut _) + }) } } @@ -66,21 +58,14 @@ where U: 'static, R: 'static, { - unsafe fn get_data(surface: &Resource) -> &Mutex> { - let ptr = surface.get_user_data(); - &*(ptr as *mut _) - } - /// Cleans the user_data of that surface, must be called when it is destroyed - pub unsafe fn cleanup(surface: &Resource) { - let ptr = surface.get_user_data(); - surface.set_user_data(::std::ptr::null_mut()); - let my_data_mutex: Box>> = Box::from_raw(ptr as *mut _); - let mut my_data = my_data_mutex.into_inner().unwrap(); + pub fn cleanup(surface: &Resource) { + let my_data_mutex = surface.user_data::>>().unwrap(); + let mut my_data = my_data_mutex.lock().unwrap(); if let Some(old_parent) = my_data.parent.take() { if !old_parent.equals(surface) { // We had a parent that is not ourselves, lets unregister ourselves from it - let old_parent_mutex = Self::get_data(&old_parent); + let old_parent_mutex = old_parent.user_data::>>().unwrap(); let mut old_parent_guard = old_parent_mutex.lock().unwrap(); old_parent_guard.children.retain(|c| !c.equals(surface)); } @@ -91,7 +76,7 @@ where if child.equals(surface) { continue; } - let child_mutex = Self::get_data(child); + let child_mutex = child.user_data::>>().unwrap(); let mut child_guard = child_mutex.lock().unwrap(); child_guard.parent = None; } @@ -99,32 +84,32 @@ where } impl SurfaceData { - pub unsafe fn has_a_role(surface: &Resource) -> bool { + pub fn has_a_role(surface: &Resource) -> bool { debug_assert!(surface.is_alive()); - let data_mutex = Self::get_data(surface); + let data_mutex = surface.user_data::>>().unwrap(); let data_guard = data_mutex.lock().unwrap(); ::has_role(&data_guard.role) } /// Check wether a surface has a given role - pub unsafe fn has_role(surface: &Resource) -> bool + pub fn has_role(surface: &Resource) -> bool where R: Role, { debug_assert!(surface.is_alive()); - let data_mutex = Self::get_data(surface); + let data_mutex = surface.user_data::>>().unwrap(); let data_guard = data_mutex.lock().unwrap(); >::has(&data_guard.role) } /// Register that this surface has a role, fails if it already has one - pub unsafe fn give_role(surface: &Resource) -> Result<(), ()> + pub fn give_role(surface: &Resource) -> Result<(), ()> where R: Role, RoleData: Default, { debug_assert!(surface.is_alive()); - let data_mutex = Self::get_data(surface); + let data_mutex = surface.user_data::>>().unwrap(); let mut data_guard = data_mutex.lock().unwrap(); >::set(&mut data_guard.role) } @@ -132,15 +117,12 @@ impl SurfaceData { /// Register that this surface has a role with given data /// /// Fails if it already has one and returns the data - pub unsafe fn give_role_with( - surface: &Resource, - data: RoleData, - ) -> Result<(), RoleData> + pub fn give_role_with(surface: &Resource, data: RoleData) -> Result<(), RoleData> where R: Role, { debug_assert!(surface.is_alive()); - let data_mutex = Self::get_data(surface); + let data_mutex = surface.user_data::>>().unwrap(); let mut data_guard = data_mutex.lock().unwrap(); >::set_with(&mut data_guard.role, data) } @@ -149,24 +131,24 @@ impl SurfaceData { /// /// It is a noop if this surface already didn't have one, but fails if /// the role was "subsurface", it must be removed by the `unset_parent` method. - pub unsafe fn remove_role(surface: &Resource) -> Result + pub fn remove_role(surface: &Resource) -> Result where R: Role, { debug_assert!(surface.is_alive()); - let data_mutex = Self::get_data(surface); + let data_mutex = surface.user_data::>>().unwrap(); let mut data_guard = data_mutex.lock().unwrap(); >::unset(&mut data_guard.role) } /// Access to the role data - pub unsafe fn with_role_data(surface: &Resource, f: F) -> Result + pub fn with_role_data(surface: &Resource, f: F) -> Result where R: Role, F: FnOnce(&mut RoleData) -> T, { debug_assert!(surface.is_alive()); - let data_mutex = Self::get_data(surface); + let data_mutex = surface.user_data::>>().unwrap(); let mut data_guard = data_mutex.lock().unwrap(); let data = >::data_mut(&mut data_guard.role)?; Ok(f(data)) @@ -178,13 +160,13 @@ impl + 'static> SurfaceData /// /// if this surface already has a role, does nothing and fails, otherwise /// its role is now to be a subsurface - pub unsafe fn set_parent(child: &Resource, parent: &Resource) -> Result<(), ()> { + pub fn set_parent(child: &Resource, parent: &Resource) -> Result<(), ()> { debug_assert!(child.is_alive()); debug_assert!(parent.is_alive()); // change child's parent { - let child_mutex = Self::get_data(child); + let child_mutex = child.user_data::>>().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)?; @@ -194,7 +176,7 @@ impl + 'static> SurfaceData // register child to new parent // double scoping is to be robust to have a child be its own parent { - let parent_mutex = Self::get_data(parent); + let parent_mutex = parent.user_data::>>().unwrap(); let mut parent_guard = parent_mutex.lock().unwrap(); parent_guard.children.push(child.clone()) } @@ -204,10 +186,10 @@ impl + 'static> SurfaceData /// Remove a pre-existing parent of this child /// /// Does nothing if it has no parent - pub unsafe fn unset_parent(child: &Resource) { + pub fn unset_parent(child: &Resource) { debug_assert!(child.is_alive()); let old_parent = { - let child_mutex = Self::get_data(child); + let child_mutex = child.user_data::>>().unwrap(); let mut child_guard = child_mutex.lock().unwrap(); let old_parent = child_guard.parent.take(); if old_parent.is_some() { @@ -219,22 +201,22 @@ impl + 'static> SurfaceData }; // unregister from our parent if let Some(old_parent) = old_parent { - let parent_mutex = Self::get_data(&old_parent); + let parent_mutex = old_parent.user_data::>>().unwrap(); let mut parent_guard = parent_mutex.lock().unwrap(); parent_guard.children.retain(|c| !c.equals(child)); } } /// Retrieve the parent surface (if any) of this surface - pub unsafe fn get_parent(child: &Resource) -> Option> { - let child_mutex = Self::get_data(child); + pub fn get_parent(child: &Resource) -> Option> { + let child_mutex = child.user_data::>>().unwrap(); let child_guard = child_mutex.lock().unwrap(); child_guard.parent.as_ref().cloned() } /// Retrieve the parent surface (if any) of this surface - pub unsafe fn get_children(child: &Resource) -> Vec> { - let child_mutex = Self::get_data(child); + pub fn get_children(child: &Resource) -> Vec> { + let child_mutex = child.user_data::>>().unwrap(); let child_guard = child_mutex.lock().unwrap(); child_guard.children.to_vec() } @@ -242,13 +224,13 @@ impl + 'static> SurfaceData /// Reorders a surface relative to one of its sibling /// /// Fails if `relative_to` is not a sibling or parent of `surface`. - pub unsafe fn reorder( + pub fn reorder( surface: &Resource, to: Location, relative_to: &Resource, ) -> Result<(), ()> { let parent = { - let data_mutex = Self::get_data(surface); + let data_mutex = surface.user_data::>>().unwrap(); let data_guard = data_mutex.lock().unwrap(); data_guard.parent.as_ref().cloned().unwrap() }; @@ -266,7 +248,7 @@ impl + 'static> SurfaceData None } - let parent_mutex = Self::get_data(&parent); + let parent_mutex = parent.user_data::>>().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(surface, &parent_guard.children) { @@ -291,11 +273,13 @@ impl SurfaceData { /// /// Note that an internal lock is taken during access of this data, /// so the tree cannot be manipulated at the same time - pub unsafe fn with_data(surface: &Resource, f: F) -> T + pub fn with_data(surface: &Resource, f: F) -> T where F: FnOnce(&mut SurfaceAttributes) -> T, { - let data_mutex = Self::get_data(surface); + let data_mutex = surface + .user_data::>>() + .expect("Accessing the data of foreign surfaces is not supported."); let mut data_guard = data_mutex.lock().unwrap(); f(&mut data_guard.attributes) } @@ -308,12 +292,12 @@ impl SurfaceData { /// /// The callback returns wether the traversal should continue or not. Returning /// false will cause an early-stopping. - pub unsafe fn map_tree(root: &Resource, initial: T, mut f: F, reverse: bool) + pub fn map_tree(root: &Resource, initial: T, mut f: F, reverse: bool) where F: FnMut(&Resource, &mut SurfaceAttributes, &mut R, &T) -> TraversalAction, { // helper function for recursion - unsafe fn map( + fn map( surface: &Resource, root: &Resource, initial: &T, @@ -328,16 +312,11 @@ impl SurfaceData { return true; } - let data_mutex = SurfaceData::::get_data(surface); + let data_mutex = surface.user_data::>>().unwrap(); let mut data_guard = data_mutex.lock().unwrap(); let data_guard = &mut *data_guard; // call the callback on ourselves - match f( - surface, - &mut data_guard.attributes, - &mut data_guard.role, - initial, - ) { + match f(surface, &mut data_guard.attributes, &mut data_guard.role, initial) { TraversalAction::DoChildren(t) => { // loop over children if reverse { @@ -360,16 +339,13 @@ impl SurfaceData { } } - let data_mutex = Self::get_data(root); + let data_mutex = root.user_data::>>().unwrap(); let mut data_guard = data_mutex.lock().unwrap(); let data_guard = &mut *data_guard; // call the callback on ourselves - if let TraversalAction::DoChildren(t) = f( - root, - &mut data_guard.attributes, - &mut data_guard.role, - &initial, - ) { + if let TraversalAction::DoChildren(t) = + f(root, &mut data_guard.attributes, &mut data_guard.role, &initial) + { // loop over children if reverse { for c in data_guard.children.iter().rev() { diff --git a/src/wayland/mod.rs b/src/wayland/mod.rs index ccdb2d9..9fc31f4 100644 --- a/src/wayland/mod.rs +++ b/src/wayland/mod.rs @@ -7,19 +7,13 @@ //! //! - An init function or method will take the event loop as argument and //! insert one or more globals into it. -//! - These functions will return the `Global` handles and, if applicable, -//! a `StateToken` allowing you to access the associated state value in -//! this event loop. //! - If you want to remove a previously inserted global, just call the //! `destroy()` method on the associated `Global`. If you don't plan to //! destroy the global at all, you don't need to bother keeping the //! `Global` around. -//! - You should not remove a state value from the event loop if you have -//! not previously destroyed all the globals using it, otherwise you'll -//! quickly encounter a panic. pub mod compositor; pub mod output; pub mod seat; -pub mod shm; pub mod shell; +pub mod shm; diff --git a/src/wayland/output/mod.rs b/src/wayland/output/mod.rs index 43d5c43..95092a5 100644 --- a/src/wayland/output/mod.rs +++ b/src/wayland/output/mod.rs @@ -22,18 +22,18 @@ //! use wayland_server::protocol::wl_output; //! //! # fn main() { -//! # let (mut display, event_loop) = wayland_server::Display::new(); +//! # let mut event_loop = wayland_server::calloop::EventLoop::<()>::new().unwrap(); +//! # let mut display = wayland_server::Display::new(event_loop.handle()); //! // Create the Output with given name and physical properties //! let (output, _output_global) = Output::new( -//! &mut display, // the display -//! event_loop.token(), // the LoopToken +//! &mut display, // the display //! "output-0".into(), // the name of this output, //! PhysicalProperties { -//! width: 200, // width in mm -//! height: 150, // height in mm, -//! subpixel: wl_output::Subpixel::HorizontalRgb, // subpixel information -//! maker: "Screens Inc".into(), // manufacturer of the monitor -//! model: "Monitor Ultra".into(), // model of the monitor +//! width: 200, // width in mm +//! height: 150, // height in mm, +//! subpixel: wl_output::Subpixel::HorizontalRgb, // subpixel information +//! make: "Screens Inc".into(), // make of the monitor +//! model: "Monitor Ultra".into(), // model of the monitor //! }, //! None // insert a logger here //! ); @@ -53,10 +53,9 @@ use std::sync::{Arc, Mutex}; -use wayland_server::{Display, Global, LoopToken, NewResource, Resource}; -use wayland_server::commons::{downcast_impl, Implementation}; use wayland_server::protocol::wl_output::{Event, Mode as WMode, Request, WlOutput}; pub use wayland_server::protocol::wl_output::{Subpixel, Transform}; +use wayland_server::{Display, Global, NewResource, Resource}; /// An output mode /// @@ -84,8 +83,8 @@ pub struct PhysicalProperties { pub height: i32, /// The subpixel geometry pub subpixel: Subpixel, - /// Textual representation of the manufacturer - pub maker: String, + /// Textual representation of the make + pub make: String, /// Textual representation of the model pub model: String, } @@ -148,27 +147,13 @@ impl Inner { physical_width: self.physical.width, physical_height: self.physical.height, subpixel: self.physical.subpixel, - make: self.physical.maker.clone(), + make: self.physical.make.clone(), model: self.physical.model.clone(), transform: self.transform, }); } } -struct InnerWrapper { - inner: Arc>, -} - -// This implementation does nothing, we just use it as a stable type to downcast the -// implementation in the destructor of wl_output, in order to retrieve the Arc to the -// inner and remove this output from the list -impl Implementation, Request> for InnerWrapper { - fn receive(&mut self, req: Request, _res: Resource) { - // this will break if new variants are added :) - let Request::Release = req; - } -} - /// An output as seen by the clients /// /// This handle is stored in the events loop, and allows you to notify clients @@ -185,7 +170,6 @@ impl Output { /// in case you whish to remove this global in the future. pub fn new( display: &mut Display, - token: LoopToken, name: String, physical: PhysicalProperties, logger: L, @@ -210,25 +194,19 @@ impl Output { preferred_mode: None, })); - let output = Output { - inner: inner.clone(), - }; + let output = Output { inner: inner.clone() }; - let global = display.create_global(&token, 3, move |_version, new_output: NewResource<_>| { + let global = display.create_global(3, move |new_output: NewResource<_>, _version| { let output = new_output.implement( - InnerWrapper { - inner: inner.clone(), + |req, _| { + // this will break if new variants are added :) + let Request::Release = req; }, - Some(|output, boxed_impl| { - let wrapper: Box = - downcast_impl(boxed_impl).unwrap_or_else(|_| unreachable!()); - wrapper - .inner - .lock() - .unwrap() - .instances - .retain(|o| !o.equals(&output)); + Some(|output: Resource| { + let inner = output.user_data::>>().unwrap(); + inner.lock().unwrap().instances.retain(|o| !o.equals(&output)); }), + inner.clone(), ); inner.lock().unwrap().new_global(output); }); diff --git a/src/wayland/seat/keyboard.rs b/src/wayland/seat/keyboard.rs index 1a6d403..07d018b 100644 --- a/src/wayland/seat/keyboard.rs +++ b/src/wayland/seat/keyboard.rs @@ -3,9 +3,11 @@ use std::io::{Error as IoError, Write}; use std::os::unix::io::AsRawFd; use std::sync::{Arc, Mutex}; use tempfile::tempfile; -use wayland_server::{NewResource, Resource}; +use wayland_server::protocol::wl_keyboard::{ + Event, KeyState as WlKeyState, KeymapFormat, Request, WlKeyboard, +}; use wayland_server::protocol::wl_surface::WlSurface; -use wayland_server::protocol::wl_keyboard::{Event, KeyState as WlKeyState, KeymapFormat, Request, WlKeyboard}; +use wayland_server::{NewResource, Resource}; use xkbcommon::xkb; pub use xkbcommon::xkb::{keysyms, Keysym}; @@ -194,18 +196,11 @@ pub(crate) fn create_keyboard_handler( "rules" => rules, "model" => model, "layout" => layout, "variant" => variant, "options" => &options ); - let internal = KbdInternal::new( - rules, - model, - layout, - variant, - options, - repeat_rate, - repeat_delay, - ).map_err(|_| { - debug!(log, "Loading keymap failed"); - Error::BadKeymap - })?; + let internal = KbdInternal::new(rules, model, layout, variant, options, repeat_rate, repeat_delay) + .map_err(|_| { + debug!(log, "Loading keymap failed"); + Error::BadKeymap + })?; info!(log, "Loaded Keymap"; "name" => internal.keymap.layouts().next()); @@ -416,7 +411,7 @@ pub(crate) fn implement_keyboard( let destructor = match handle { Some(h) => { let arc = h.arc.clone(); - Some(move |keyboard: Resource<_>, _| { + Some(move |keyboard: Resource<_>| { arc.internal .lock() .unwrap() @@ -435,5 +430,6 @@ pub(crate) fn implement_keyboard( } }, destructor, + (), ) } diff --git a/src/wayland/seat/mod.rs b/src/wayland/seat/mod.rs index 98478fd..194f541 100644 --- a/src/wayland/seat/mod.rs +++ b/src/wayland/seat/mod.rs @@ -13,13 +13,13 @@ //! use smithay::wayland::seat::Seat; //! //! # fn main(){ -//! # let (mut display, event_loop) = wayland_server::Display::new(); +//! # let mut event_loop = wayland_server::calloop::EventLoop::<()>::new().unwrap(); +//! # let mut display = wayland_server::Display::new(event_loop.handle()); //! // insert the seat: //! let (seat, seat_global) = Seat::new( -//! &mut display, // the display -//! event_loop.token(), // a LoopToken -//! "seat-0".into(), // the name of the seat, will be advertize to clients -//! None /* insert a logger here*/ +//! &mut display, // the display +//! "seat-0".into(), // the name of the seat, will be advertized to clients +//! None // insert a logger here //! ); //! # } //! ``` @@ -40,12 +40,12 @@ //! # use smithay::wayland::seat::Seat; //! # //! # fn main(){ -//! # let (mut display, event_loop) = wayland_server::Display::new(); +//! # let mut event_loop = wayland_server::calloop::EventLoop::<()>::new().unwrap(); +//! # let mut display = wayland_server::Display::new(event_loop.handle()); //! # let (mut seat, seat_global) = Seat::new( //! # &mut display, -//! # event_loop.token(), -//! # "seat-0".into(), // the name of the seat, will be advertize to clients -//! # None /* insert a logger here*/ +//! # "seat-0".into(), +//! # None //! # ); //! let pointer_handle = seat.add_pointer(); //! # } @@ -61,8 +61,8 @@ mod pointer; pub use self::keyboard::{keysyms, Error as KeyboardError, KeyboardHandle, Keysym, ModifiersState}; pub use self::pointer::{PointerAxisHandle, PointerHandle}; -use wayland_server::{Display, Global, LoopToken, NewResource, Resource}; use wayland_server::protocol::wl_seat; +use wayland_server::{Display, Global, NewResource, Resource}; struct Inner { log: ::slog::Logger, @@ -113,12 +113,7 @@ impl Seat { /// You are provided with the state token to retrieve it (allowing /// you to add or remove capabilities from it), and the global handle, /// in case you want to remove it. - pub fn new( - display: &mut Display, - token: LoopToken, - name: String, - logger: L, - ) -> (Seat, Global) + pub fn new(display: &mut Display, name: String, logger: L) -> (Seat, Global) where L: Into>, { @@ -130,10 +125,8 @@ impl Seat { keyboard: None, known_seats: Vec::new(), })); - let seat = Seat { - inner: inner.clone(), - }; - let global = display.create_global(&token, 5, move |_version, new_seat| { + let seat = Seat { inner: inner.clone() }; + let global = display.create_global(5, move |new_seat, _version| { let seat = implement_seat(new_seat, inner.clone()); let mut inner = inner.lock().unwrap(); if seat.version() >= 2 { @@ -277,12 +270,13 @@ fn implement_seat( } } }, - Some(move |seat, _| { + Some(move |seat| { dest_inner .lock() .unwrap() .known_seats .retain(|s| !s.equals(&seat)); }), + (), ) } diff --git a/src/wayland/seat/pointer.rs b/src/wayland/seat/pointer.rs index 47aeabe..b20bb33 100644 --- a/src/wayland/seat/pointer.rs +++ b/src/wayland/seat/pointer.rs @@ -1,7 +1,7 @@ use std::sync::{Arc, Mutex, MutexGuard}; -use wayland_server::{NewResource, Resource}; -use wayland_server::protocol::wl_surface::WlSurface; use wayland_server::protocol::wl_pointer::{Axis, AxisSource, ButtonState, Event, Request, WlPointer}; +use wayland_server::protocol::wl_surface::WlSurface; +use wayland_server::{NewResource, Resource}; // TODO: handle pointer surface role @@ -138,7 +138,7 @@ impl PointerHandle { /// /// A single frame will group multiple scroll events as if they happended in the same instance. /// Dropping the returned `PointerAxisHandle` will group the events together. - pub fn axis(& self) -> PointerAxisHandle { + pub fn axis(&self) -> PointerAxisHandle { PointerAxisHandle { inner: self.inner.lock().unwrap(), } @@ -171,9 +171,7 @@ impl<'a> PointerAxisHandle<'a> { pub fn source(&mut self, source: AxisSource) -> &mut Self { self.inner.with_focused_pointers(|pointer, _| { if pointer.version() >= 5 { - pointer.send(Event::AxisSource { - axis_source: source, - }); + pointer.send(Event::AxisSource { axis_source: source }); } }); self @@ -245,7 +243,7 @@ pub(crate) fn implement_pointer( let destructor = match handle { Some(h) => { let inner = h.inner.clone(); - Some(move |pointer: Resource<_>, _| { + Some(move |pointer: Resource<_>| { inner .lock() .unwrap() @@ -267,5 +265,6 @@ pub(crate) fn implement_pointer( } }, destructor, + (), ) } diff --git a/src/wayland/shell/legacy/mod.rs b/src/wayland/shell/legacy/mod.rs index 7081c8c..93bbb61 100644 --- a/src/wayland/shell/legacy/mod.rs +++ b/src/wayland/shell/legacy/mod.rs @@ -35,7 +35,6 @@ //! use smithay::wayland::compositor::roles::*; //! use smithay::wayland::compositor::CompositorToken; //! use smithay::wayland::shell::legacy::{wl_shell_init, ShellSurfaceRole, ShellRequest}; -//! use wayland_server::{EventLoop, LoopToken}; //! # use wayland_server::protocol::{wl_seat, wl_output}; //! # #[derive(Default)] struct MySurfaceData; //! @@ -51,21 +50,19 @@ //! ); //! //! # fn main() { -//! # let (mut display, event_loop) = wayland_server::Display::new(); +//! # let mut event_loop = wayland_server::calloop::EventLoop::<()>::new().unwrap(); +//! # let mut display = wayland_server::Display::new(event_loop.handle()); //! # let (compositor_token, _, _) = smithay::wayland::compositor::compositor_init::<(), MyRoles, _, _>( //! # &mut display, -//! # event_loop.token(), -//! # |_, _| {}, +//! # |_, _, _| {}, //! # None //! # ); //! let (shell_state, _) = wl_shell_init( //! &mut display, -//! event_loop.token(), //! // token from the compositor implementation //! compositor_token, -//! // your implementation, can also be a strucy implementing the -//! // appropriate Implementation<(), ShellRequest<_, _, _>> trait -//! |event: ShellRequest<_, _, MyShellSurfaceData>, ()| { /* ... */ }, +//! // your implementation +//! |event: ShellRequest<_, _, MyShellSurfaceData>| { /* ... */ }, //! None // put a logger if you want //! ); //! @@ -73,16 +70,15 @@ //! # } //! ``` -use std::rc::Rc; use std::cell::RefCell; +use std::rc::Rc; use std::sync::{Arc, Mutex}; -use wayland::compositor::CompositorToken; use wayland::compositor::roles::Role; +use wayland::compositor::CompositorToken; -use wayland_server::{Display, Global, LoopToken, Resource}; -use wayland_server::commons::Implementation; use wayland_server::protocol::{wl_output, wl_seat, wl_shell, wl_shell_surface, wl_surface}; +use wayland_server::{Display, Global, Resource}; mod wl_handlers; @@ -154,8 +150,7 @@ where } }); if let Ok(true) = ret { - self.shell_surface - .send(wl_shell_surface::Event::Ping { serial }); + self.shell_surface.send(wl_shell_surface::Event::Ping { serial }); Ok(()) } else { Err(()) @@ -318,7 +313,6 @@ where /// Create a new `wl_shell` global pub fn wl_shell_init( display: &mut Display, - ltoken: LoopToken, ctoken: CompositorToken, implementation: Impl, logger: L, @@ -328,23 +322,23 @@ where D: Default + 'static, R: Role> + 'static, L: Into>, - Impl: Implementation<(), ShellRequest>, + Impl: FnMut(ShellRequest) + 'static, { let _log = ::slog_or_stdlog(logger); let implementation = Rc::new(RefCell::new(implementation)); - let ltoken2 = ltoken.clone(); + let dtoken = display.get_token(); let state = Arc::new(Mutex::new(ShellState { known_surfaces: Vec::new(), })); let state2 = state.clone(); - let global = display.create_global(<oken2, 1, move |_version, shell| { + let global = display.create_global(1, move |shell, _version| { self::wl_handlers::implement_shell( shell, - ltoken.clone(), + dtoken.clone(), ctoken, implementation.clone(), state2.clone(), diff --git a/src/wayland/shell/legacy/wl_handlers.rs b/src/wayland/shell/legacy/wl_handlers.rs index c9ac168..8987e65 100644 --- a/src/wayland/shell/legacy/wl_handlers.rs +++ b/src/wayland/shell/legacy/wl_handlers.rs @@ -2,18 +2,17 @@ use std::cell::RefCell; use std::rc::Rc; use std::sync::{Arc, Mutex}; -use wayland_server::{LoopToken, NewResource, Resource}; -use wayland_server::commons::Implementation; use wayland_server::protocol::{wl_shell, wl_shell_surface, wl_surface}; +use wayland_server::{DisplayToken, NewResource, Resource}; -use wayland::compositor::CompositorToken; use wayland::compositor::roles::Role; +use wayland::compositor::CompositorToken; use super::{ShellRequest, ShellState, ShellSurface, ShellSurfaceKind, ShellSurfaceRole}; pub(crate) fn implement_shell( shell: NewResource, - ltoken: LoopToken, + dtoken: DisplayToken, ctoken: CompositorToken, implementation: Rc>, state: Arc>>, @@ -21,9 +20,9 @@ pub(crate) fn implement_shell( U: 'static, D: Default + 'static, R: Role> + 'static, - Impl: Implementation<(), ShellRequest> + 'static, + Impl: FnMut(ShellRequest) + 'static, { - let ltoken2 = ltoken.clone(); + let dtoken2 = dtoken.clone(); shell.implement_nonsend( move |req, shell: Resource<_>| { let wl_shell::Request::GetShellSurface { id, surface } = req; @@ -34,17 +33,14 @@ pub(crate) fn implement_shell( user_data: Default::default(), }; if ctoken.give_role_with(&surface, role_data).is_err() { - shell.post_error( - wl_shell::Error::Role as u32, - "Surface already has a role.".into(), - ); + shell.post_error(wl_shell::Error::Role as u32, "Surface already has a role.".into()); return; } let shell_surface = implement_shell_surface( id, surface, implementation.clone(), - ltoken.clone(), + dtoken.clone(), ctoken, state.clone(), ); @@ -53,23 +49,29 @@ pub(crate) fn implement_shell( .unwrap() .known_surfaces .push(make_handle(&shell_surface, ctoken)); - implementation.borrow_mut().receive( - ShellRequest::NewShellSurface { - surface: make_handle(&shell_surface, ctoken), - }, - (), - ); + let mut imp = implementation.borrow_mut(); + (&mut *imp)(ShellRequest::NewShellSurface { + surface: make_handle(&shell_surface, ctoken), + }); }, - None::, - <oken2, + None::, + (), + &dtoken2, ); } -fn make_handle( +fn make_handle( shell_surface: &Resource, token: CompositorToken, -) -> ShellSurface { - let data = unsafe { &*(shell_surface.get_user_data() as *mut ShellSurfaceUserData) }; +) -> ShellSurface +where + U: 'static, + R: Role> + 'static, + SD: 'static, +{ + let data = shell_surface + .user_data::>() + .unwrap(); ShellSurface { wl_surface: data.surface.clone(), shell_surface: shell_surface.clone(), @@ -78,29 +80,31 @@ fn make_handle( } } -pub(crate) struct ShellSurfaceUserData { +pub(crate) struct ShellSurfaceUserData { surface: Resource, - state: Arc>>, + state: Arc>>, } -fn implement_shell_surface( +fn implement_shell_surface( shell_surface: NewResource, surface: Resource, implementation: Rc>, - ltoken: LoopToken, + dtoken: DisplayToken, ctoken: CompositorToken, - state: Arc>>, + state: Arc>>, ) -> Resource where U: 'static, - D: 'static, - R: Role> + 'static, - Impl: Implementation<(), ShellRequest> + 'static, + SD: 'static, + R: Role> + 'static, + Impl: FnMut(ShellRequest) + 'static, { use self::wl_shell_surface::Request; - let shell_surface = shell_surface.implement_nonsend( + shell_surface.implement_nonsend( move |req, shell_surface: Resource<_>| { - let data = unsafe { &mut *(shell_surface.get_user_data() as *mut ShellSurfaceUserData) }; + let data = shell_surface + .user_data::>() + .unwrap(); let mut user_impl = implementation.borrow_mut(); match req { Request::Pong { serial } => { @@ -112,76 +116,48 @@ where } else { false } - }) - .expect("wl_shell_surface exists but surface has not the right role?"); + }).expect("wl_shell_surface exists but surface has not the right role?"); if valid { - user_impl.receive( - ShellRequest::Pong { - surface: make_handle(&shell_surface, ctoken), - }, - (), - ); + (&mut *user_impl)(ShellRequest::Pong { + surface: make_handle(&shell_surface, ctoken), + }); } } - Request::Move { seat, serial } => user_impl.receive( - ShellRequest::Move { - surface: make_handle(&shell_surface, ctoken), - serial, - seat, - }, - (), - ), - Request::Resize { - seat, + Request::Move { seat, serial } => (&mut *user_impl)(ShellRequest::Move { + surface: make_handle(&shell_surface, ctoken), serial, + seat, + }), + Request::Resize { seat, serial, edges } => (&mut *user_impl)(ShellRequest::Resize { + surface: make_handle(&shell_surface, ctoken), + serial, + seat, edges, - } => user_impl.receive( - ShellRequest::Resize { - surface: make_handle(&shell_surface, ctoken), - serial, - seat, - edges, + }), + Request::SetToplevel => (&mut *user_impl)(ShellRequest::SetKind { + surface: make_handle(&shell_surface, ctoken), + kind: ShellSurfaceKind::Toplevel, + }), + Request::SetTransient { parent, x, y, flags } => (&mut *user_impl)(ShellRequest::SetKind { + surface: make_handle(&shell_surface, ctoken), + kind: ShellSurfaceKind::Transient { + parent, + location: (x, y), + inactive: flags.contains(wl_shell_surface::Transient::Inactive), }, - (), - ), - Request::SetToplevel => user_impl.receive( - ShellRequest::SetKind { - surface: make_handle(&shell_surface, ctoken), - kind: ShellSurfaceKind::Toplevel, - }, - (), - ), - Request::SetTransient { - parent, - x, - y, - flags, - } => user_impl.receive( - ShellRequest::SetKind { - surface: make_handle(&shell_surface, ctoken), - kind: ShellSurfaceKind::Transient { - parent, - location: (x, y), - inactive: flags.contains(wl_shell_surface::Transient::Inactive), - }, - }, - (), - ), + }), Request::SetFullscreen { method, framerate, output, - } => user_impl.receive( - ShellRequest::SetKind { - surface: make_handle(&shell_surface, ctoken), - kind: ShellSurfaceKind::Fullscreen { - method, - framerate, - output, - }, + } => (&mut *user_impl)(ShellRequest::SetKind { + surface: make_handle(&shell_surface, ctoken), + kind: ShellSurfaceKind::Fullscreen { + method, + framerate, + output, }, - (), - ), + }), Request::SetPopup { seat, serial, @@ -189,26 +165,20 @@ where x, y, flags, - } => user_impl.receive( - ShellRequest::SetKind { - surface: make_handle(&shell_surface, ctoken), - kind: ShellSurfaceKind::Popup { - parent, - serial, - seat, - location: (x, y), - inactive: flags.contains(wl_shell_surface::Transient::Inactive), - }, + } => (&mut *user_impl)(ShellRequest::SetKind { + surface: make_handle(&shell_surface, ctoken), + kind: ShellSurfaceKind::Popup { + parent, + serial, + seat, + location: (x, y), + inactive: flags.contains(wl_shell_surface::Transient::Inactive), }, - (), - ), - Request::SetMaximized { output } => user_impl.receive( - ShellRequest::SetKind { - surface: make_handle(&shell_surface, ctoken), - kind: ShellSurfaceKind::Maximized { output }, - }, - (), - ), + }), + Request::SetMaximized { output } => (&mut *user_impl)(ShellRequest::SetKind { + surface: make_handle(&shell_surface, ctoken), + kind: ShellSurfaceKind::Maximized { output }, + }), Request::SetTitle { title } => { ctoken .with_role_data(&data.surface, |data| data.title = title) @@ -221,13 +191,13 @@ where } } }, - Some(|shell_surface: Resource<_>, _| { - let data = - unsafe { Box::from_raw(shell_surface.get_user_data() as *mut ShellSurfaceUserData) }; + Some(|shell_surface: Resource<_>| { + let data = shell_surface + .user_data::>() + .unwrap(); data.state.lock().unwrap().cleanup_surfaces(); }), - <oken, - ); - shell_surface.set_user_data(Box::into_raw(Box::new(ShellSurfaceUserData { surface, state })) as *mut ()); - shell_surface + ShellSurfaceUserData { surface, state }, + &dtoken, + ) } diff --git a/src/wayland/shell/xdg/mod.rs b/src/wayland/shell/xdg/mod.rs index 6a5ec83..6f008d5 100644 --- a/src/wayland/shell/xdg/mod.rs +++ b/src/wayland/shell/xdg/mod.rs @@ -34,7 +34,6 @@ //! use smithay::wayland::compositor::CompositorToken; //! use smithay::wayland::shell::xdg::{xdg_shell_init, XdgSurfaceRole, XdgRequest}; //! use wayland_protocols::unstable::xdg_shell::v6::server::zxdg_shell_v6::ZxdgShellV6; -//! use wayland_server::{EventLoop, LoopToken}; //! # use wayland_server::protocol::{wl_seat, wl_output}; //! # #[derive(Default)] struct MySurfaceData; //! @@ -50,21 +49,19 @@ //! } //! //! # fn main() { -//! # let (mut display, event_loop) = wayland_server::Display::new(); +//! # let mut event_loop = wayland_server::calloop::EventLoop::<()>::new().unwrap(); +//! # let mut display = wayland_server::Display::new(event_loop.handle()); //! # let (compositor_token, _, _) = smithay::wayland::compositor::compositor_init::<(), MyRoles, _, _>( //! # &mut display, -//! # event_loop.token(), -//! # |_, _| {}, +//! # |_, _, _| {}, //! # None //! # ); //! let (shell_state, _, _) = xdg_shell_init( //! &mut display, -//! event_loop.token(), //! // token from the compositor implementation //! compositor_token, -//! // your implementation, can also be a strucy implementing the -//! // appropriate Implementation<(), XdgRequest<_, _, _>> trait -//! |event: XdgRequest<_, _, MyShellData>, ()| { /* ... */ }, +//! // your implementation +//! |event: XdgRequest<_, _, MyShellData>| { /* ... */ }, //! None // put a logger if you want //! ); //! @@ -92,14 +89,16 @@ use std::cell::RefCell; use std::rc::Rc; use std::sync::{Arc, Mutex}; use utils::Rectangle; -use wayland::compositor::CompositorToken; use wayland::compositor::roles::Role; -use wayland_protocols::xdg_shell::server::{xdg_popup, xdg_positioner, xdg_surface, xdg_toplevel, xdg_wm_base}; -use wayland_protocols::unstable::xdg_shell::v6::server::{zxdg_popup_v6, zxdg_shell_v6, zxdg_surface_v6, - zxdg_toplevel_v6}; -use wayland_server::{Display, Global, LoopToken, Resource}; -use wayland_server::commons::Implementation; +use wayland::compositor::CompositorToken; +use wayland_protocols::unstable::xdg_shell::v6::server::{ + zxdg_popup_v6, zxdg_shell_v6, zxdg_surface_v6, zxdg_toplevel_v6, +}; +use wayland_protocols::xdg_shell::server::{ + xdg_popup, xdg_positioner, xdg_surface, xdg_toplevel, xdg_wm_base, +}; use wayland_server::protocol::{wl_output, wl_seat, wl_surface}; +use wayland_server::{Display, DisplayToken, Global, Resource}; // handlers for the xdg_shell protocol mod xdg_handlers; @@ -254,20 +253,20 @@ impl Default for XdgSurfacePendingState { } } -pub(crate) struct ShellImplementation { +pub(crate) struct ShellData { log: ::slog::Logger, compositor_token: CompositorToken, - loop_token: LoopToken, - user_impl: Rc>>>, + display_token: DisplayToken, + user_impl: Rc)>>, shell_state: Arc>>, } -impl Clone for ShellImplementation { +impl Clone for ShellData { fn clone(&self) -> Self { - ShellImplementation { + ShellData { log: self.log.clone(), compositor_token: self.compositor_token, - loop_token: self.loop_token.clone(), + display_token: self.display_token.clone(), user_impl: self.user_impl.clone(), shell_state: self.shell_state.clone(), } @@ -277,7 +276,6 @@ impl Clone for ShellImplementation { /// Create a new `xdg_shell` globals pub fn xdg_shell_init( display: &mut Display, - ltoken: LoopToken, ctoken: CompositorToken, implementation: Impl, logger: L, @@ -291,7 +289,7 @@ where R: Role + 'static, SD: Default + 'static, L: Into>, - Impl: Implementation<(), XdgRequest>, + Impl: FnMut(XdgRequest) + 'static, { let log = ::slog_or_stdlog(logger); let shell_state = Arc::new(Mutex::new(ShellState { @@ -299,22 +297,22 @@ where known_popups: Vec::new(), })); - let shell_impl = ShellImplementation { + let shell_data = ShellData { log: log.new(o!("smithay_module" => "xdg_shell_handler")), - loop_token: ltoken.clone(), + display_token: display.get_token(), compositor_token: ctoken, user_impl: Rc::new(RefCell::new(implementation)), shell_state: shell_state.clone(), }; - let shell_impl_z = shell_impl.clone(); + let shell_data_z = shell_data.clone(); - let xdg_shell_global = display.create_global(<oken, 1, move |_version, shell| { - self::xdg_handlers::implement_wm_base(shell, &shell_impl); + let xdg_shell_global = display.create_global(1, move |shell, _version| { + self::xdg_handlers::implement_wm_base(shell, &shell_data); }); - let zxdgv6_shell_global = display.create_global(<oken, 1, move |_version, shell| { - self::zxdgv6_handlers::implement_shell(shell, &shell_impl_z); + let zxdgv6_shell_global = display.create_global(1, move |shell, _version| { + self::zxdgv6_handlers::implement_shell(shell, &shell_data_z); }); (shell_state, xdg_shell_global, zxdgv6_shell_global) @@ -377,12 +375,18 @@ fn make_shell_client_data() -> ShellClientData { /// /// You can use this handle to access a storage for any /// client-specific data you wish to associate with it. -pub struct ShellClient { +pub struct ShellClient { kind: ShellClientKind, + _token: CompositorToken, _data: ::std::marker::PhantomData<*mut SD>, } -impl ShellClient { +impl ShellClient +where + U: 'static, + R: Role + 'static, + SD: 'static, +{ /// Is the shell client represented by this handle still connected? pub fn alive(&self) -> bool { match self.kind { @@ -416,9 +420,10 @@ impl ShellClient { } match self.kind { ShellClientKind::Xdg(ref shell) => { - let mutex = - unsafe { &*(shell.get_user_data() as *mut self::xdg_handlers::ShellUserData) }; - let mut guard = mutex.lock().unwrap(); + let user_data = shell + .user_data::>() + .unwrap(); + let mut guard = user_data.client_data.lock().unwrap(); if guard.pending_ping == 0 { return Err(()); } @@ -426,9 +431,10 @@ impl ShellClient { shell.send(xdg_wm_base::Event::Ping { serial }); } ShellClientKind::ZxdgV6(ref shell) => { - let mutex = - unsafe { &*(shell.get_user_data() as *mut self::zxdgv6_handlers::ShellUserData) }; - let mut guard = mutex.lock().unwrap(); + let user_data = shell + .user_data::>() + .unwrap(); + let mut guard = user_data.client_data.lock().unwrap(); if guard.pending_ping == 0 { return Err(()); } @@ -449,15 +455,17 @@ impl ShellClient { } match self.kind { ShellClientKind::Xdg(ref shell) => { - let mutex = - unsafe { &*(shell.get_user_data() as *mut self::xdg_handlers::ShellUserData) }; - let mut guard = mutex.lock().unwrap(); + let data = shell + .user_data::>() + .unwrap(); + let mut guard = data.client_data.lock().unwrap(); Ok(f(&mut guard.data)) } ShellClientKind::ZxdgV6(ref shell) => { - let mutex = - unsafe { &*(shell.get_user_data() as *mut self::zxdgv6_handlers::ShellUserData) }; - let mut guard = mutex.lock().unwrap(); + let data = shell + .user_data::>() + .unwrap(); + let mut guard = data.client_data.lock().unwrap(); Ok(f(&mut guard.data)) } } @@ -500,26 +508,29 @@ where /// Retrieve the shell client owning this toplevel surface /// /// Returns `None` if the surface does actually no longer exist. - pub fn client(&self) -> Option> { + pub fn client(&self) -> Option> { if !self.alive() { return None; } let shell = match self.shell_surface { ToplevelKind::Xdg(ref s) => { - let &(_, ref shell, _) = - unsafe { &*(s.get_user_data() as *mut self::xdg_handlers::ShellSurfaceUserData) }; - ShellClientKind::Xdg(shell.clone()) + let data = s + .user_data::>() + .unwrap(); + ShellClientKind::Xdg(data.wm_base.clone()) } ToplevelKind::ZxdgV6(ref s) => { - let &(_, ref shell, _) = - unsafe { &*(s.get_user_data() as *mut self::zxdgv6_handlers::ShellSurfaceUserData) }; - ShellClientKind::ZxdgV6(shell.clone()) + let data = s + .user_data::>() + .unwrap(); + ShellClientKind::ZxdgV6(data.shell.clone()) } }; Some(ShellClient { kind: shell, + _token: self.token, _data: ::std::marker::PhantomData, }) } @@ -532,8 +543,8 @@ where return; } match self.shell_surface { - ToplevelKind::Xdg(ref s) => self::xdg_handlers::send_toplevel_configure(self.token, s, cfg), - ToplevelKind::ZxdgV6(ref s) => self::zxdgv6_handlers::send_toplevel_configure(self.token, s, cfg), + ToplevelKind::Xdg(ref s) => self::xdg_handlers::send_toplevel_configure::(s, cfg), + ToplevelKind::ZxdgV6(ref s) => self::zxdgv6_handlers::send_toplevel_configure::(s, cfg), } } @@ -549,25 +560,26 @@ where if !self.alive() { return false; } - let configured = self.token + let configured = self + .token .with_role_data::(&self.wl_surface, |data| data.configured) .expect("A shell surface object exists but the surface does not have the shell_surface role ?!"); if !configured { match self.shell_surface { ToplevelKind::Xdg(ref s) => { - let ptr = s.get_user_data(); - let &(_, _, ref xdg_surface) = - unsafe { &*(ptr as *mut self::xdg_handlers::ShellSurfaceUserData) }; - xdg_surface.post_error( + let data = s + .user_data::>() + .unwrap(); + data.xdg_surface.post_error( xdg_surface::Error::NotConstructed as u32, "Surface has not been configured yet.".into(), ); } ToplevelKind::ZxdgV6(ref s) => { - let ptr = s.get_user_data(); - let &(_, _, ref xdg_surface) = - unsafe { &*(ptr as *mut self::zxdgv6_handlers::ShellSurfaceUserData) }; - xdg_surface.post_error( + let data = s + .user_data::>() + .unwrap(); + data.xdg_surface.post_error( zxdg_surface_v6::Error::NotConstructed as u32, "Surface has not been configured yet.".into(), ); @@ -607,8 +619,7 @@ where .with_role_data::(&self.wl_surface, |data| match data.pending_state { XdgSurfacePendingState::Toplevel(ref state) => Some(state.clone()), _ => None, - }) - .ok() + }).ok() .and_then(|x| x) } } @@ -652,26 +663,29 @@ where /// Retrieve the shell client owning this popup surface /// /// Returns `None` if the surface does actually no longer exist. - pub fn client(&self) -> Option> { + pub fn client(&self) -> Option> { if !self.alive() { return None; } let shell = match self.shell_surface { PopupKind::Xdg(ref p) => { - let &(_, ref shell, _) = - unsafe { &*(p.get_user_data() as *mut self::xdg_handlers::ShellSurfaceUserData) }; - ShellClientKind::Xdg(shell.clone()) + let data = p + .user_data::>() + .unwrap(); + ShellClientKind::Xdg(data.wm_base.clone()) } PopupKind::ZxdgV6(ref p) => { - let &(_, ref shell, _) = - unsafe { &*(p.get_user_data() as *mut self::zxdgv6_handlers::ShellSurfaceUserData) }; - ShellClientKind::ZxdgV6(shell.clone()) + let data = p + .user_data::>() + .unwrap(); + ShellClientKind::ZxdgV6(data.shell.clone()) } }; Some(ShellClient { kind: shell, + _token: self.token, _data: ::std::marker::PhantomData, }) } @@ -685,10 +699,10 @@ where } match self.shell_surface { PopupKind::Xdg(ref p) => { - self::xdg_handlers::send_popup_configure(self.token, p, cfg); + self::xdg_handlers::send_popup_configure::(p, cfg); } PopupKind::ZxdgV6(ref p) => { - self::zxdgv6_handlers::send_popup_configure(self.token, p, cfg); + self::zxdgv6_handlers::send_popup_configure::(p, cfg); } } } @@ -705,25 +719,26 @@ where if !self.alive() { return false; } - let configured = self.token + let configured = self + .token .with_role_data::(&self.wl_surface, |data| data.configured) .expect("A shell surface object exists but the surface does not have the shell_surface role ?!"); if !configured { match self.shell_surface { PopupKind::Xdg(ref s) => { - let ptr = s.get_user_data(); - let &(_, _, ref xdg_surface) = - unsafe { &*(ptr as *mut self::xdg_handlers::ShellSurfaceUserData) }; - xdg_surface.post_error( + let data = s + .user_data::>() + .unwrap(); + data.xdg_surface.post_error( xdg_surface::Error::NotConstructed as u32, "Surface has not been confgured yet.".into(), ); } PopupKind::ZxdgV6(ref s) => { - let ptr = s.get_user_data(); - let &(_, _, ref xdg_surface) = - unsafe { &*(ptr as *mut self::zxdgv6_handlers::ShellSurfaceUserData) }; - xdg_surface.post_error( + let data = s + .user_data::>() + .unwrap(); + data.xdg_surface.post_error( zxdg_surface_v6::Error::NotConstructed as u32, "Surface has not been confgured yet.".into(), ); @@ -766,8 +781,7 @@ where .with_role_data::(&self.wl_surface, |data| match data.pending_state { XdgSurfacePendingState::Popup(ref state) => Some(state.clone()), _ => None, - }) - .ok() + }).ok() .and_then(|x| x) } } @@ -814,7 +828,7 @@ pub enum XdgRequest { /// A new shell client was instanciated NewClient { /// the client - client: ShellClient, + client: ShellClient, }, /// The pong for a pending ping of this shell client was received /// @@ -822,7 +836,7 @@ pub enum XdgRequest { /// from the pending ping. ClientPong { /// the client - client: ShellClient, + client: ShellClient, }, /// A new toplevel surface was created /// diff --git a/src/wayland/shell/xdg/xdg_handlers.rs b/src/wayland/shell/xdg/xdg_handlers.rs index fc65837..44fe735 100644 --- a/src/wayland/shell/xdg/xdg_handlers.rs +++ b/src/wayland/shell/xdg/xdg_handlers.rs @@ -1,18 +1,25 @@ -use super::{make_shell_client_data, PopupConfigure, PopupKind, PopupState, PositionerState, ShellClient, - ShellClientData, ShellImplementation, ToplevelConfigure, ToplevelKind, ToplevelState, - XdgRequest, XdgSurfacePendingState, XdgSurfaceRole}; +use std::cell::RefCell; use std::sync::Mutex; -use utils::Rectangle; -use wayland::compositor::CompositorToken; + use wayland::compositor::roles::*; -use wayland_protocols::xdg_shell::server::{xdg_popup, xdg_positioner, xdg_surface, xdg_toplevel, xdg_wm_base}; -use wayland_server::{LoopToken, NewResource, Resource}; -use wayland_server::commons::{downcast_impl, Implementation}; +use wayland::compositor::CompositorToken; +use wayland_protocols::xdg_shell::server::{ + xdg_popup, xdg_positioner, xdg_surface, xdg_toplevel, xdg_wm_base, +}; use wayland_server::protocol::wl_surface; +use wayland_server::{DisplayToken, NewResource, Resource}; + +use utils::Rectangle; + +use super::{ + make_shell_client_data, PopupConfigure, PopupKind, PopupState, PositionerState, ShellClient, + ShellClientData, ShellData, ToplevelConfigure, ToplevelKind, ToplevelState, XdgRequest, + XdgSurfacePendingState, XdgSurfaceRole, +}; pub(crate) fn implement_wm_base( shell: NewResource, - implem: &ShellImplementation, + shell_data: &ShellData, ) -> Resource where U: 'static, @@ -20,18 +27,18 @@ where SD: Default + 'static, { let shell = shell.implement_nonsend( - implem.clone(), - Some(|shell, _| destroy_shell::(&shell)), - &implem.loop_token, - ); - shell.set_user_data(Box::into_raw(Box::new(Mutex::new(make_shell_client_data::()))) as *mut _); - let mut user_impl = implem.user_impl.borrow_mut(); - user_impl.receive( - XdgRequest::NewClient { - client: make_shell_client(&shell), + wm_implementation::, + None::, + ShellUserData { + shell_data: shell_data.clone(), + client_data: Mutex::new(make_shell_client_data::()), }, - (), + &shell_data.display_token, ); + let mut user_impl = shell_data.user_impl.borrow_mut(); + (&mut *user_impl)(XdgRequest::NewClient { + client: make_shell_client(&shell, shell_data.compositor_token), + }); shell } @@ -39,83 +46,81 @@ where * xdg_shell */ -pub(crate) type ShellUserData = Mutex>; - -fn destroy_shell(shell: &Resource) { - let ptr = shell.get_user_data(); - shell.set_user_data(::std::ptr::null_mut()); - let data = unsafe { Box::from_raw(ptr as *mut ShellUserData) }; - // explicit call to drop to not forget what we're doing here - ::std::mem::drop(data); +pub(crate) struct ShellUserData { + shell_data: ShellData, + pub(crate) client_data: Mutex>, } -pub(crate) fn make_shell_client(resource: &Resource) -> ShellClient { +pub(crate) fn make_shell_client( + resource: &Resource, + token: CompositorToken, +) -> ShellClient { ShellClient { kind: super::ShellClientKind::Xdg(resource.clone()), + _token: token, _data: ::std::marker::PhantomData, } } -impl Implementation, xdg_wm_base::Request> - for ShellImplementation +fn wm_implementation(request: xdg_wm_base::Request, shell: Resource) where U: 'static, R: Role + 'static, SD: 'static, { - fn receive(&mut self, request: xdg_wm_base::Request, shell: Resource) { - match request { - xdg_wm_base::Request::Destroy => { - // all is handled by destructor - } - xdg_wm_base::Request::CreatePositioner { id } => { - implement_positioner(id, &self.loop_token); - } - xdg_wm_base::Request::GetXdgSurface { id, surface } => { - let role_data = XdgSurfaceRole { - pending_state: XdgSurfacePendingState::None, - window_geometry: None, - pending_configures: Vec::new(), - configured: false, - }; - if self.compositor_token - .give_role_with(&surface, role_data) - .is_err() - { - shell.post_error( - xdg_wm_base::Error::Role as u32, - "Surface already has a role.".into(), - ); - return; - } - let xdg_surface = id.implement_nonsend( - self.clone(), - Some(destroy_surface::), - &self.loop_token, + let data = shell.user_data::>().unwrap(); + match request { + xdg_wm_base::Request::Destroy => { + // all is handled by destructor + } + xdg_wm_base::Request::CreatePositioner { id } => { + implement_positioner(id, &data.shell_data.display_token); + } + xdg_wm_base::Request::GetXdgSurface { id, surface } => { + let role_data = XdgSurfaceRole { + pending_state: XdgSurfacePendingState::None, + window_geometry: None, + pending_configures: Vec::new(), + configured: false, + }; + if data + .shell_data + .compositor_token + .give_role_with(&surface, role_data) + .is_err() + { + shell.post_error( + xdg_wm_base::Error::Role as u32, + "Surface already has a role.".into(), ); - xdg_surface - .set_user_data(Box::into_raw(Box::new((surface.clone(), shell.clone()))) as *mut _); + return; } - xdg_wm_base::Request::Pong { serial } => { - let valid = { - let mutex = unsafe { &*(shell.get_user_data() as *mut ShellUserData) }; - let mut guard = mutex.lock().unwrap(); - if guard.pending_ping == serial { - guard.pending_ping = 0; - true - } else { - false - } - }; - if valid { - let mut user_impl = self.user_impl.borrow_mut(); - user_impl.receive( - XdgRequest::ClientPong { - client: make_shell_client(&shell), - }, - (), - ); + id.implement_nonsend( + xdg_surface_implementation::, + Some(destroy_surface::), + XdgSurfaceUserData { + shell_data: data.shell_data.clone(), + wl_surface: surface, + wm_base: shell.clone(), + }, + &data.shell_data.display_token, + ); + } + xdg_wm_base::Request::Pong { serial } => { + let valid = { + let mut guard = data.client_data.lock().unwrap(); + if guard.pending_ping == serial { + guard.pending_ping = 0; + true + } else { + false } + }; + if valid { + let mut user_impl = data.shell_data.user_impl.borrow_mut(); + (&mut *user_impl)(XdgRequest::ClientPong { + client: make_shell_client(&shell, data.shell_data.compositor_token), + }); } } } @@ -125,23 +130,14 @@ where * xdg_positioner */ -fn destroy_positioner(positioner: &Resource) { - let ptr = positioner.get_user_data(); - positioner.set_user_data(::std::ptr::null_mut()); - // drop the PositionerState - let surface = unsafe { Box::from_raw(ptr as *mut PositionerState) }; - // explicit call to drop to not forget what we're doing here - ::std::mem::drop(surface); -} - fn implement_positioner( positioner: NewResource, - token: &LoopToken, + token: &DisplayToken, ) -> Resource { - let positioner = positioner.implement_nonsend( + positioner.implement_nonsend( |request, positioner: Resource<_>| { - let ptr = positioner.get_user_data(); - let state = unsafe { &mut *(ptr as *mut PositionerState) }; + let mutex = positioner.user_data::>().unwrap(); + let mut state = mutex.borrow_mut(); match request { xdg_positioner::Request::Destroy => { // handled by destructor @@ -156,24 +152,14 @@ fn implement_positioner( state.rect_size = (width, height); } } - xdg_positioner::Request::SetAnchorRect { - x, - y, - width, - height, - } => { + xdg_positioner::Request::SetAnchorRect { x, y, width, height } => { if width < 1 || height < 1 { positioner.post_error( xdg_positioner::Error::InvalidInput as u32, "Invalid size for positioner's anchor rectangle.".into(), ); } else { - state.anchor_rect = Rectangle { - x, - y, - width, - height, - }; + state.anchor_rect = Rectangle { x, y, width, height }; } } xdg_positioner::Request::SetAnchor { anchor } => { @@ -194,183 +180,166 @@ fn implement_positioner( } } }, - Some(|positioner, _| destroy_positioner(&positioner)), + None::, + RefCell::new(PositionerState::new()), token, - ); - let data = PositionerState::new(); - positioner.set_user_data(Box::into_raw(Box::new(data)) as *mut _); - positioner + ) } /* * xdg_surface */ -type XdgSurfaceUserData = ( - Resource, - Resource, -); - -fn destroy_surface( - surface: Resource, - implem: Box, xdg_surface::Request>>, -) where - U: 'static, - R: Role + 'static, - SD: 'static, -{ - let implem: ShellImplementation = *downcast_impl(implem).unwrap_or_else(|_| unreachable!()); - let ptr = surface.get_user_data(); - surface.set_user_data(::std::ptr::null_mut()); - // take back ownership of the userdata - let data = unsafe { Box::from_raw(ptr as *mut XdgSurfaceUserData) }; - if !data.0.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 - // disconnecting client), ignore the protocol check. - return; - } - implem - .compositor_token - .with_role_data::(&data.0, |rdata| { - if let XdgSurfacePendingState::None = rdata.pending_state { - // all is good - } else { - data.1.post_error( - xdg_wm_base::Error::Role as u32, - "xdg_surface was destroyed before its role object".into(), - ); - } - }) - .expect("xdg_surface exists but surface has not shell_surface role?!"); +struct XdgSurfaceUserData { + shell_data: ShellData, + wl_surface: Resource, + wm_base: Resource, } -impl Implementation, xdg_surface::Request> - for ShellImplementation +fn destroy_surface(surface: Resource) where U: 'static, R: Role + 'static, SD: 'static, { - fn receive(&mut self, request: xdg_surface::Request, xdg_surface: Resource) { - let ptr = xdg_surface.get_user_data(); - let &(ref surface, ref shell) = unsafe { &*(ptr as *mut XdgSurfaceUserData) }; - match request { - xdg_surface::Request::Destroy => { - // all is handled by our destructor - } - xdg_surface::Request::GetToplevel { id } => { - self.compositor_token - .with_role_data::(surface, |data| { - data.pending_state = XdgSurfacePendingState::Toplevel(ToplevelState { - parent: None, - title: String::new(), - app_id: String::new(), - min_size: (0, 0), - max_size: (0, 0), - }); - }) - .expect("xdg_surface exists but surface has not shell_surface role?!"); - let toplevel = id.implement_nonsend( - self.clone(), - Some(destroy_toplevel::), - &self.loop_token, + let data = surface.user_data::>().unwrap(); + if !data.wl_surface.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 + // disconnecting client), ignore the protocol check. + return; + } + data.shell_data + .compositor_token + .with_role_data::(&data.wl_surface, |rdata| { + if let XdgSurfacePendingState::None = rdata.pending_state { + // all is good + } else { + data.wm_base.post_error( + xdg_wm_base::Error::Role as u32, + "xdg_surface was destroyed before its role object".into(), ); - toplevel.set_user_data(Box::into_raw(Box::new(( - surface.clone(), - shell.clone(), - xdg_surface.clone(), - ))) as *mut _); - - self.shell_state - .lock() - .unwrap() - .known_toplevels - .push(make_toplevel_handle(self.compositor_token, &toplevel)); - - let handle = make_toplevel_handle(self.compositor_token, &toplevel); - let mut user_impl = self.user_impl.borrow_mut(); - user_impl.receive(XdgRequest::NewToplevel { surface: handle }, ()); } - xdg_surface::Request::GetPopup { - id, - parent, - positioner, - } => { - let positioner_data = unsafe { &*(positioner.get_user_data() as *const PositionerState) }; + }).expect("xdg_surface exists but surface has not shell_surface role?!"); +} - let parent_surface = parent.map(|parent| { - let parent_ptr = parent.get_user_data(); - let &(ref parent_surface, _) = unsafe { &*(parent_ptr as *mut XdgSurfaceUserData) }; - parent_surface.clone() - }); - self.compositor_token - .with_role_data::(surface, |data| { - data.pending_state = XdgSurfacePendingState::Popup(PopupState { - parent: parent_surface, - positioner: positioner_data.clone(), - }); - }) - .expect("xdg_surface exists but surface has not shell_surface role?!"); - let popup = id.implement_nonsend( - self.clone(), - Some(destroy_popup::), - &self.loop_token, - ); - popup.set_user_data(Box::into_raw(Box::new(( - surface.clone(), - shell.clone(), - xdg_surface.clone(), - ))) as *mut _); +fn xdg_surface_implementation( + request: xdg_surface::Request, + xdg_surface: Resource, +) where + U: 'static, + R: Role + 'static, + SD: 'static, +{ + let data = xdg_surface.user_data::>().unwrap(); + match request { + xdg_surface::Request::Destroy => { + // all is handled by our destructor + } + xdg_surface::Request::GetToplevel { id } => { + data.shell_data + .compositor_token + .with_role_data::(&data.wl_surface, |data| { + data.pending_state = XdgSurfacePendingState::Toplevel(ToplevelState { + parent: None, + title: String::new(), + app_id: String::new(), + min_size: (0, 0), + max_size: (0, 0), + }); + }).expect("xdg_surface exists but surface has not shell_surface role?!"); + let toplevel = id.implement_nonsend( + toplevel_implementation::, + Some(destroy_toplevel::), + ShellSurfaceUserData { + shell_data: data.shell_data.clone(), + wl_surface: data.wl_surface.clone(), + xdg_surface: xdg_surface.clone(), + wm_base: data.wm_base.clone(), + }, + &data.shell_data.display_token, + ); - self.shell_state - .lock() - .unwrap() - .known_popups - .push(make_popup_handle(self.compositor_token, &popup)); + data.shell_data + .shell_state + .lock() + .unwrap() + .known_toplevels + .push(make_toplevel_handle(&toplevel)); - let handle = make_popup_handle(self.compositor_token, &popup); - let mut user_impl = self.user_impl.borrow_mut(); - user_impl.receive(XdgRequest::NewPopup { surface: handle }, ()); - } - xdg_surface::Request::SetWindowGeometry { - x, - y, - width, - height, - } => { - self.compositor_token - .with_role_data::(surface, |data| { - data.window_geometry = Some(Rectangle { - x, - y, - width, - height, - }); - }) - .expect("xdg_surface exists but surface has not shell_surface role?!"); - } - xdg_surface::Request::AckConfigure { serial } => { - self.compositor_token - .with_role_data::(surface, |data| { - let mut found = false; - data.pending_configures.retain(|&s| { - if s == serial { - found = true; - } - s > serial - }); - if !found { - // client responded to a non-existing configure - shell.post_error( - xdg_wm_base::Error::InvalidSurfaceState as u32, - format!("Wrong configure serial: {}", serial), - ); + let handle = make_toplevel_handle(&toplevel); + let mut user_impl = data.shell_data.user_impl.borrow_mut(); + (&mut *user_impl)(XdgRequest::NewToplevel { surface: handle }); + } + xdg_surface::Request::GetPopup { + id, + parent, + positioner, + } => { + let positioner_data = positioner.user_data::>().unwrap(); + + let parent_surface = parent.map(|parent| { + let parent_data = parent.user_data::>().unwrap(); + parent_data.wl_surface.clone() + }); + data.shell_data + .compositor_token + .with_role_data::(&data.wl_surface, |data| { + data.pending_state = XdgSurfacePendingState::Popup(PopupState { + parent: parent_surface, + positioner: positioner_data.borrow().clone(), + }); + }).expect("xdg_surface exists but surface has not shell_surface role?!"); + let popup = id.implement_nonsend( + xg_popup_implementation::, + Some(destroy_popup::), + ShellSurfaceUserData { + shell_data: data.shell_data.clone(), + wl_surface: data.wl_surface.clone(), + xdg_surface: xdg_surface.clone(), + wm_base: data.wm_base.clone(), + }, + &data.shell_data.display_token, + ); + + data.shell_data + .shell_state + .lock() + .unwrap() + .known_popups + .push(make_popup_handle(&popup)); + + let handle = make_popup_handle(&popup); + let mut user_impl = data.shell_data.user_impl.borrow_mut(); + (&mut *user_impl)(XdgRequest::NewPopup { surface: handle }); + } + xdg_surface::Request::SetWindowGeometry { x, y, width, height } => { + data.shell_data + .compositor_token + .with_role_data::(&data.wl_surface, |data| { + data.window_geometry = Some(Rectangle { x, y, width, height }); + }).expect("xdg_surface exists but surface has not shell_surface role?!"); + } + xdg_surface::Request::AckConfigure { serial } => { + data.shell_data + .compositor_token + .with_role_data::(&data.wl_surface, |role_data| { + let mut found = false; + role_data.pending_configures.retain(|&s| { + if s == serial { + found = true; } - data.configured = true; - }) - .expect("xdg_surface exists but surface has not shell_surface role?!"); - } + s > serial + }); + if !found { + // client responded to a non-existing configure + data.wm_base.post_error( + xdg_wm_base::Error::InvalidSurfaceState as u32, + format!("Wrong configure serial: {}", serial), + ); + } + role_data.configured = true; + }).expect("xdg_surface exists but surface has not shell_surface role?!"); } } } @@ -379,15 +348,16 @@ where * xdg_toplevel */ -pub type ShellSurfaceUserData = ( - Resource, - Resource, - Resource, -); +pub(crate) struct ShellSurfaceUserData { + pub(crate) shell_data: ShellData, + pub(crate) wl_surface: Resource, + pub(crate) wm_base: Resource, + pub(crate) xdg_surface: Resource, +} // Utility functions allowing to factor out a lot of the upcoming logic fn with_surface_toplevel_data( - implem: &ShellImplementation, + shell_data: &ShellData, toplevel: &Resource, f: F, ) where @@ -396,27 +366,24 @@ fn with_surface_toplevel_data( SD: 'static, F: FnOnce(&mut ToplevelState), { - let ptr = toplevel.get_user_data(); - let &(ref surface, _, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) }; - implem + let toplevel_data = toplevel.user_data::>().unwrap(); + shell_data .compositor_token - .with_role_data::(surface, |data| match data.pending_state { + .with_role_data::(&toplevel_data.wl_surface, |data| match data.pending_state { XdgSurfacePendingState::Toplevel(ref mut toplevel_data) => f(toplevel_data), _ => unreachable!(), - }) - .expect("xdg_toplevel exists but surface has not shell_surface role?!"); + }).expect("xdg_toplevel exists but surface has not shell_surface role?!"); } -pub fn send_toplevel_configure( - token: CompositorToken, +pub fn send_toplevel_configure( resource: &Resource, configure: ToplevelConfigure, ) where U: 'static, R: Role + 'static, + SD: 'static, { - let &(ref surface, _, ref shell_surface) = - unsafe { &*(resource.get_user_data() as *mut ShellSurfaceUserData) }; + let data = resource.user_data::>().unwrap(); let (width, height) = configure.size.unwrap_or((0, 0)); // convert the Vec (which is really a Vec) into Vec let states = { @@ -433,177 +400,153 @@ pub fn send_toplevel_configure( height, states, }); - shell_surface.send(xdg_surface::Event::Configure { serial }); + data.xdg_surface.send(xdg_surface::Event::Configure { serial }); // Add the configure as pending - token - .with_role_data::(surface, |data| data.pending_configures.push(serial)) + data.shell_data + .compositor_token + .with_role_data::(&data.wl_surface, |data| data.pending_configures.push(serial)) .expect("xdg_toplevel exists but surface has not shell_surface role?!"); } -fn make_toplevel_handle( - token: CompositorToken, +fn make_toplevel_handle( resource: &Resource, ) -> super::ToplevelSurface { - let ptr = resource.get_user_data(); - let &(ref wl_surface, _, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) }; + let data = resource.user_data::>().unwrap(); super::ToplevelSurface { - wl_surface: wl_surface.clone(), + wl_surface: data.wl_surface.clone(), shell_surface: ToplevelKind::Xdg(resource.clone()), - token, + token: data.shell_data.compositor_token, _shell_data: ::std::marker::PhantomData, } } -impl Implementation, xdg_toplevel::Request> - for ShellImplementation -where - U: 'static, - R: Role + 'static, - SD: 'static, -{ - fn receive(&mut self, request: xdg_toplevel::Request, toplevel: Resource) { - match request { - xdg_toplevel::Request::Destroy => { - // all it done by the destructor - } - xdg_toplevel::Request::SetParent { parent } => { - with_surface_toplevel_data(self, &toplevel, |toplevel_data| { - toplevel_data.parent = parent.map(|toplevel_surface_parent| { - let parent_ptr = toplevel_surface_parent.get_user_data(); - let &(ref parent_surface, _, _) = - unsafe { &*(parent_ptr as *mut ShellSurfaceUserData) }; - parent_surface.clone() - }) - }); - } - xdg_toplevel::Request::SetTitle { title } => { - with_surface_toplevel_data(self, &toplevel, |toplevel_data| { - toplevel_data.title = title; - }); - } - xdg_toplevel::Request::SetAppId { app_id } => { - with_surface_toplevel_data(self, &toplevel, |toplevel_data| { - toplevel_data.app_id = app_id; - }); - } - xdg_toplevel::Request::ShowWindowMenu { seat, serial, x, y } => { - let handle = make_toplevel_handle(self.compositor_token, &toplevel); - let mut user_impl = self.user_impl.borrow_mut(); - user_impl.receive( - XdgRequest::ShowWindowMenu { - surface: handle, - seat, - serial, - location: (x, y), - }, - (), - ); - } - xdg_toplevel::Request::Move { seat, serial } => { - let handle = make_toplevel_handle(self.compositor_token, &toplevel); - let mut user_impl = self.user_impl.borrow_mut(); - user_impl.receive( - XdgRequest::Move { - surface: handle, - seat, - serial, - }, - (), - ); - } - 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(self.compositor_token, &toplevel); - let mut user_impl = self.user_impl.borrow_mut(); - user_impl.receive( - XdgRequest::Resize { - surface: handle, - seat, - serial, - edges, - }, - (), - ); - } - xdg_toplevel::Request::SetMaxSize { width, height } => { - with_surface_toplevel_data(self, &toplevel, |toplevel_data| { - toplevel_data.max_size = (width, height); - }); - } - xdg_toplevel::Request::SetMinSize { width, height } => { - with_surface_toplevel_data(self, &toplevel, |toplevel_data| { - toplevel_data.max_size = (width, height); - }); - } - xdg_toplevel::Request::SetMaximized => { - let handle = make_toplevel_handle(self.compositor_token, &toplevel); - let mut user_impl = self.user_impl.borrow_mut(); - user_impl.receive(XdgRequest::Maximize { surface: handle }, ()); - } - xdg_toplevel::Request::UnsetMaximized => { - let handle = make_toplevel_handle(self.compositor_token, &toplevel); - let mut user_impl = self.user_impl.borrow_mut(); - user_impl.receive(XdgRequest::UnMaximize { surface: handle }, ()); - } - xdg_toplevel::Request::SetFullscreen { output } => { - let handle = make_toplevel_handle(self.compositor_token, &toplevel); - let mut user_impl = self.user_impl.borrow_mut(); - user_impl.receive( - XdgRequest::Fullscreen { - surface: handle, - output, - }, - (), - ); - } - xdg_toplevel::Request::UnsetFullscreen => { - let handle = make_toplevel_handle(self.compositor_token, &toplevel); - let mut user_impl = self.user_impl.borrow_mut(); - user_impl.receive(XdgRequest::UnFullscreen { surface: handle }, ()); - } - xdg_toplevel::Request::SetMinimized => { - let handle = make_toplevel_handle(self.compositor_token, &toplevel); - let mut user_impl = self.user_impl.borrow_mut(); - user_impl.receive(XdgRequest::Minimize { surface: handle }, ()); - } - } - } -} - -fn destroy_toplevel( +fn toplevel_implementation( + request: xdg_toplevel::Request, toplevel: Resource, - implem: Box, xdg_toplevel::Request>>, ) where U: 'static, R: Role + 'static, SD: 'static, { - let implem: ShellImplementation = *downcast_impl(implem).unwrap_or_else(|_| unreachable!()); - let ptr = toplevel.get_user_data(); - toplevel.set_user_data(::std::ptr::null_mut()); - // take back ownership of the userdata - let data = *unsafe { Box::from_raw(ptr as *mut ShellSurfaceUserData) }; - if !data.0.is_alive() { + let data = toplevel.user_data::>().unwrap(); + match request { + xdg_toplevel::Request::Destroy => { + // all it done by the destructor + } + xdg_toplevel::Request::SetParent { parent } => { + with_surface_toplevel_data(&data.shell_data, &toplevel, |toplevel_data| { + toplevel_data.parent = parent.map(|toplevel_surface_parent| { + toplevel_surface_parent + .user_data::>() + .unwrap() + .wl_surface + .clone() + }) + }); + } + xdg_toplevel::Request::SetTitle { title } => { + with_surface_toplevel_data(&data.shell_data, &toplevel, |toplevel_data| { + toplevel_data.title = title; + }); + } + xdg_toplevel::Request::SetAppId { app_id } => { + with_surface_toplevel_data(&data.shell_data, &toplevel, |toplevel_data| { + toplevel_data.app_id = app_id; + }); + } + xdg_toplevel::Request::ShowWindowMenu { seat, serial, x, y } => { + let handle = make_toplevel_handle(&toplevel); + let mut user_impl = data.shell_data.user_impl.borrow_mut(); + (&mut *user_impl)(XdgRequest::ShowWindowMenu { + surface: handle, + seat, + serial, + location: (x, y), + }); + } + xdg_toplevel::Request::Move { seat, serial } => { + let handle = make_toplevel_handle(&toplevel); + let mut user_impl = data.shell_data.user_impl.borrow_mut(); + (&mut *user_impl)(XdgRequest::Move { + surface: handle, + seat, + serial, + }); + } + 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 { + surface: handle, + seat, + serial, + edges, + }); + } + xdg_toplevel::Request::SetMaxSize { width, height } => { + with_surface_toplevel_data(&data.shell_data, &toplevel, |toplevel_data| { + toplevel_data.max_size = (width, height); + }); + } + xdg_toplevel::Request::SetMinSize { width, height } => { + with_surface_toplevel_data(&data.shell_data, &toplevel, |toplevel_data| { + toplevel_data.max_size = (width, height); + }); + } + xdg_toplevel::Request::SetMaximized => { + let handle = make_toplevel_handle(&toplevel); + let mut user_impl = data.shell_data.user_impl.borrow_mut(); + (&mut *user_impl)(XdgRequest::Maximize { surface: handle }); + } + xdg_toplevel::Request::UnsetMaximized => { + let handle = make_toplevel_handle(&toplevel); + let mut user_impl = data.shell_data.user_impl.borrow_mut(); + (&mut *user_impl)(XdgRequest::UnMaximize { surface: handle }); + } + xdg_toplevel::Request::SetFullscreen { output } => { + let handle = make_toplevel_handle(&toplevel); + let mut user_impl = data.shell_data.user_impl.borrow_mut(); + (&mut *user_impl)(XdgRequest::Fullscreen { + surface: handle, + output, + }); + } + xdg_toplevel::Request::UnsetFullscreen => { + let handle = make_toplevel_handle(&toplevel); + let mut user_impl = data.shell_data.user_impl.borrow_mut(); + (&mut *user_impl)(XdgRequest::UnFullscreen { surface: handle }); + } + xdg_toplevel::Request::SetMinimized => { + let handle = make_toplevel_handle(&toplevel); + let mut user_impl = data.shell_data.user_impl.borrow_mut(); + (&mut *user_impl)(XdgRequest::Minimize { surface: handle }); + } + } +} + +fn destroy_toplevel(toplevel: Resource) +where + U: 'static, + R: Role + 'static, + SD: 'static, +{ + let data = toplevel.user_data::>().unwrap(); + if !data.wl_surface.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 // disconnecting client), ignore the protocol check. return; } else { - implem + data.shell_data .compositor_token - .with_role_data::(&data.0, |data| { + .with_role_data::(&data.wl_surface, |data| { data.pending_state = XdgSurfacePendingState::None; data.configured = false; - }) - .expect("xdg_toplevel exists but surface has not shell_surface role?!"); + }).expect("xdg_toplevel exists but surface has not shell_surface role?!"); } // remove this surface from the known ones (as well as any leftover dead surface) - implem + data.shell_data .shell_state .lock() .unwrap() @@ -615,103 +558,84 @@ fn destroy_toplevel( * xdg_popup */ -pub(crate) fn send_popup_configure( - token: CompositorToken, +pub(crate) fn send_popup_configure( resource: &Resource, configure: PopupConfigure, ) where U: 'static, R: Role + 'static, + SD: 'static, { - let &(ref surface, _, ref shell_surface) = - unsafe { &*(resource.get_user_data() as *mut ShellSurfaceUserData) }; + let data = resource.user_data::>().unwrap(); let (x, y) = configure.position; let (width, height) = configure.size; let serial = configure.serial; - resource.send(xdg_popup::Event::Configure { - x, - y, - width, - height, - }); - shell_surface.send(xdg_surface::Event::Configure { serial }); + resource.send(xdg_popup::Event::Configure { x, y, width, height }); + data.xdg_surface.send(xdg_surface::Event::Configure { serial }); // Add the configure as pending - token - .with_role_data::(surface, |data| data.pending_configures.push(serial)) + data.shell_data + .compositor_token + .with_role_data::(&data.wl_surface, |data| data.pending_configures.push(serial)) .expect("xdg_toplevel exists but surface has not shell_surface role?!"); } -fn make_popup_handle( - token: CompositorToken, +fn make_popup_handle( resource: &Resource, ) -> super::PopupSurface { - let ptr = resource.get_user_data(); - let &(ref wl_surface, _, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) }; + let data = resource.user_data::>().unwrap(); super::PopupSurface { - wl_surface: wl_surface.clone(), + wl_surface: data.wl_surface.clone(), shell_surface: PopupKind::Xdg(resource.clone()), - token, + token: data.shell_data.compositor_token, _shell_data: ::std::marker::PhantomData, } } -impl Implementation, xdg_popup::Request> - for ShellImplementation +fn xg_popup_implementation(request: xdg_popup::Request, popup: Resource) where U: 'static, R: Role + 'static, SD: 'static, { - fn receive(&mut self, request: xdg_popup::Request, popup: Resource) { - match request { - xdg_popup::Request::Destroy => { - // all is handled by our destructor - } - xdg_popup::Request::Grab { seat, serial } => { - let handle = make_popup_handle(self.compositor_token, &popup); - let mut user_impl = self.user_impl.borrow_mut(); - user_impl.receive( - XdgRequest::Grab { - surface: handle, - seat, - serial, - }, - (), - ); - } + let data = popup.user_data::>().unwrap(); + match request { + xdg_popup::Request::Destroy => { + // all is handled by our destructor + } + xdg_popup::Request::Grab { seat, serial } => { + let handle = make_popup_handle(&popup); + let mut user_impl = data.shell_data.user_impl.borrow_mut(); + (&mut *user_impl)(XdgRequest::Grab { + surface: handle, + seat, + serial, + }); } } } -fn destroy_popup( - popup: Resource, - implem: Box, xdg_popup::Request>>, -) where +fn destroy_popup(popup: Resource) +where U: 'static, R: Role + 'static, SD: 'static, { - let implem: ShellImplementation = *downcast_impl(implem).unwrap_or_else(|_| unreachable!()); - let ptr = popup.get_user_data(); - popup.set_user_data(::std::ptr::null_mut()); - // take back ownership of the userdata - let data = *unsafe { Box::from_raw(ptr as *mut ShellSurfaceUserData) }; - if !data.0.is_alive() { + let data = popup.user_data::>().unwrap(); + if !data.wl_surface.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 // disconnecting client), ignore the protocol check. return; } else { - implem + data.shell_data .compositor_token - .with_role_data::(&data.0, |data| { + .with_role_data::(&data.wl_surface, |data| { data.pending_state = XdgSurfacePendingState::None; data.configured = false; - }) - .expect("xdg_popup exists but surface has not shell_surface role?!"); + }).expect("xdg_popup exists but surface has not shell_surface role?!"); } // remove this surface from the known ones (as well as any leftover dead surface) - implem + data.shell_data .shell_state .lock() .unwrap() diff --git a/src/wayland/shell/xdg/zxdgv6_handlers.rs b/src/wayland/shell/xdg/zxdgv6_handlers.rs index e55875e..0136835 100644 --- a/src/wayland/shell/xdg/zxdgv6_handlers.rs +++ b/src/wayland/shell/xdg/zxdgv6_handlers.rs @@ -1,20 +1,26 @@ -use super::{make_shell_client_data, PopupConfigure, PopupKind, PopupState, PositionerState, ShellClient, - ShellClientData, ShellImplementation, ToplevelConfigure, ToplevelKind, ToplevelState, - XdgRequest, XdgSurfacePendingState, XdgSurfaceRole}; +use std::cell::RefCell; use std::sync::Mutex; -use utils::Rectangle; -use wayland::compositor::CompositorToken; + use wayland::compositor::roles::*; +use wayland::compositor::CompositorToken; +use wayland_protocols::unstable::xdg_shell::v6::server::{ + zxdg_popup_v6, zxdg_positioner_v6, zxdg_shell_v6, zxdg_surface_v6, zxdg_toplevel_v6, +}; use wayland_protocols::xdg_shell::server::{xdg_positioner, xdg_toplevel}; -use wayland_protocols::unstable::xdg_shell::v6::server::{zxdg_popup_v6, zxdg_positioner_v6, zxdg_shell_v6, - zxdg_surface_v6, zxdg_toplevel_v6}; -use wayland_server::{LoopToken, NewResource, Resource}; -use wayland_server::commons::{downcast_impl, Implementation}; use wayland_server::protocol::wl_surface; +use wayland_server::{DisplayToken, NewResource, Resource}; + +use utils::Rectangle; + +use super::{ + make_shell_client_data, PopupConfigure, PopupKind, PopupState, PositionerState, ShellClient, + ShellClientData, ShellData, ToplevelConfigure, ToplevelKind, ToplevelState, XdgRequest, + XdgSurfacePendingState, XdgSurfaceRole, +}; pub(crate) fn implement_shell( shell: NewResource, - implem: &ShellImplementation, + shell_data: &ShellData, ) -> Resource where U: 'static, @@ -22,18 +28,18 @@ where SD: Default + 'static, { let shell = shell.implement_nonsend( - implem.clone(), - Some(|shell, _| destroy_shell::(&shell)), - &implem.loop_token, - ); - shell.set_user_data(Box::into_raw(Box::new(Mutex::new(make_shell_client_data::()))) as *mut _); - let mut user_impl = implem.user_impl.borrow_mut(); - user_impl.receive( - XdgRequest::NewClient { - client: make_shell_client(&shell), + shell_implementation::, + None::, + ShellUserData { + shell_data: shell_data.clone(), + client_data: Mutex::new(make_shell_client_data::()), }, - (), + &shell_data.display_token, ); + let mut user_impl = shell_data.user_impl.borrow_mut(); + (&mut *user_impl)(XdgRequest::NewClient { + client: make_shell_client(&shell, shell_data.compositor_token), + }); shell } @@ -41,83 +47,83 @@ where * xdg_shell */ -pub(crate) type ShellUserData = Mutex>; - -fn destroy_shell(shell: &Resource) { - let ptr = shell.get_user_data(); - shell.set_user_data(::std::ptr::null_mut()); - let data = unsafe { Box::from_raw(ptr as *mut ShellUserData) }; - // explicit call to drop to not forget what we're doing here - ::std::mem::drop(data); +pub(crate) struct ShellUserData { + shell_data: ShellData, + pub(crate) client_data: Mutex>, } -pub(crate) fn make_shell_client(resource: &Resource) -> ShellClient { +pub(crate) fn make_shell_client( + resource: &Resource, + token: CompositorToken, +) -> ShellClient { ShellClient { kind: super::ShellClientKind::ZxdgV6(resource.clone()), + _token: token, _data: ::std::marker::PhantomData, } } -impl Implementation, zxdg_shell_v6::Request> - for ShellImplementation -where +fn shell_implementation( + request: zxdg_shell_v6::Request, + shell: Resource, +) where U: 'static, R: Role + 'static, SD: 'static, { - fn receive(&mut self, request: zxdg_shell_v6::Request, shell: Resource) { - match request { - zxdg_shell_v6::Request::Destroy => { - // all is handled by destructor - } - zxdg_shell_v6::Request::CreatePositioner { id } => { - implement_positioner(id, &self.loop_token); - } - zxdg_shell_v6::Request::GetXdgSurface { id, surface } => { - let role_data = XdgSurfaceRole { - pending_state: XdgSurfacePendingState::None, - window_geometry: None, - pending_configures: Vec::new(), - configured: false, - }; - if self.compositor_token - .give_role_with(&surface, role_data) - .is_err() - { - shell.post_error( - zxdg_shell_v6::Error::Role as u32, - "Surface already has a role.".into(), - ); - return; - } - let xdg_surface = id.implement_nonsend( - self.clone(), - Some(destroy_surface::), - &self.loop_token, + let data = shell.user_data::>().unwrap(); + match request { + zxdg_shell_v6::Request::Destroy => { + // all is handled by destructor + } + zxdg_shell_v6::Request::CreatePositioner { id } => { + implement_positioner(id, &data.shell_data.display_token); + } + zxdg_shell_v6::Request::GetXdgSurface { id, surface } => { + let role_data = XdgSurfaceRole { + pending_state: XdgSurfacePendingState::None, + window_geometry: None, + pending_configures: Vec::new(), + configured: false, + }; + if data + .shell_data + .compositor_token + .give_role_with(&surface, role_data) + .is_err() + { + shell.post_error( + zxdg_shell_v6::Error::Role as u32, + "Surface already has a role.".into(), ); - xdg_surface - .set_user_data(Box::into_raw(Box::new((surface.clone(), shell.clone()))) as *mut _); + return; } - zxdg_shell_v6::Request::Pong { serial } => { - let valid = { - let mutex = unsafe { &*(shell.get_user_data() as *mut ShellUserData) }; - let mut guard = mutex.lock().unwrap(); - if guard.pending_ping == serial { - guard.pending_ping = 0; - true - } else { - false - } - }; - if valid { - let mut user_impl = self.user_impl.borrow_mut(); - user_impl.receive( - XdgRequest::ClientPong { - client: make_shell_client(&shell), - }, - (), - ); + id.implement_nonsend( + xdg_surface_implementation::, + Some(destroy_surface::), + XdgSurfaceUserData { + shell_data: data.shell_data.clone(), + wl_surface: surface.clone(), + shell: shell.clone(), + }, + &data.shell_data.display_token, + ); + } + zxdg_shell_v6::Request::Pong { serial } => { + let valid = { + let mut guard = data.client_data.lock().unwrap(); + if guard.pending_ping == serial { + guard.pending_ping = 0; + true + } else { + false } + }; + if valid { + let mut user_impl = data.shell_data.user_impl.borrow_mut(); + (&mut *user_impl)(XdgRequest::ClientPong { + client: make_shell_client(&shell, data.shell_data.compositor_token), + }); } } } @@ -127,23 +133,14 @@ where * xdg_positioner */ -fn destroy_positioner(positioner: &Resource) { - let ptr = positioner.get_user_data(); - positioner.set_user_data(::std::ptr::null_mut()); - // drop the PositionerState - let surface = unsafe { Box::from_raw(ptr as *mut PositionerState) }; - // explicit call to drop to not forget what we're doing here - ::std::mem::drop(surface); -} - fn implement_positioner( positioner: NewResource, - token: &LoopToken, + token: &DisplayToken, ) -> Resource { - let positioner = positioner.implement_nonsend( + positioner.implement_nonsend( |request, positioner: Resource<_>| { - let ptr = positioner.get_user_data(); - let state = unsafe { &mut *(ptr as *mut PositionerState) }; + let mutex = positioner.user_data::>().unwrap(); + let mut state = mutex.borrow_mut(); match request { zxdg_positioner_v6::Request::Destroy => { // handled by destructor @@ -158,24 +155,14 @@ fn implement_positioner( state.rect_size = (width, height); } } - zxdg_positioner_v6::Request::SetAnchorRect { - x, - y, - width, - height, - } => { + zxdg_positioner_v6::Request::SetAnchorRect { x, y, width, height } => { if width < 1 || height < 1 { positioner.post_error( zxdg_positioner_v6::Error::InvalidInput as u32, "Invalid size for positioner's anchor rectangle.".into(), ); } else { - state.anchor_rect = Rectangle { - x, - y, - width, - height, - }; + state.anchor_rect = Rectangle { x, y, width, height }; } } zxdg_positioner_v6::Request::SetAnchor { anchor } => { @@ -210,184 +197,163 @@ fn implement_positioner( } } }, - Some(|positioner, _| destroy_positioner(&positioner)), + None::, + RefCell::new(PositionerState::new()), token, - ); - let data = PositionerState::new(); - positioner.set_user_data(Box::into_raw(Box::new(data)) as *mut _); - positioner + ) } /* * xdg_surface */ -type XdgSurfaceUserData = ( - Resource, - Resource, -); - -fn destroy_surface( - surface: Resource, - implem: Box, zxdg_surface_v6::Request>>, -) where - U: 'static, - R: Role + 'static, - SD: 'static, -{ - let implem: ShellImplementation = *downcast_impl(implem).unwrap_or_else(|_| unreachable!()); - let ptr = surface.get_user_data(); - surface.set_user_data(::std::ptr::null_mut()); - // take back ownership of the userdata - let data = unsafe { Box::from_raw(ptr as *mut XdgSurfaceUserData) }; - if !data.0.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 - // disconnecting client), ignore the protocol check. - return; - } - implem - .compositor_token - .with_role_data::(&data.0, |rdata| { - if let XdgSurfacePendingState::None = rdata.pending_state { - // all is good - } else { - data.1.post_error( - zxdg_shell_v6::Error::Role as u32, - "xdg_surface was destroyed before its role object".into(), - ); - } - }) - .expect("xdg_surface exists but surface has not shell_surface role?!"); +struct XdgSurfaceUserData { + shell_data: ShellData, + wl_surface: Resource, + shell: Resource, } -impl Implementation, zxdg_surface_v6::Request> - for ShellImplementation +fn destroy_surface(surface: Resource) where U: 'static, R: Role + 'static, SD: 'static, { - fn receive( - &mut self, - request: zxdg_surface_v6::Request, - xdg_surface: Resource, - ) { - let ptr = xdg_surface.get_user_data(); - let &(ref surface, ref shell) = unsafe { &*(ptr as *mut XdgSurfaceUserData) }; - match request { - zxdg_surface_v6::Request::Destroy => { - // all is handled by our destructor - } - zxdg_surface_v6::Request::GetToplevel { id } => { - self.compositor_token - .with_role_data::(surface, |data| { - data.pending_state = XdgSurfacePendingState::Toplevel(ToplevelState { - parent: None, - title: String::new(), - app_id: String::new(), - min_size: (0, 0), - max_size: (0, 0), - }); - }) - .expect("xdg_surface exists but surface has not shell_surface role?!"); - let toplevel = id.implement_nonsend( - self.clone(), - Some(destroy_toplevel::), - &self.loop_token, + let data = surface.user_data::>().unwrap(); + if !data.wl_surface.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 + // disconnecting client), ignore the protocol check. + return; + } + data.shell_data + .compositor_token + .with_role_data::(&data.wl_surface, |rdata| { + if let XdgSurfacePendingState::None = rdata.pending_state { + // all is good + } else { + data.shell.post_error( + zxdg_shell_v6::Error::Role as u32, + "xdg_surface was destroyed before its role object".into(), ); - toplevel.set_user_data(Box::into_raw(Box::new(( - surface.clone(), - shell.clone(), - xdg_surface.clone(), - ))) as *mut _); - - self.shell_state - .lock() - .unwrap() - .known_toplevels - .push(make_toplevel_handle(self.compositor_token, &toplevel)); - - let handle = make_toplevel_handle(self.compositor_token, &toplevel); - let mut user_impl = self.user_impl.borrow_mut(); - user_impl.receive(XdgRequest::NewToplevel { surface: handle }, ()); } - zxdg_surface_v6::Request::GetPopup { - id, - parent, - positioner, - } => { - let positioner_data = unsafe { &*(positioner.get_user_data() as *const PositionerState) }; + }).expect("xdg_surface exists but surface has not shell_surface role?!"); +} - let parent_ptr = parent.get_user_data(); - let &(ref parent_surface, _) = unsafe { &*(parent_ptr as *mut XdgSurfaceUserData) }; - self.compositor_token - .with_role_data::(surface, |data| { - data.pending_state = XdgSurfacePendingState::Popup(PopupState { - parent: Some(parent_surface.clone()), - positioner: positioner_data.clone(), - }); - }) - .expect("xdg_surface exists but surface has not shell_surface role?!"); - let popup = id.implement_nonsend( - self.clone(), - Some(destroy_popup::), - &self.loop_token, - ); - popup.set_user_data(Box::into_raw(Box::new(( - surface.clone(), - shell.clone(), - xdg_surface.clone(), - ))) as *mut _); +fn xdg_surface_implementation( + request: zxdg_surface_v6::Request, + xdg_surface: Resource, +) where + U: 'static, + R: Role + 'static, + SD: 'static, +{ + let data = xdg_surface.user_data::>().unwrap(); + match request { + zxdg_surface_v6::Request::Destroy => { + // all is handled by our destructor + } + zxdg_surface_v6::Request::GetToplevel { id } => { + data.shell_data + .compositor_token + .with_role_data::(&data.wl_surface, |data| { + data.pending_state = XdgSurfacePendingState::Toplevel(ToplevelState { + parent: None, + title: String::new(), + app_id: String::new(), + min_size: (0, 0), + max_size: (0, 0), + }); + }).expect("xdg_surface exists but surface has not shell_surface role?!"); + let toplevel = id.implement_nonsend( + toplevel_implementation::, + Some(destroy_toplevel::), + ShellSurfaceUserData { + shell_data: data.shell_data.clone(), + wl_surface: data.wl_surface.clone(), + shell: data.shell.clone(), + xdg_surface: xdg_surface.clone(), + }, + &data.shell_data.display_token, + ); - self.shell_state - .lock() - .unwrap() - .known_popups - .push(make_popup_handle(self.compositor_token, &popup)); + data.shell_data + .shell_state + .lock() + .unwrap() + .known_toplevels + .push(make_toplevel_handle(&toplevel)); - let handle = make_popup_handle(self.compositor_token, &popup); - let mut user_impl = self.user_impl.borrow_mut(); - user_impl.receive(XdgRequest::NewPopup { surface: handle }, ()); - } - zxdg_surface_v6::Request::SetWindowGeometry { - x, - y, - width, - height, - } => { - self.compositor_token - .with_role_data::(surface, |data| { - data.window_geometry = Some(Rectangle { - x, - y, - width, - height, - }); - }) - .expect("xdg_surface exists but surface has not shell_surface role?!"); - } - zxdg_surface_v6::Request::AckConfigure { serial } => { - self.compositor_token - .with_role_data::(surface, |data| { - let mut found = false; - data.pending_configures.retain(|&s| { - if s == serial { - found = true; - } - s > serial - }); - if !found { - // client responded to a non-existing configure - shell.post_error( - zxdg_shell_v6::Error::InvalidSurfaceState as u32, - format!("Wrong configure serial: {}", serial), - ); + let handle = make_toplevel_handle(&toplevel); + let mut user_impl = data.shell_data.user_impl.borrow_mut(); + (&mut *user_impl)(XdgRequest::NewToplevel { surface: handle }); + } + zxdg_surface_v6::Request::GetPopup { + id, + parent, + positioner, + } => { + let positioner_data = positioner.user_data::>().unwrap(); + + let parent_data = parent.user_data::>().unwrap(); + data.shell_data + .compositor_token + .with_role_data::(&data.wl_surface, |data| { + data.pending_state = XdgSurfacePendingState::Popup(PopupState { + parent: Some(parent_data.wl_surface.clone()), + positioner: positioner_data.borrow().clone(), + }); + }).expect("xdg_surface exists but surface has not shell_surface role?!"); + let popup = id.implement_nonsend( + popup_implementation::, + Some(destroy_popup::), + ShellSurfaceUserData { + shell_data: data.shell_data.clone(), + wl_surface: data.wl_surface.clone(), + shell: data.shell.clone(), + xdg_surface: xdg_surface.clone(), + }, + &data.shell_data.display_token, + ); + + data.shell_data + .shell_state + .lock() + .unwrap() + .known_popups + .push(make_popup_handle(&popup)); + + let handle = make_popup_handle(&popup); + let mut user_impl = data.shell_data.user_impl.borrow_mut(); + (&mut *user_impl)(XdgRequest::NewPopup { surface: handle }); + } + zxdg_surface_v6::Request::SetWindowGeometry { x, y, width, height } => { + data.shell_data + .compositor_token + .with_role_data::(&data.wl_surface, |data| { + data.window_geometry = Some(Rectangle { x, y, width, height }); + }).expect("xdg_surface exists but surface has not shell_surface role?!"); + } + zxdg_surface_v6::Request::AckConfigure { serial } => { + data.shell_data + .compositor_token + .with_role_data::(&data.wl_surface, |role_data| { + let mut found = false; + role_data.pending_configures.retain(|&s| { + if s == serial { + found = true; } - data.configured = true; - }) - .expect("xdg_surface exists but surface has not shell_surface role?!"); - } + s > serial + }); + if !found { + // client responded to a non-existing configure + data.shell.post_error( + zxdg_shell_v6::Error::InvalidSurfaceState as u32, + format!("Wrong configure serial: {}", serial), + ); + } + role_data.configured = true; + }).expect("xdg_surface exists but surface has not shell_surface role?!"); } } } @@ -396,44 +362,39 @@ where * xdg_toplevel */ -pub type ShellSurfaceUserData = ( - Resource, - Resource, - Resource, -); +pub struct ShellSurfaceUserData { + pub(crate) shell_data: ShellData, + pub(crate) wl_surface: Resource, + pub(crate) shell: Resource, + pub(crate) xdg_surface: Resource, +} // Utility functions allowing to factor out a lot of the upcoming logic -fn with_surface_toplevel_data( - implem: &ShellImplementation, - toplevel: &Resource, - f: F, -) where +fn with_surface_toplevel_data(toplevel: &Resource, f: F) +where U: 'static, R: Role + 'static, SD: 'static, F: FnOnce(&mut ToplevelState), { - let ptr = toplevel.get_user_data(); - let &(ref surface, _, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) }; - implem + let data = toplevel.user_data::>().unwrap(); + data.shell_data .compositor_token - .with_role_data::(surface, |data| match data.pending_state { + .with_role_data::(&data.wl_surface, |data| match data.pending_state { XdgSurfacePendingState::Toplevel(ref mut toplevel_data) => f(toplevel_data), _ => unreachable!(), - }) - .expect("xdg_toplevel exists but surface has not shell_surface role?!"); + }).expect("xdg_toplevel exists but surface has not shell_surface role?!"); } -pub fn send_toplevel_configure( - token: CompositorToken, +pub fn send_toplevel_configure( resource: &Resource, configure: ToplevelConfigure, ) where U: 'static, R: Role + 'static, + SD: 'static, { - let &(ref surface, _, ref shell_surface) = - unsafe { &*(resource.get_user_data() as *mut ShellSurfaceUserData) }; + let data = resource.user_data::>().unwrap(); let (width, height) = configure.size.unwrap_or((0, 0)); // convert the Vec (which is really a Vec) into Vec let states = { @@ -450,181 +411,154 @@ pub fn send_toplevel_configure( height, states, }); - shell_surface.send(zxdg_surface_v6::Event::Configure { serial }); + data.xdg_surface + .send(zxdg_surface_v6::Event::Configure { serial }); // Add the configure as pending - token - .with_role_data::(surface, |data| data.pending_configures.push(serial)) + data.shell_data + .compositor_token + .with_role_data::(&data.wl_surface, |data| data.pending_configures.push(serial)) .expect("xdg_toplevel exists but surface has not shell_surface role?!"); } -fn make_toplevel_handle( - token: CompositorToken, +fn make_toplevel_handle( resource: &Resource, ) -> super::ToplevelSurface { - let ptr = resource.get_user_data(); - let &(ref wl_surface, _, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) }; + let data = resource.user_data::>().unwrap(); super::ToplevelSurface { - wl_surface: wl_surface.clone(), + wl_surface: data.wl_surface.clone(), shell_surface: ToplevelKind::ZxdgV6(resource.clone()), - token, + token: data.shell_data.compositor_token, _shell_data: ::std::marker::PhantomData, } } -impl Implementation, zxdg_toplevel_v6::Request> - for ShellImplementation -where - U: 'static, - R: Role + 'static, - SD: 'static, -{ - fn receive( - &mut self, - request: zxdg_toplevel_v6::Request, - toplevel: Resource, - ) { - match request { - zxdg_toplevel_v6::Request::Destroy => { - // all it done by the destructor - } - zxdg_toplevel_v6::Request::SetParent { parent } => { - with_surface_toplevel_data(self, &toplevel, |toplevel_data| { - toplevel_data.parent = parent.map(|toplevel_surface_parent| { - let parent_ptr = toplevel_surface_parent.get_user_data(); - let &(ref parent_surface, _, _) = - unsafe { &*(parent_ptr as *mut ShellSurfaceUserData) }; - parent_surface.clone() - }) - }); - } - zxdg_toplevel_v6::Request::SetTitle { title } => { - with_surface_toplevel_data(self, &toplevel, |toplevel_data| { - toplevel_data.title = title; - }); - } - zxdg_toplevel_v6::Request::SetAppId { app_id } => { - with_surface_toplevel_data(self, &toplevel, |toplevel_data| { - toplevel_data.app_id = app_id; - }); - } - zxdg_toplevel_v6::Request::ShowWindowMenu { seat, serial, x, y } => { - let handle = make_toplevel_handle(self.compositor_token, &toplevel); - let mut user_impl = self.user_impl.borrow_mut(); - user_impl.receive( - XdgRequest::ShowWindowMenu { - surface: handle, - seat, - serial, - location: (x, y), - }, - (), - ); - } - zxdg_toplevel_v6::Request::Move { seat, serial } => { - let handle = make_toplevel_handle(self.compositor_token, &toplevel); - let mut user_impl = self.user_impl.borrow_mut(); - user_impl.receive( - XdgRequest::Move { - surface: handle, - seat, - serial, - }, - (), - ); - } - zxdg_toplevel_v6::Request::Resize { - seat, - serial, - edges, - } => { - let edges = zxdg_toplevel_v6::ResizeEdge::from_raw(edges) - .unwrap_or(zxdg_toplevel_v6::ResizeEdge::None); - let handle = make_toplevel_handle(self.compositor_token, &toplevel); - let mut user_impl = self.user_impl.borrow_mut(); - user_impl.receive( - XdgRequest::Resize { - surface: handle, - seat, - serial, - edges: zxdg_edges_to_xdg(edges), - }, - (), - ); - } - zxdg_toplevel_v6::Request::SetMaxSize { width, height } => { - with_surface_toplevel_data(self, &toplevel, |toplevel_data| { - toplevel_data.max_size = (width, height); - }); - } - zxdg_toplevel_v6::Request::SetMinSize { width, height } => { - with_surface_toplevel_data(self, &toplevel, |toplevel_data| { - toplevel_data.max_size = (width, height); - }); - } - zxdg_toplevel_v6::Request::SetMaximized => { - let handle = make_toplevel_handle(self.compositor_token, &toplevel); - let mut user_impl = self.user_impl.borrow_mut(); - user_impl.receive(XdgRequest::Maximize { surface: handle }, ()); - } - zxdg_toplevel_v6::Request::UnsetMaximized => { - let handle = make_toplevel_handle(self.compositor_token, &toplevel); - let mut user_impl = self.user_impl.borrow_mut(); - user_impl.receive(XdgRequest::UnMaximize { surface: handle }, ()); - } - zxdg_toplevel_v6::Request::SetFullscreen { output } => { - let handle = make_toplevel_handle(self.compositor_token, &toplevel); - let mut user_impl = self.user_impl.borrow_mut(); - user_impl.receive( - XdgRequest::Fullscreen { - surface: handle, - output, - }, - (), - ); - } - zxdg_toplevel_v6::Request::UnsetFullscreen => { - let handle = make_toplevel_handle(self.compositor_token, &toplevel); - let mut user_impl = self.user_impl.borrow_mut(); - user_impl.receive(XdgRequest::UnFullscreen { surface: handle }, ()); - } - zxdg_toplevel_v6::Request::SetMinimized => { - let handle = make_toplevel_handle(self.compositor_token, &toplevel); - let mut user_impl = self.user_impl.borrow_mut(); - user_impl.receive(XdgRequest::Minimize { surface: handle }, ()); - } - } - } -} - -fn destroy_toplevel( +fn toplevel_implementation( + request: zxdg_toplevel_v6::Request, toplevel: Resource, - implem: Box, zxdg_toplevel_v6::Request>>, ) where U: 'static, R: Role + 'static, SD: 'static, { - let implem: ShellImplementation = *downcast_impl(implem).unwrap_or_else(|_| unreachable!()); - let ptr = toplevel.get_user_data(); - toplevel.set_user_data(::std::ptr::null_mut()); - // take back ownership of the userdata - let data = *unsafe { Box::from_raw(ptr as *mut ShellSurfaceUserData) }; - if !data.0.is_alive() { + let data = toplevel.user_data::>().unwrap(); + match request { + zxdg_toplevel_v6::Request::Destroy => { + // all it done by the destructor + } + zxdg_toplevel_v6::Request::SetParent { parent } => { + with_surface_toplevel_data::(&toplevel, |toplevel_data| { + toplevel_data.parent = parent.map(|toplevel_surface_parent| { + let parent_data = toplevel_surface_parent + .user_data::>() + .unwrap(); + parent_data.wl_surface.clone() + }) + }); + } + zxdg_toplevel_v6::Request::SetTitle { title } => { + with_surface_toplevel_data::(&toplevel, |toplevel_data| { + toplevel_data.title = title; + }); + } + zxdg_toplevel_v6::Request::SetAppId { app_id } => { + with_surface_toplevel_data::(&toplevel, |toplevel_data| { + toplevel_data.app_id = app_id; + }); + } + zxdg_toplevel_v6::Request::ShowWindowMenu { seat, serial, x, y } => { + let handle = make_toplevel_handle(&toplevel); + let mut user_impl = data.shell_data.user_impl.borrow_mut(); + (&mut *user_impl)(XdgRequest::ShowWindowMenu { + surface: handle, + seat, + serial, + location: (x, y), + }); + } + zxdg_toplevel_v6::Request::Move { seat, serial } => { + let handle = make_toplevel_handle(&toplevel); + let mut user_impl = data.shell_data.user_impl.borrow_mut(); + (&mut *user_impl)(XdgRequest::Move { + surface: handle, + seat, + serial, + }); + } + zxdg_toplevel_v6::Request::Resize { seat, serial, edges } => { + let edges = + zxdg_toplevel_v6::ResizeEdge::from_raw(edges).unwrap_or(zxdg_toplevel_v6::ResizeEdge::None); + let handle = make_toplevel_handle(&toplevel); + let mut user_impl = data.shell_data.user_impl.borrow_mut(); + (&mut *user_impl)(XdgRequest::Resize { + surface: handle, + seat, + serial, + edges: zxdg_edges_to_xdg(edges), + }); + } + zxdg_toplevel_v6::Request::SetMaxSize { width, height } => { + with_surface_toplevel_data::(&toplevel, |toplevel_data| { + toplevel_data.max_size = (width, height); + }); + } + zxdg_toplevel_v6::Request::SetMinSize { width, height } => { + with_surface_toplevel_data::(&toplevel, |toplevel_data| { + toplevel_data.max_size = (width, height); + }); + } + zxdg_toplevel_v6::Request::SetMaximized => { + let handle = make_toplevel_handle(&toplevel); + let mut user_impl = data.shell_data.user_impl.borrow_mut(); + (&mut *user_impl)(XdgRequest::Maximize { surface: handle }); + } + zxdg_toplevel_v6::Request::UnsetMaximized => { + let handle = make_toplevel_handle(&toplevel); + let mut user_impl = data.shell_data.user_impl.borrow_mut(); + (&mut *user_impl)(XdgRequest::UnMaximize { surface: handle }); + } + zxdg_toplevel_v6::Request::SetFullscreen { output } => { + let handle = make_toplevel_handle(&toplevel); + let mut user_impl = data.shell_data.user_impl.borrow_mut(); + (&mut *user_impl)(XdgRequest::Fullscreen { + surface: handle, + output, + }); + } + zxdg_toplevel_v6::Request::UnsetFullscreen => { + let handle = make_toplevel_handle(&toplevel); + let mut user_impl = data.shell_data.user_impl.borrow_mut(); + (&mut *user_impl)(XdgRequest::UnFullscreen { surface: handle }); + } + zxdg_toplevel_v6::Request::SetMinimized => { + let handle = make_toplevel_handle(&toplevel); + let mut user_impl = data.shell_data.user_impl.borrow_mut(); + (&mut *user_impl)(XdgRequest::Minimize { surface: handle }); + } + } +} + +fn destroy_toplevel(toplevel: Resource) +where + U: 'static, + R: Role + 'static, + SD: 'static, +{ + let data = toplevel.user_data::>().unwrap(); + if !data.wl_surface.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 // disconnecting client), ignore the protocol check. return; } else { - implem + data.shell_data .compositor_token - .with_role_data::(&data.0, |data| { + .with_role_data::(&data.wl_surface, |data| { data.pending_state = XdgSurfacePendingState::None; data.configured = false; - }) - .expect("xdg_toplevel exists but surface has not shell_surface role?!"); + }).expect("xdg_toplevel exists but surface has not shell_surface role?!"); } // remove this surface from the known ones (as well as any leftover dead surface) - implem + data.shell_data .shell_state .lock() .unwrap() @@ -636,103 +570,87 @@ fn destroy_toplevel( * xdg_popup */ -pub(crate) fn send_popup_configure( - token: CompositorToken, +pub(crate) fn send_popup_configure( resource: &Resource, configure: PopupConfigure, ) where U: 'static, R: Role + 'static, + SD: 'static, { - let &(ref surface, _, ref shell_surface) = - unsafe { &*(resource.get_user_data() as *mut ShellSurfaceUserData) }; + let data = resource.user_data::>().unwrap(); let (x, y) = configure.position; let (width, height) = configure.size; let serial = configure.serial; - resource.send(zxdg_popup_v6::Event::Configure { - x, - y, - width, - height, - }); - shell_surface.send(zxdg_surface_v6::Event::Configure { serial }); + resource.send(zxdg_popup_v6::Event::Configure { x, y, width, height }); + data.xdg_surface + .send(zxdg_surface_v6::Event::Configure { serial }); // Add the configure as pending - token - .with_role_data::(surface, |data| data.pending_configures.push(serial)) + data.shell_data + .compositor_token + .with_role_data::(&data.wl_surface, |data| data.pending_configures.push(serial)) .expect("xdg_toplevel exists but surface has not shell_surface role?!"); } -fn make_popup_handle( - token: CompositorToken, +fn make_popup_handle( resource: &Resource, ) -> super::PopupSurface { - let ptr = resource.get_user_data(); - let &(ref wl_surface, _, _) = unsafe { &*(ptr as *mut ShellSurfaceUserData) }; + let data = resource.user_data::>().unwrap(); super::PopupSurface { - wl_surface: wl_surface.clone(), + wl_surface: data.wl_surface.clone(), shell_surface: PopupKind::ZxdgV6(resource.clone()), - token, + token: data.shell_data.compositor_token, _shell_data: ::std::marker::PhantomData, } } -impl Implementation, zxdg_popup_v6::Request> - for ShellImplementation -where - U: 'static, - R: Role + 'static, - SD: 'static, -{ - fn receive(&mut self, request: zxdg_popup_v6::Request, popup: Resource) { - match request { - zxdg_popup_v6::Request::Destroy => { - // all is handled by our destructor - } - zxdg_popup_v6::Request::Grab { seat, serial } => { - let handle = make_popup_handle(self.compositor_token, &popup); - let mut user_impl = self.user_impl.borrow_mut(); - user_impl.receive( - XdgRequest::Grab { - surface: handle, - seat, - serial, - }, - (), - ); - } - } - } -} - -fn destroy_popup( +fn popup_implementation( + request: zxdg_popup_v6::Request, popup: Resource, - implem: Box, zxdg_popup_v6::Request>>, ) where U: 'static, R: Role + 'static, SD: 'static, { - let implem: ShellImplementation = *downcast_impl(implem).unwrap_or_else(|_| unreachable!()); - let ptr = popup.get_user_data(); - popup.set_user_data(::std::ptr::null_mut()); - // take back ownership of the userdata - let data = *unsafe { Box::from_raw(ptr as *mut ShellSurfaceUserData) }; - if !data.0.is_alive() { + let data = popup.user_data::>().unwrap(); + match request { + zxdg_popup_v6::Request::Destroy => { + // all is handled by our destructor + } + zxdg_popup_v6::Request::Grab { seat, serial } => { + let handle = make_popup_handle(&popup); + let mut user_impl = data.shell_data.user_impl.borrow_mut(); + (&mut *user_impl)(XdgRequest::Grab { + surface: handle, + seat, + serial, + }); + } + } +} + +fn destroy_popup(popup: Resource) +where + U: 'static, + R: Role + 'static, + SD: 'static, +{ + let data = popup.user_data::>().unwrap(); + if !data.wl_surface.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 // disconnecting client), ignore the protocol check. return; } else { - implem + data.shell_data .compositor_token - .with_role_data::(&data.0, |data| { + .with_role_data::(&data.wl_surface, |data| { data.pending_state = XdgSurfacePendingState::None; data.configured = false; - }) - .expect("xdg_popup exists but surface has not shell_surface role?!"); + }).expect("xdg_popup exists but surface has not shell_surface role?!"); } // remove this surface from the known ones (as well as any leftover dead surface) - implem + data.shell_data .shell_state .lock() .unwrap() diff --git a/src/wayland/shm/mod.rs b/src/wayland/shm/mod.rs index 2f57fc4..416efa8 100644 --- a/src/wayland/shm/mod.rs +++ b/src/wayland/shm/mod.rs @@ -23,21 +23,21 @@ //! use wayland_server::protocol::wl_shm::Format; //! //! # fn main() { -//! # let (mut display, mut event_loop) = wayland_server::Display::new(); +//! # let mut event_loop = wayland_server::calloop::EventLoop::<()>::new().unwrap(); +//! # let mut display = wayland_server::Display::new(event_loop.handle()); //! // Insert the ShmGlobal into your event loop //! // Here, we specify that Yuyv and C8 format are supported //! // additionnaly to the standart Argb8888 and Xrgb8888. //! let shm_global = init_shm_global( //! &mut display, -//! event_loop.token(), //! vec![Format::Yuyv, Format::C8], //! None // we don't provide a logger here //! ); //! # } //! ``` //! -//! Then, when you have a `WlBuffer` and need to retrieve its contents, use the token method to -//! do it: +//! Then, when you have a `WlBuffer` and need to retrieve its contents, use the +//! `with_buffer_contents` function to do it: //! //! ``` //! # extern crate wayland_server; @@ -45,13 +45,27 @@ //! # use wayland_server::protocol::wl_buffer::WlBuffer; //! # use wayland_server::Resource; //! # fn wrap(buffer: &Resource) { -//! use smithay::wayland::shm::{with_buffer_contents, BufferData}; +//! use smithay::wayland::shm::{with_buffer_contents, BufferData, BufferAccessError}; //! -//! with_buffer_contents(&buffer, +//! let content = with_buffer_contents(&buffer, //! |slice: &[u8], buffer_metadata: BufferData| { -//! // do something to draw it on the screen +//! // do something to extract the contents of the buffer //! } //! ); +//! +//! match content { +//! Ok(something) => { +//! /* `something` is the content you returned from the closure */ +//! }, +//! Err(BufferAccessError::NotManaged) => { +//! /* This buffer is not managed by the SHM global, but by something else */ +//! }, +//! Err(BufferAccessError::BadMap) => { +//! /* The client supplied invalid content specification for this buffer, +//! and was killed. +//! */ +//! } +//! } //! # } //! # fn main() {} //! ``` @@ -66,9 +80,8 @@ use self::pool::{Pool, ResizeError}; use std::rc::Rc; use std::sync::Arc; -use wayland_server::{Display, Global, LoopToken, NewResource, Resource}; -use wayland_server::commons::Implementation; use wayland_server::protocol::{wl_buffer, wl_shm, wl_shm_pool}; +use wayland_server::{Display, DisplayToken, Global, NewResource, Resource}; mod pool; @@ -80,7 +93,7 @@ mod pool; pub struct ShmGlobalData { formats: Rc>, log: ::slog::Logger, - token: LoopToken, + token: DisplayToken, } /// Create a new SHM global advertizing given supported formats. @@ -94,7 +107,6 @@ pub struct ShmGlobalData { /// the future. pub fn init_shm_global( display: &mut Display, - token: LoopToken, mut formats: Vec, logger: L, ) -> Global @@ -109,11 +121,19 @@ where let data = ShmGlobalData { formats: Rc::new(formats), log: log.new(o!("smithay_module" => "shm_handler")), - token: token.clone(), + token: display.get_token(), }; - display.create_global::(&token, 1, move |_version, shm_new: NewResource<_>| { - let shm = shm_new.implement_nonsend(data.clone(), None::, &data.token); + display.create_global::(1, move |shm_new: NewResource<_>, _version| { + let shm = shm_new.implement_nonsend( + { + let mut data = data.clone(); + move |req, shm| data.receive_shm_message(req, shm) + }, + None::, + (), + &data.token, + ); // send the formats for f in &data.formats[..] { shm.send(wl_shm::Event::Format { format: *f }); @@ -152,10 +172,10 @@ pub fn with_buffer_contents( where F: FnOnce(&[u8], BufferData) -> T, { - if !buffer.is_implemented_with::() { - return Err(BufferAccessError::NotManaged); - } - let data = unsafe { &*(buffer.get_user_data() as *mut InternalBufferData) }; + let data = match buffer.user_data::() { + Some(d) => d, + None => return Err(BufferAccessError::NotManaged), + }; match data.pool.with_data_slice(|slice| f(slice, data.data)) { Ok(t) => Ok(t), @@ -167,40 +187,38 @@ where } } -impl Implementation, wl_shm::Request> for ShmGlobalData { - fn receive(&mut self, request: wl_shm::Request, shm: Resource) { +impl ShmGlobalData { + fn receive_shm_message(&mut self, request: wl_shm::Request, shm: Resource) { use self::wl_shm::{Error, Request}; - match request { - Request::CreatePool { id: pool, fd, size } => { - if size <= 0 { - shm.post_error( - Error::InvalidFd as u32, - "Invalid size for a new wl_shm_pool.".into(), - ); - return; - } - let mmap_pool = match Pool::new(fd, size as usize, self.log.clone()) { - Ok(p) => p, - Err(()) => { - shm.post_error( - wl_shm::Error::InvalidFd as u32, - format!("Failed mmap of fd {}.", fd), - ); - return; - } - }; - let arc_pool = Box::new(Arc::new(mmap_pool)); - let pool = pool.implement_nonsend( - self.clone(), - Some(|pool: Resource<_>, _| { - drop(unsafe { Box::from_raw(pool.get_user_data() as *mut Arc) }) - }), - &self.token, - ); - pool.set_user_data(Box::into_raw(arc_pool) as *mut ()); - } + let Request::CreatePool { id: pool, fd, size } = request; + if size <= 0 { + shm.post_error( + Error::InvalidFd as u32, + "Invalid size for a new wl_shm_pool.".into(), + ); + return; } + let mmap_pool = match Pool::new(fd, size as usize, self.log.clone()) { + Ok(p) => p, + Err(()) => { + shm.post_error( + wl_shm::Error::InvalidFd as u32, + format!("Failed mmap of fd {}.", fd), + ); + return; + } + }; + let arc_pool = Arc::new(mmap_pool); + pool.implement_nonsend( + { + let mut data = self.clone(); + move |req, pool| data.receive_pool_message(req, pool) + }, + None::, + arc_pool, + &self.token, + ); } } @@ -224,11 +242,15 @@ struct InternalBufferData { data: BufferData, } -impl Implementation, wl_shm_pool::Request> for ShmGlobalData { - fn receive(&mut self, request: wl_shm_pool::Request, pool: Resource) { +impl ShmGlobalData { + fn receive_pool_message( + &mut self, + request: wl_shm_pool::Request, + pool: Resource, + ) { use self::wl_shm_pool::Request; - let arc_pool = unsafe { &*(pool.get_user_data() as *mut Arc) }; + let arc_pool = pool.user_data::>().unwrap(); match request { Request::CreateBuffer { @@ -246,7 +268,7 @@ impl Implementation, wl_shm_pool::Request> for ); return; } - let data = Box::into_raw(Box::new(InternalBufferData { + let data = InternalBufferData { pool: arc_pool.clone(), data: BufferData { offset, @@ -255,15 +277,16 @@ impl Implementation, wl_shm_pool::Request> for stride, format, }, - })); - let buffer = buffer.implement_nonsend( - self.clone(), - Some(|buffer: Resource<_>, _| { - drop(unsafe { Box::from_raw(buffer.get_user_data() as *mut InternalBufferData) }) - }), + }; + buffer.implement_nonsend( + |req, _| { + // this will break if a variant is added to wl_buffer::Request + let wl_buffer::Request::Destroy = req; + }, + None::, + data, &self.token, ); - buffer.set_user_data(data as *mut ()); } Request::Resize { size } => match arc_pool.resize(size) { Ok(()) => {} @@ -281,10 +304,3 @@ impl Implementation, wl_shm_pool::Request> for } } } - -impl Implementation, wl_buffer::Request> for ShmGlobalData { - fn receive(&mut self, request: wl_buffer::Request, _pool: Resource) { - // this will break if new requests are added to buffer =) - let wl_buffer::Request::Destroy = request; - } -} diff --git a/src/wayland/shm/pool.rs b/src/wayland/shm/pool.rs index 931119e..13e69b0 100644 --- a/src/wayland/shm/pool.rs +++ b/src/wayland/shm/pool.rs @@ -1,6 +1,6 @@ -use nix::{libc, unistd}; use nix::sys::mman; use nix::sys::signal::{self, SigAction, SigHandler, Signal}; +use nix::{libc, unistd}; use std::cell::Cell; use std::os::unix::io::RawFd; use std::ptr; diff --git a/src/xwayland/mod.rs b/src/xwayland/mod.rs index 5e21dd1..f4b91d0 100644 --- a/src/xwayland/mod.rs +++ b/src/xwayland/mod.rs @@ -1,4 +1,4 @@ -mod xserver; mod x11_sockets; +mod xserver; pub use self::xserver::{XWayland, XWindowManager}; diff --git a/src/xwayland/x11_sockets.rs b/src/xwayland/x11_sockets.rs index fd7d7d7..fc64e03 100644 --- a/src/xwayland/x11_sockets.rs +++ b/src/xwayland/x11_sockets.rs @@ -2,9 +2,9 @@ use std::io::{Read, Write}; use std::os::unix::io::FromRawFd; use std::os::unix::net::UnixStream; -use nix::{Error as NixError, Result as NixResult}; use nix::errno::Errno; use nix::sys::socket; +use nix::{Error as NixError, Result as NixResult}; /// Find a free X11 display slot and setup pub(crate) fn prepare_x11_sockets(log: ::slog::Logger) -> Result<(X11Lock, [UnixStream; 2]), ()> { @@ -62,11 +62,13 @@ impl X11Lock { let mut spid = [0u8; 11]; file.read_exact(&mut spid).map_err(|_| ())?; ::std::mem::drop(file); - let pid = ::nix::unistd::Pid::from_raw(::std::str::from_utf8(&spid) - .map_err(|_| ())? - .trim() - .parse::() - .map_err(|_| ())?); + let pid = ::nix::unistd::Pid::from_raw( + ::std::str::from_utf8(&spid) + .map_err(|_| ())? + .trim() + .parse::() + .map_err(|_| ())?, + ); if let Err(NixError::Sys(Errno::ESRCH)) = ::nix::sys::signal::kill(pid, None) { // no process whose pid equals the contents of the lockfile exists // remove the lockfile and try grabbing it again diff --git a/src/xwayland/xserver.rs b/src/xwayland/xserver.rs index 3240ff8..dfec5b6 100644 --- a/src/xwayland/xserver.rs +++ b/src/xwayland/xserver.rs @@ -25,21 +25,22 @@ * */ use std::cell::RefCell; -use std::rc::Rc; use std::env; use std::ffi::CString; use std::os::unix::io::{AsRawFd, IntoRawFd}; use std::os::unix::net::UnixStream; +use std::rc::Rc; -use nix::{Error as NixError, Result as NixResult}; use nix::errno::Errno; -use nix::unistd::{fork, ForkResult, Pid}; use nix::sys::signal; +use nix::unistd::{fork, ForkResult, Pid}; +use nix::{Error as NixError, Result as NixResult}; -use wayland_server::{Client, Display, LoopToken}; -use wayland_server::sources::{SignalEvent, Source}; +use wayland_server::calloop::signals::{Signal, Signals}; +use wayland_server::calloop::{LoopHandle, Source}; +use wayland_server::{Client, Display}; -use super::x11_sockets::{X11Lock, prepare_x11_sockets}; +use super::x11_sockets::{prepare_x11_sockets, X11Lock}; /// The XWayland handle pub struct XWayland { @@ -66,9 +67,9 @@ pub trait XWindowManager { impl XWayland { /// Start the XWayland server - pub fn init( + pub fn init( wm: WM, - token: LoopToken, + handle: LoopHandle, display: Rc>, logger: L, ) -> Result, ()> @@ -78,7 +79,16 @@ impl XWayland { let log = ::slog_or_stdlog(logger); let inner = Rc::new(RefCell::new(Inner { wm, - token, + source_maker: Box::new(move |inner| { + handle + .insert_source( + Signals::new(&[Signal::SIGUSR1]).map_err(|_| ())?, + move |evt, _| { + debug_assert!(evt.signal() == Signal::SIGUSR1); + xwayland_ready(&inner); + }, + ).map_err(|_| ()) + }), wayland_display: display, instance: None, log: log.new(o!("smithay_module" => "XWayland")), @@ -97,7 +107,7 @@ impl Drop for XWayland { struct XWaylandInstance { display_lock: X11Lock, wayland_client: Client, - sigusr1_handler: Option>, + sigusr1_handler: Option>, wm_fd: Option, started_at: ::std::time::Instant, child_pid: Option, @@ -106,7 +116,7 @@ struct XWaylandInstance { // Inner implementation of the XWayland manager struct Inner { wm: WM, - token: LoopToken, + source_maker: Box>>) -> Result, ()>>, wayland_display: Rc>, instance: Option, log: ::slog::Logger, @@ -140,17 +150,11 @@ fn launch(inner: &Rc>>) -> Resul .borrow_mut() .create_client(wl_me.into_raw_fd()) }; - client.set_user_data(Rc::into_raw(inner.clone()) as *const () as *mut ()); - client.set_destructor(client_destroy::); + client.data_map().insert_if_missing(|| inner.clone()); + client.add_destructor(client_destroy::); // setup the SIGUSR1 handler - let my_inner = inner.clone(); - let sigusr1_handler = guard - .token - .add_signal_event_source(signal::Signal::SIGUSR1, move |_, ()| { - xwayland_ready(&my_inner) - }) - .map_err(|_| ())?; + let sigusr1_handler = (&mut *guard.source_maker)(inner.clone())?; // all is ready, we can do the fork dance let child_pid = match fork() { @@ -242,8 +246,8 @@ impl Inner { } } -fn client_destroy(data: *mut ()) { - let inner = unsafe { Rc::from_raw(data as *const () as *const RefCell>) }; +fn client_destroy(map: &::wayland_server::UserDataMap) { + let inner = map.get::>>>().unwrap(); // shutdown the server let started_at = inner.borrow().instance.as_ref().map(|i| i.started_at); diff --git a/vagga.yaml b/vagga.yaml index 9518ea5..4505ce0 100644 --- a/vagga.yaml +++ b/vagga.yaml @@ -19,6 +19,9 @@ containers: - !Container base - !Env HOME: /work/.vagga/stable-home - !Sh curl https://sh.rustup.rs -sSf | sh -s -- -y --default-host x86_64-unknown-linux-gnu --default-toolchain stable --no-modify-path + - !Env PATH: /bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/work/.vagga/stable-home/.cargo/bin:/work/.vagga/stable-home/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/bin/ + - !Sh rustup self update + - !Sh rustup component add rustfmt-preview beta: auto-clean: true @@ -45,7 +48,7 @@ containers: - !Sh curl https://sh.rustup.rs -sSf | sh -s -- -y --default-host x86_64-unknown-linux-gnu --default-toolchain nightly --no-modify-path - !Env PATH: /bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/work/.vagga/nightly-home/.cargo/bin:/work/.vagga/nightly-home/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/ - !Sh rustup self update - - !Sh rustup component add rustfmt-preview + - !Sh rustup component add clippy-preview commands: update-stable: !Command