diff --git a/Cargo.toml b/Cargo.toml index c01f8a7..4f99f5b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,8 +7,8 @@ description = "Smithay is a library for writing wayland compositors." repository = "https://github.com/Smithay/smithay" [dependencies] -wayland-server = "0.12.5" -wayland-sys = "0.12.5" +wayland-server = "0.14.0" +wayland-sys = "0.14.0" nix = "0.9.0" xkbcommon = "0.2.1" tempfile = "2.1.5" @@ -24,7 +24,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.12.5", features = ["unstable_protocols", "server"] } +wayland-protocols = { version = "0.14.0", features = ["unstable_protocols", "server"] } image = "0.17.0" error-chain = "0.11.0" lazy_static = "1.0.0" diff --git a/examples/drm.rs b/examples/drm.rs index ad1e418..86e81b9 100644 --- a/examples/drm.rs +++ b/examples/drm.rs @@ -34,6 +34,7 @@ use std::os::unix::io::AsRawFd; use std::os::unix::io::RawFd; use std::rc::Rc; use std::time::Duration; +use wayland_server::EventLoopHandle; #[derive(Debug)] pub struct Card(File); @@ -137,17 +138,17 @@ fn main() { /* * Register the DrmDevice on the EventLoop */ - let device_token = event_loop.state().insert(device); let _source = drm_device_bind( &mut event_loop, - device_token, + device, DrmHandlerImpl { compositor_token, window_map: window_map.clone(), drawer: renderer, logger: log, }, - ).unwrap(); + ).map_err(|(err, _)| err) + .unwrap(); loop { event_loop.dispatch(Some(16)).unwrap(); @@ -166,7 +167,8 @@ pub struct DrmHandlerImpl { impl DrmHandler for DrmHandlerImpl { fn ready( - &mut self, _device: &mut DrmDevice, _crtc: crtc::Handle, _frame: u32, _duration: Duration + &mut self, _evlh: &mut EventLoopHandle, _device: &mut DrmDevice, _crtc: crtc::Handle, + _frame: u32, _duration: Duration, ) { let mut frame = self.drawer.draw(); frame.clear_color(0.8, 0.8, 0.9, 1.0); @@ -246,7 +248,7 @@ impl DrmHandler for DrmHandlerImpl { frame.finish().unwrap(); } - fn error(&mut self, _device: &mut DrmDevice, error: DrmError) { + fn error(&mut self, _evlh: &mut EventLoopHandle, _device: &mut DrmDevice, error: DrmError) { panic!("{:?}", error); } } diff --git a/examples/udev.rs b/examples/udev.rs index 4fd1a66..cfe5134 100644 --- a/examples/udev.rs +++ b/examples/udev.rs @@ -54,8 +54,9 @@ use std::rc::Rc; use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; use std::time::Duration; -use wayland_server::{Display, EventLoopHandle, StateProxy, StateToken}; +use wayland_server::{Display, EventLoopHandle}; use wayland_server::protocol::{wl_output, wl_pointer}; +use wayland_server::sources::EventSource; use xkbcommon::xkb::keysyms as xkb; struct LibinputInputHandler { @@ -270,7 +271,7 @@ fn main() { let primary_gpu = primary_gpu(&context, &seat).unwrap_or_default(); let bytes = include_bytes!("resources/cursor2.rgba"); - let udev_token = UdevBackend::new( + let mut udev_backend = UdevBackend::new( &mut event_loop, &context, session.clone(), @@ -288,7 +289,7 @@ fn main() { log.clone(), ).unwrap(); - let udev_session_id = notifier.register(udev_token.clone()); + let udev_session_id = notifier.register(&mut udev_backend); let (seat_token, _) = Seat::new(&mut event_loop, session.seat().into(), log.clone()); @@ -339,7 +340,7 @@ fn main() { */ let mut libinput_context = Libinput::new_from_udev::>(session.clone().into(), &context); - let libinput_session_id = notifier.register(libinput_context.clone()); + let libinput_session_id = notifier.register(&mut libinput_context); libinput_context.udev_assign_seat(&seat).unwrap(); let mut libinput_backend = LibinputInputBackend::new(libinput_context, log.clone()); libinput_backend.set_handler( @@ -356,10 +357,16 @@ fn main() { running: running.clone(), }, ); - let libinput_event_source = libinput_bind(libinput_backend, &mut event_loop).unwrap(); + let libinput_event_source = libinput_bind(libinput_backend, &mut event_loop) + .map_err(|(err, _)| err) + .unwrap(); - let session_event_source = auto_session_bind(notifier, &mut event_loop).unwrap(); - let udev_event_source = udev_backend_bind(&mut event_loop, udev_token).unwrap(); + let session_event_source = auto_session_bind(notifier, &mut event_loop) + .map_err(|(err, _)| err) + .unwrap(); + let udev_event_source = udev_backend_bind(&mut event_loop, udev_backend) + .map_err(|(err, _)| err) + .unwrap(); while running.load(Ordering::SeqCst) { if let Err(_) = event_loop.dispatch(Some(16)) { @@ -378,9 +385,8 @@ fn main() { libinput_event_source.remove(); - let udev_token = udev_event_source.remove(); - let udev = event_loop.state().remove(udev_token); - udev.close(event_loop.state()); + // destroy the udev backend freeing the drm devices + udev_event_source.remove().close(&mut event_loop) } struct UdevHandlerImpl { @@ -455,8 +461,8 @@ impl UdevHandlerImpl { } impl UdevHandler for UdevHandlerImpl { - fn device_added<'a, S: Into>>( - &mut self, _state: S, device: &mut DrmDevice + fn device_added( + &mut self, _evlh: &mut EventLoopHandle, device: &mut DrmDevice ) -> Option { // init hardware acceleration on the primary gpu. if device.dev_path().and_then(|path| path.canonicalize().ok()) == self.primary_gpu { @@ -475,21 +481,13 @@ impl UdevHandler for UdevHandlerImpl { }) } - fn device_changed<'a, S: Into>>( - &mut self, state: S, device: &StateToken> - ) { + fn device_changed(&mut self, _evlh: &mut EventLoopHandle, device: &mut DrmDevice) { //quick and dirt, just re-init all backends - let mut state = state.into(); - let backends = self.backends.get(&state.get(device).device_id()).unwrap(); - *backends.borrow_mut() = self.scan_connectors(state.get_mut(device)); + let backends = self.backends.get(&device.device_id()).unwrap(); + *backends.borrow_mut() = self.scan_connectors(device); } - fn device_removed<'a, S: Into>>( - &mut self, state: S, device: &StateToken> - ) { - let state = state.into(); - let device = state.get(device); - + fn device_removed(&mut self, _evlh: &mut EventLoopHandle, device: &mut DrmDevice) { // drop the backends on this side self.backends.remove(&device.device_id()); @@ -499,7 +497,7 @@ impl UdevHandler for UdevHandlerImpl { } } - fn error<'a, S: Into>>(&mut self, _state: S, error: IoError) { + fn error(&mut self, _evlh: &mut EventLoopHandle, error: IoError) { error!(self.logger, "{:?}", error); } } @@ -514,8 +512,8 @@ pub struct DrmHandlerImpl { impl DrmHandler for DrmHandlerImpl { fn ready( - &mut self, _device: &mut DrmDevice, crtc: crtc::Handle, _frame: u32, - _duration: Duration, + &mut self, _evlh: &mut EventLoopHandle, _device: &mut DrmDevice, + crtc: crtc::Handle, _frame: u32, _duration: Duration, ) { if let Some(drawer) = self.backends.borrow().get(&crtc) { { @@ -605,7 +603,9 @@ impl DrmHandler for DrmHandlerImpl { } } - fn error(&mut self, _device: &mut DrmDevice, error: DrmError) { + fn error( + &mut self, _evlh: &mut EventLoopHandle, _device: &mut DrmDevice, error: DrmError + ) { error!(self.logger, "{:?}", error); } } diff --git a/src/backend/drm/mod.rs b/src/backend/drm/mod.rs index d4260e5..91fe4b3 100644 --- a/src/backend/drm/mod.rs +++ b/src/backend/drm/mod.rs @@ -52,7 +52,6 @@ //! use std::os::unix::io::RawFd; //! use std::os::unix::io::AsRawFd; //! use smithay::backend::drm::{DrmDevice, DrmBackend}; -//! use wayland_server::StateToken; //! //! #[derive(Debug)] //! pub struct Card(File); @@ -140,6 +139,7 @@ //! # use std::time::Duration; //! use smithay::backend::drm::{DrmDevice, DrmBackend, DrmHandler, drm_device_bind}; //! use smithay::backend::graphics::egl::EGLGraphicsBackend; +//! use wayland_server::EventLoopHandle; //! # //! # #[derive(Debug)] //! # pub struct Card(File); @@ -181,6 +181,7 @@ //! impl DrmHandler for MyDrmHandler { //! fn ready( //! &mut self, +//! _evlh: &mut EventLoopHandle, //! _device: &mut DrmDevice, //! _crtc: CrtcHandle, //! _frame: u32, @@ -191,6 +192,7 @@ //! } //! fn error( //! &mut self, +//! _evlh: &mut EventLoopHandle, //! device: &mut DrmDevice, //! error: DrmError) //! { @@ -201,8 +203,7 @@ //! // render something (like clear_color) //! backend.swap_buffers().unwrap(); //! -//! let device_token = event_loop.state().insert(device); -//! let _source = drm_device_bind(&mut event_loop, device_token, MyDrmHandler(backend)).unwrap(); +//! let _source = drm_device_bind(&mut event_loop, device, MyDrmHandler(backend)).map_err(|(err, _)| err).unwrap(); //! //! event_loop.run().unwrap(); //! # } @@ -213,7 +214,7 @@ use backend::graphics::egl::error::Result as EGLResult; use backend::graphics::egl::native::Gbm; use backend::graphics::egl::wayland::{EGLDisplay, EGLWaylandExtensions}; #[cfg(feature = "backend_session")] -use backend::session::SessionObserver; +use backend::session::{AsSessionObserver, SessionObserver}; use drm::Device as BasicDevice; use drm::control::{connector, crtc, encoder, Mode, ResourceInfo}; use drm::control::Device as ControlDevice; @@ -222,17 +223,17 @@ use drm::result::Error as DrmError; use gbm::{BufferObject, Device as GbmDevice}; use nix; use nix::sys::stat::{self, dev_t, fstat}; +use std::cell::RefCell; use std::collections::HashMap; use std::hash::{Hash, Hasher}; -use std::io::Result as IoResult; +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::{Once, ONCE_INIT}; +use std::sync::{Arc, Once, ONCE_INIT}; +use std::sync::atomic::{AtomicBool, Ordering}; use std::time::Duration; -use wayland_server::{Display, EventLoopHandle, StateToken}; -#[cfg(feature = "backend_session")] -use wayland_server::StateProxy; +use wayland_server::{Display, EventLoopHandle}; use wayland_server::sources::{FdEventSource, FdEventSourceImpl, FdInterest}; mod backend; @@ -249,8 +250,8 @@ pub struct DrmDevice { context: Rc, GbmDevice>>, old_state: HashMap)>, device_id: dev_t, - backends: HashMap>>, - active: bool, + backends: Rc>>>>, + active: Arc, priviledged: bool, logger: ::slog::Logger, } @@ -316,10 +317,10 @@ impl DrmDevice { Default::default(), log.clone(), ).map_err(Error::from)?), - backends: HashMap::new(), + backends: Rc::new(RefCell::new(HashMap::new())), device_id, old_state: HashMap::new(), - active: true, + active: Arc::new(AtomicBool::new(true)), priviledged: true, logger: log.clone(), }; @@ -382,11 +383,11 @@ impl DrmDevice { where I: Into>, { - if self.backends.contains_key(&crtc) { + if self.backends.borrow().contains_key(&crtc) { bail!(ErrorKind::CrtcAlreadyInUse(crtc)); } - if !self.active { + if !self.active.load(Ordering::SeqCst) { bail!(ErrorKind::DeviceInactive); } @@ -441,7 +442,7 @@ impl DrmDevice { let logger = self.logger.new(o!("crtc" => format!("{:?}", crtc))); let backend = DrmBackend::new(self.context.clone(), crtc, mode, connectors, logger)?; - self.backends.insert(crtc, backend.weak()); + self.backends.borrow_mut().insert(crtc, backend.weak()); Ok(backend) } @@ -531,25 +532,28 @@ impl Drop for DrmDevice { pub trait DrmHandler { /// The `DrmBackend` of crtc has finished swapping buffers and new frame can now /// (and should be immediately) be rendered. - fn ready(&mut self, device: &mut DrmDevice, crtc: crtc::Handle, frame: u32, duration: Duration); + fn ready( + &mut self, evlh: &mut EventLoopHandle, device: &mut DrmDevice, crtc: crtc::Handle, frame: u32, + duration: Duration, + ); /// The `DrmDevice` has thrown an error. /// /// The related backends are most likely *not* usable anymore and /// the whole stack has to be recreated.. - fn error(&mut self, device: &mut DrmDevice, error: DrmError); + fn error(&mut self, evlh: &mut EventLoopHandle, device: &mut DrmDevice, error: DrmError); } /// Bind a `DrmDevice` to an `EventLoop`, /// /// This will cause it to recieve events and feed them into an `DrmHandler` pub fn drm_device_bind( - evlh: &mut EventLoopHandle, device: StateToken>, handler: H -) -> IoResult>, H)>> + evlh: &mut EventLoopHandle, device: DrmDevice, handler: H +) -> ::std::result::Result, H)>, (IoError, (DrmDevice, H))> where A: ControlDevice + 'static, H: DrmHandler + 'static, { - let fd = evlh.state().get(&device).as_raw_fd(); + let fd = device.as_raw_fd(); evlh.add_fd_event_source( fd, fd_event_source_implementation(), @@ -558,26 +562,19 @@ where ) } -fn fd_event_source_implementation() -> FdEventSourceImpl<(StateToken>, H)> +fn fd_event_source_implementation() -> FdEventSourceImpl<(DrmDevice, H)> where A: ControlDevice + 'static, H: DrmHandler + 'static, { FdEventSourceImpl { - ready: |evlh, &mut (ref mut dev_token, ref mut handler), _, _| { - let (events, logger) = { - let dev = evlh.state().get(dev_token); - let events = crtc::receive_events(dev); - let logger = dev.logger.clone(); - (events, logger) - }; - - match events { + ready: |evlh, &mut (ref mut device, ref mut handler), _, _| { + match crtc::receive_events(device) { Ok(events) => for event in events { if let crtc::Event::PageFlip(event) = event { - let dev = evlh.state().get_mut(dev_token); - if dev.active { - if let Some(backend) = dev.backends + 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()) @@ -585,91 +582,120 @@ where { // we can now unlock the buffer backend.unlock_buffer(); - trace!(logger, "Handling event for backend {:?}", event.crtc); + trace!(device.logger, "Handling event for backend {:?}", event.crtc); // and then call the user to render the next frame - handler.ready(dev, event.crtc, event.frame, event.duration); + handler.ready(evlh, device, event.crtc, event.frame, event.duration); } else { - dev.backends.remove(&event.crtc); + device.backends.borrow_mut().remove(&event.crtc); } } } }, - Err(err) => handler.error(evlh.state().get_mut(dev_token), err), + Err(err) => handler.error(evlh, device, err), }; }, - error: |evlh, &mut (ref mut dev_token, ref mut handler), _, error| { - let mut dev = evlh.state().get_mut(dev_token); - warn!(dev.logger, "DrmDevice errored: {}", error); - handler.error(&mut dev, error.into()); + error: |evlh, &mut (ref mut device, ref mut handler), _, error| { + warn!(device.logger, "DrmDevice errored: {}", error); + handler.error(evlh, device, error.into()); }, } } +/// `SessionObserver` linked to the `DrmDevice` it was created from. +pub struct DrmDeviceObserver { + context: Weak, GbmDevice>>, + device_id: dev_t, + backends: Rc>>>>, + old_state: HashMap)>, + active: Arc, + priviledged: bool, + logger: ::slog::Logger, +} + #[cfg(feature = "backend_session")] -impl SessionObserver for StateToken> { - fn pause<'a>(&mut self, state: &mut StateProxy<'a>, devnum: Option<(u32, u32)>) { - let device = state.get_mut(self); +impl AsSessionObserver> for DrmDevice { + fn observer(&mut self) -> DrmDeviceObserver { + DrmDeviceObserver { + context: Rc::downgrade(&self.context), + device_id: self.device_id.clone(), + backends: self.backends.clone(), + old_state: self.old_state.clone(), + active: self.active.clone(), + priviledged: self.priviledged, + logger: self.logger.clone(), + } + } +} + +#[cfg(feature = "backend_session")] +impl SessionObserver for DrmDeviceObserver { + fn pause(&mut self, _evlh: &mut EventLoopHandle, devnum: Option<(u32, u32)>) { if let Some((major, minor)) = devnum { - if major as u64 != stat::major(device.device_id) || minor as u64 != stat::minor(device.device_id) - { + if major as u64 != stat::major(self.device_id) || minor as u64 != stat::minor(self.device_id) { return; } } - for (handle, &(ref info, ref connectors)) in device.old_state.iter() { - if let Err(err) = crtc::set( - &*device.context, - *handle, - info.fb(), - connectors, - info.position(), - info.mode(), - ) { - error!( - device.logger, - "Failed to reset crtc ({:?}). Error: {}", handle, err - ); + if let Some(device) = self.context.upgrade() { + for (handle, &(ref info, ref connectors)) in self.old_state.iter() { + if let Err(err) = crtc::set( + &*device, + *handle, + info.fb(), + connectors, + info.position(), + info.mode(), + ) { + error!( + self.logger, + "Failed to reset crtc ({:?}). Error: {}", handle, err + ); + } } } - device.active = false; - if device.priviledged { - if let Err(err) = device.drop_master() { - error!( - device.logger, - "Failed to drop drm master state. Error: {}", err - ); + self.active.store(false, Ordering::SeqCst); + 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 + ); + } } } } - fn activate<'a>(&mut self, state: &mut StateProxy<'a>, devnum: Option<(u32, u32, Option)>) { - let device = state.get_mut(self); + fn activate(&mut self, _evlh: &mut EventLoopHandle, devnum: Option<(u32, u32, Option)>) { if let Some((major, minor, fd)) = devnum { - if major as u64 != stat::major(device.device_id) || minor as u64 != stat::minor(device.device_id) - { + if major as u64 != stat::major(self.device_id) || minor as u64 != stat::minor(self.device_id) { return; } else if let Some(fd) = fd { - info!(device.logger, "Replacing fd"); - nix::unistd::dup2(device.as_raw_fd(), fd) - .expect("Failed to replace file descriptor of drm device"); + info!(self.logger, "Replacing fd"); + if let Some(device) = self.context.upgrade() { + nix::unistd::dup2(device.as_raw_fd(), fd) + .expect("Failed to replace file descriptor of drm device"); + } } } - device.active = true; - if device.priviledged { - if let Err(err) = device.set_master() { - crit!( - device.logger, - "Failed to acquire drm master again. Error: {}", - err - ); + self.active.store(true, Ordering::SeqCst); + 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 + ); + } } } let mut crtcs = Vec::new(); - for (crtc, backend) in device.backends.iter() { + for (crtc, backend) in self.backends.borrow().iter() { if let Some(backend) = backend.upgrade() { backend.unlock_buffer(); if let Err(err) = backend.page_flip(None) { error!( - device.logger, + self.logger, "Failed to activate crtc ({:?}) again. Error: {}", crtc, err ); } @@ -685,7 +711,7 @@ impl SessionObserver for StateToken> { ).is_err() { if let Err(err) = crtc::set_cursor(&*backend.context, *crtc, cursor) { - error!(device.logger, "Failed to reset cursor. Error: {}", err); + error!(self.logger, "Failed to reset cursor. Error: {}", err); } } } @@ -694,7 +720,7 @@ impl SessionObserver for StateToken> { } } for crtc in crtcs { - device.backends.remove(&crtc); + self.backends.borrow_mut().remove(&crtc); } } } diff --git a/src/backend/libinput.rs b/src/backend/libinput.rs index c43dc96..07f6561 100644 --- a/src/backend/libinput.rs +++ b/src/backend/libinput.rs @@ -7,11 +7,11 @@ use input as libinput; use input::event; use std::collections::hash_map::{DefaultHasher, Entry, HashMap}; use std::hash::{Hash, Hasher}; -use std::io::{Error as IoError, Result as IoResult}; +use std::io::Error as IoError; use std::os::unix::io::RawFd; use std::path::Path; use std::rc::Rc; -use wayland_server::{EventLoopHandle, StateProxy}; +use wayland_server::EventLoopHandle; use wayland_server::sources::{FdEventSource, FdEventSourceImpl, FdInterest}; // No idea if this is the same across unix platforms @@ -586,7 +586,7 @@ impl From for backend::MouseButtonState { #[cfg(feature = "backend_session")] impl SessionObserver for libinput::Libinput { - fn pause<'a>(&mut self, _state: &mut StateProxy<'a>, device: Option<(u32, u32)>) { + fn pause(&mut self, _state: &mut EventLoopHandle, device: Option<(u32, u32)>) { if let Some((major, _)) = device { if major != INPUT_MAJOR { return; @@ -596,7 +596,7 @@ impl SessionObserver for libinput::Libinput { self.suspend() } - fn activate<'a>(&mut self, _state: &mut StateProxy<'a>, _device: Option<(u32, u32, Option)>) { + fn activate(&mut self, _state: &mut EventLoopHandle, _device: Option<(u32, u32, Option)>) { // libinput closes the devices on suspend, so we should not get any INPUT_MAJOR calls // also lets hope multiple resumes are okay in case of logind self.resume().expect("Unable to resume libinput context"); @@ -635,7 +635,7 @@ impl libinput::LibinputInterface for LibinputSessionInterface { /// `dispatch_new_events`. Should be used to achieve the smallest possible latency. pub fn libinput_bind( backend: LibinputInputBackend, evlh: &mut EventLoopHandle -) -> IoResult> { +) -> ::std::result::Result, (IoError, LibinputInputBackend)> { let fd = unsafe { backend.context.fd() }; evlh.add_fd_event_source( fd, diff --git a/src/backend/session/auto.rs b/src/backend/session/auto.rs index 7c6530a..c65d5ad 100644 --- a/src/backend/session/auto.rs +++ b/src/backend/session/auto.rs @@ -29,18 +29,18 @@ //! automatically by the `UdevBackend`, if not done manually). //! ``` -use super::{AsErrno, Session, SessionNotifier, SessionObserver}; +use super::{AsErrno, AsSessionObserver, Session, SessionNotifier, SessionObserver}; use super::direct::{self, direct_session_bind, DirectSession, DirectSessionNotifier}; #[cfg(feature = "backend_session_logind")] use super::logind::{self, logind_session_bind, BoundLogindSession, LogindSession, LogindSessionNotifier}; use nix::fcntl::OFlag; use std::cell::RefCell; -use std::io::Result as IoResult; +use std::io::Error as IoError; use std::os::unix::io::RawFd; use std::path::Path; use std::rc::Rc; use wayland_server::EventLoopHandle; -use wayland_server::sources::SignalEventSource; +use wayland_server::sources::{EventSource, SignalEventSource}; /// `Session` using the best available inteface #[derive(Clone)] @@ -154,11 +154,13 @@ impl AutoSession { /// session state and call it's `SessionObservers`. pub fn auto_session_bind( notifier: AutoSessionNotifier, evlh: &mut EventLoopHandle -) -> IoResult { +) -> ::std::result::Result { Ok(match notifier { #[cfg(feature = "backend_session_logind")] - AutoSessionNotifier::Logind(logind) => BoundAutoSession::Logind(logind_session_bind(logind, evlh)?), - AutoSessionNotifier::Direct(direct) => BoundAutoSession::Direct(direct_session_bind(direct, evlh)?), + AutoSessionNotifier::Logind(logind) => BoundAutoSession::Logind(logind_session_bind(logind, evlh) + .map_err(|(error, notifier)| (error, AutoSessionNotifier::Logind(notifier)))?), + AutoSessionNotifier::Direct(direct) => BoundAutoSession::Direct(direct_session_bind(direct, evlh) + .map_err(|(error, notifier)| (error, AutoSessionNotifier::Direct(notifier)))?), }) } @@ -207,7 +209,9 @@ impl Session for AutoSession { impl SessionNotifier for AutoSessionNotifier { type Id = AutoId; - fn register(&mut self, signal: S) -> Self::Id { + fn register>( + &mut self, signal: &mut A + ) -> Self::Id { match self { #[cfg(feature = "backend_session_logind")] &mut AutoSessionNotifier::Logind(ref mut logind) => { diff --git a/src/backend/session/dbus/logind.rs b/src/backend/session/dbus/logind.rs index 84918a3..54a3e4c 100644 --- a/src/backend/session/dbus/logind.rs +++ b/src/backend/session/dbus/logind.rs @@ -30,20 +30,20 @@ //! automatically by the `UdevBackend`, if not done manually). //! ``` -use backend::session::{AsErrno, Session, SessionNotifier, SessionObserver}; +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 nix::fcntl::OFlag; use nix::sys::stat::{fstat, major, minor, stat}; use std::cell::RefCell; -use std::io::Result as IoResult; +use std::io::Error as IoError; use std::os::unix::io::RawFd; use std::path::Path; use std::rc::{Rc, Weak}; use std::sync::atomic::{AtomicBool, Ordering}; use systemd::login; use wayland_server::EventLoopHandle; -use wayland_server::sources::{FdEventSource, FdEventSourceImpl, FdInterest}; +use wayland_server::sources::{EventSource, FdEventSource, FdEventSourceImpl, FdInterest}; struct LogindSessionImpl { conn: RefCell, @@ -246,7 +246,7 @@ impl LogindSessionImpl { //So lets just put it to sleep.. forever for signal in &mut *self.signals.borrow_mut() { if let &mut Some(ref mut signal) = signal { - signal.pause(&mut evlh.state().as_proxy(), None); + signal.pause(evlh, None); } } self.active.store(false, Ordering::SeqCst); @@ -263,7 +263,7 @@ impl LogindSessionImpl { ); for signal in &mut *self.signals.borrow_mut() { if let &mut Some(ref mut signal) = signal { - signal.pause(&mut evlh.state().as_proxy(), Some((major, minor))); + signal.pause(evlh, Some((major, minor))); } } // the other possible types are "force" or "gone" (unplugged), @@ -289,7 +289,7 @@ impl LogindSessionImpl { debug!(self.logger, "Reactivating device ({},{})", major, minor); for signal in &mut *self.signals.borrow_mut() { if let &mut Some(ref mut signal) = signal { - signal.activate(&mut evlh.state().as_proxy(), Some((major, minor, Some(fd)))); + signal.activate(evlh, Some((major, minor, Some(fd)))); } } } @@ -392,11 +392,13 @@ pub struct Id(usize); impl SessionNotifier for LogindSessionNotifier { type Id = Id; - fn register(&mut self, signal: S) -> Id { + fn register>( + &mut self, signal: &mut A + ) -> Self::Id { self.internal .signals .borrow_mut() - .push(Some(Box::new(signal))); + .push(Some(Box::new(signal.observer()))); Id(self.internal.signals.borrow().len() - 1) } fn unregister(&mut self, signal: Id) { @@ -430,8 +432,10 @@ pub struct BoundLogindSession { /// session state and call it's `SessionObservers`. pub fn logind_session_bind( notifier: LogindSessionNotifier, evlh: &mut EventLoopHandle -) -> IoResult { +) -> ::std::result::Result { let watches = notifier.internal.conn.borrow().watch_fds(); + + let internal_for_error = notifier.internal.clone(); let sources = watches .clone() .into_iter() @@ -446,7 +450,15 @@ pub fn logind_session_bind( interest, ) }) - .collect::>>>>()?; + .collect::<::std::result::Result>>, (IoError, _)>>() + .map_err(|(err, _)| { + ( + err, + LogindSessionNotifier { + internal: internal_for_error, + }, + ) + })?; Ok(BoundLogindSession { notifier, diff --git a/src/backend/session/direct.rs b/src/backend/session/direct.rs index e8c8e27..eaeded8 100644 --- a/src/backend/session/direct.rs +++ b/src/backend/session/direct.rs @@ -45,14 +45,14 @@ //! for notifications are the `Libinput` context, the `UdevBackend` or a `DrmDevice` (handled //! automatically by the `UdevBackend`, if not done manually). -use super::{AsErrno, Session, SessionNotifier, SessionObserver}; +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 std::io::Result as IoResult; +use std::io::Error as IoError; use std::os::unix::io::RawFd; use std::path::Path; use std::sync::Arc; @@ -344,8 +344,10 @@ pub struct Id(usize); impl SessionNotifier for DirectSessionNotifier { type Id = Id; - fn register(&mut self, signal: S) -> Id { - self.signals.push(Some(Box::new(signal))); + fn register>( + &mut self, signal: &mut A + ) -> Self::Id { + self.signals.push(Some(Box::new(signal.observer()))); Id(self.signals.len() - 1) } fn unregister(&mut self, signal: Id) { @@ -367,7 +369,7 @@ impl SessionNotifier for DirectSessionNotifier { /// session state and call it's `SessionObservers`. pub fn direct_session_bind( notifier: DirectSessionNotifier, evlh: &mut EventLoopHandle -) -> IoResult> { +) -> ::std::result::Result, (IoError, DirectSessionNotifier)> { let signal = notifier.signal; evlh.add_signal_event_source( @@ -376,7 +378,7 @@ pub fn direct_session_bind( info!(notifier.logger, "Session shall become inactive"); for signal in &mut notifier.signals { if let &mut Some(ref mut signal) = signal { - signal.pause(&mut evlh.state().as_proxy(), None); + signal.pause(evlh, None); } } notifier.active.store(false, Ordering::SeqCst); @@ -391,7 +393,7 @@ pub fn direct_session_bind( } for signal in &mut notifier.signals { if let &mut Some(ref mut signal) = signal { - signal.activate(&mut evlh.state().as_proxy(), None); + signal.activate(evlh, None); } } notifier.active.store(true, Ordering::SeqCst); diff --git a/src/backend/session/mod.rs b/src/backend/session/mod.rs index d0a3320..a11c6d3 100644 --- a/src/backend/session/mod.rs +++ b/src/backend/session/mod.rs @@ -16,7 +16,7 @@ use std::os::unix::io::RawFd; use std::path::Path; use std::rc::Rc; use std::sync::{Arc, Mutex}; -use wayland_server::StateProxy; +use wayland_server::EventLoopHandle; /// General session interface. /// @@ -53,7 +53,8 @@ pub trait SessionNotifier { /// Registers a given `SessionObserver`. /// /// Returns an id of the inserted observer, can be used to remove it again. - fn register(&mut self, signal: S) -> Self::Id; + fn register>(&mut self, signal: &mut A) + -> Self::Id; /// Removes an observer by its given id from `SessionNotifier::register`. fn unregister(&mut self, signal: Self::Id); @@ -63,6 +64,20 @@ pub trait SessionNotifier { fn seat(&self) -> &str; } +/// Trait describing the ability to return a `SessionObserver` related to Self. +/// +/// The returned `SessionObserver` is responsible to handle the `pause` and `activate` signals. +pub trait AsSessionObserver { + /// Create a `SessionObserver` linked to this object + fn observer(&mut self) -> S; +} + +impl AsSessionObserver for T { + fn observer(&mut self) -> T { + self.clone() + } +} + /// Trait describing the ability to be notified when the session pauses or becomes active again. /// /// It might be impossible to interact with devices while the session is disabled. @@ -70,24 +85,18 @@ pub trait SessionNotifier { pub trait SessionObserver { /// Session/Device is about to be paused. /// - /// In case the implementor is a `StateToken` the state of the `EventLoop` - /// is provided via a `StateProxy`. - /// /// If only a specific device shall be closed a device number in the form of /// (major, minor) is provided. All observers not using the specified device should /// ignore the signal in that case. - fn pause<'a>(&mut self, state: &mut StateProxy<'a>, device: Option<(u32, u32)>); + fn pause(&mut self, evlh: &mut EventLoopHandle, device: Option<(u32, u32)>); /// Session/Device got active again /// - /// In case the implementor is a `StateToken` the state of the `EventLoop` - /// is provided via a `StateProxy`. - /// /// If only a specific device shall be activated again a device number in the form of /// (major, major, Option) is provided. Optionally the session may decide to replace /// the currently open file descriptor of the device with a new one. In that case the old one /// should not be used anymore and be closed. All observers not using the specified device should /// ignore the signal in that case. - fn activate<'a>(&mut self, state: &mut StateProxy<'a>, device: Option<(u32, u32, Option)>); + fn activate(&mut self, evlh: &mut EventLoopHandle, device: Option<(u32, u32, Option)>); } impl Session for () { diff --git a/src/backend/udev.rs b/src/backend/udev.rs index aad9472..c849d27 100644 --- a/src/backend/udev.rs +++ b/src/backend/udev.rs @@ -10,20 +10,22 @@ //! backend. use backend::drm::{drm_device_bind, DrmDevice, DrmHandler}; -use backend::session::{Session, SessionObserver}; +use backend::session::{AsSessionObserver, Session, SessionObserver}; use drm::Device as BasicDevice; use drm::control::Device as ControlDevice; use nix::fcntl; use nix::sys::stat::dev_t; +use std::cell::RefCell; use std::collections::HashMap; use std::ffi::OsString; -use std::io::{Error as IoError, Result as IoResult}; +use std::io::Error as IoError; use std::mem::drop; 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::{EventLoopHandle, StateProxy, StateToken}; -use wayland_server::sources::{FdEventSource, FdEventSourceImpl, FdInterest}; +use wayland_server::EventLoopHandle; +use wayland_server::sources::{EventSource, FdEventSource, FdEventSourceImpl, FdInterest}; /// Udev's `DrmDevice` type based on the underlying session pub struct SessionFdDrmDevice(RawFd); @@ -46,13 +48,7 @@ pub struct UdevBackend< S: Session + 'static, T: UdevHandler + 'static, > { - devices: HashMap< - dev_t, - ( - StateToken>, - FdEventSource<(StateToken>, H)>, - ), - >, + devices: Rc, H)>>>>, monitor: MonitorSocket, session: S, handler: T, @@ -72,7 +68,7 @@ impl + 'static, S: Session + 'static, T: UdevH /// `logger` - slog Logger to be used by the backend and its `DrmDevices`. pub fn new<'a, L>( mut evlh: &mut EventLoopHandle, context: &Context, mut session: S, mut handler: T, logger: L - ) -> Result>> + ) -> Result> where L: Into>, { @@ -96,21 +92,21 @@ impl + 'static, S: Session + 'static, T: UdevH ) { // Call the handler, which might add it to the runloop Ok(mut device) => { - let fd = device.as_raw_fd(); let devnum = device.device_id(); - match handler.device_added(&mut evlh.state().as_proxy(), &mut device) { + let fd = device.as_raw_fd(); + match handler.device_added(evlh, &mut device) { Some(drm_handler) => { - let token = evlh.state().insert(device); - if let Ok(event_source) = drm_device_bind(&mut evlh, token.clone(), drm_handler) { - Some((devnum, (token, event_source))) - } else { - handler.device_removed(evlh.state(), &token); - let device = evlh.state().remove(token); - drop(device); - if let Err(err) = session.close(fd) { - warn!(logger, "Failed to close dropped device. Error: {:?}. Ignoring", err); - }; - None + match drm_device_bind(&mut evlh, device, drm_handler) { + Ok(event_source) => Some((devnum, event_source)), + Err((err, (mut device, _))) => { + warn!(logger, "Failed to bind device. Error: {:?}.", err); + handler.device_removed(evlh, &mut device); + drop(device); + if let Err(err) = session.close(fd) { + warn!(logger, "Failed to close dropped device. Error: {:?}. Ignoring", err); + }; + None + } } }, None => { @@ -128,7 +124,7 @@ impl + 'static, S: Session + 'static, T: UdevH } } }) - .collect::>, FdEventSource<(StateToken>, H)>)>>(); + .collect::, H)>>>(); let mut builder = MonitorBuilder::new(context).chain_err(|| ErrorKind::FailedToInitMonitor)?; builder @@ -138,29 +134,21 @@ impl + 'static, S: Session + 'static, T: UdevH .listen() .chain_err(|| ErrorKind::FailedToInitMonitor)?; - Ok(evlh.state().insert(UdevBackend { - devices, + Ok(UdevBackend { + devices: Rc::new(RefCell::new(devices)), monitor, session, handler, logger, - })) + }) } /// Closes the udev backend and frees all remaining open devices. - /// - /// Needs to be called after the `FdEventSource` was removed and the backend was removed from - /// the `EventLoop`'s `State`. - /// - /// ## Panics - /// The given state might be passed to the registered `UdevHandler::device_removed` callback. - /// Make sure not to borrow any tokens twice. - pub fn close<'a, ST: Into>>(mut self, state: ST) { - let mut state = state.into(); - for (_, (device, event_source)) in self.devices.drain() { - event_source.remove(); - self.handler.device_removed(&mut state, &device); - let device = state.remove(device); + pub fn close(&mut self, evlh: &mut EventLoopHandle) { + let mut devices = self.devices.borrow_mut(); + for (_, event_source) in devices.drain() { + let (mut device, _) = event_source.remove(); + self.handler.device_removed(evlh, &mut device); let fd = device.as_raw_fd(); drop(device); if let Err(err) = self.session.close(fd) { @@ -174,26 +162,47 @@ impl + 'static, S: Session + 'static, T: UdevH } } +/// `SessionObserver` linked to the `UdevBackend` it was created from. +pub struct UdevBackendObserver + 'static> { + devices: Weak, H)>>>>, + logger: ::slog::Logger, +} + impl< H: DrmHandler + 'static, S: Session + 'static, T: UdevHandler + 'static, -> SessionObserver for StateToken> +> AsSessionObserver> for UdevBackend { - fn pause<'a>(&mut self, state: &mut StateProxy<'a>, devnum: Option<(u32, u32)>) { - state.with_value(self, |state, udev| { - for &mut (ref mut device, _) in udev.devices.values_mut() { - device.pause(state, devnum); + fn observer(&mut self) -> UdevBackendObserver { + UdevBackendObserver { + devices: Rc::downgrade(&self.devices), + logger: self.logger.clone(), + } + } +} + +impl + 'static> SessionObserver for UdevBackendObserver { + fn pause<'a>(&mut self, evlh: &mut EventLoopHandle, devnum: Option<(u32, u32)>) { + if let Some(devices) = self.devices.upgrade() { + for fd_event_source in devices.borrow_mut().values_mut() { + fd_event_source.with_idata(evlh, |&mut (ref mut device, _), evlh| { + info!(self.logger, "changed successful"); + device.observer().pause(evlh, devnum); + }) } - }); + } } - fn activate<'a>(&mut self, state: &mut StateProxy<'a>, devnum: Option<(u32, u32, Option)>) { - state.with_value(self, |state, udev| { - for &mut (ref mut device, _) in udev.devices.values_mut() { - device.activate(state, devnum); + fn activate<'a>(&mut self, evlh: &mut EventLoopHandle, devnum: Option<(u32, u32, Option)>) { + if let Some(devices) = self.devices.upgrade() { + for fd_event_source in devices.borrow_mut().values_mut() { + fd_event_source.with_idata(evlh, |&mut (ref mut device, _), evlh| { + info!(self.logger, "changed successful"); + device.observer().activate(evlh, devnum); + }) } - }); + } } } @@ -202,41 +211,37 @@ impl< /// 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( - evlh: &mut EventLoopHandle, udev: StateToken> -) -> IoResult>>> + evlh: &mut EventLoopHandle, udev: UdevBackend +) -> ::std::result::Result>, (IoError, UdevBackend)> where H: DrmHandler + 'static, T: UdevHandler + 'static, S: Session + 'static, { - let fd = evlh.state().get(&udev).monitor.as_raw_fd(); + let fd = udev.monitor.as_raw_fd(); evlh.add_fd_event_source(fd, fd_event_source_implementation(), udev, FdInterest::READ) } -fn fd_event_source_implementation() -> FdEventSourceImpl>> +fn fd_event_source_implementation() -> FdEventSourceImpl> where H: DrmHandler + 'static, T: UdevHandler + 'static, S: Session + 'static, { FdEventSourceImpl { - ready: |mut evlh, token, _, _| { - let events = evlh.state() - .get(token) - .monitor - .clone() - .collect::>(); + ready: |mut evlh, udev, _, _| { + let events = udev.monitor.clone().collect::>(); for event in events { match event.event_type() { // New device EventType::Add => { - info!(evlh.state().get(token).logger, "Device Added"); + info!(udev.logger, "Device Added"); if let (Some(path), Some(devnum)) = (event.devnode(), event.devnum()) { let mut device = { match DrmDevice::new( { - let logger = evlh.state().get(token).logger.clone(); - match evlh.state().get_mut(token).session.open( + let logger = udev.logger.clone(); + match udev.session.open( path, fcntl::O_RDWR | fcntl::O_CLOEXEC | fcntl::O_NOCTTY | fcntl::O_NONBLOCK, @@ -253,12 +258,12 @@ where } } }, - evlh.state().get(token).logger.clone(), + udev.logger.clone(), ) { Ok(dev) => dev, Err(err) => { warn!( - evlh.state().get(token).logger, + udev.logger, "Failed to initialize device {:?}. Error: {}. Skipping", path, err @@ -268,57 +273,43 @@ where } }; let fd = device.as_raw_fd(); - match evlh.state().with_value(token, |state, udev| { - udev.handler.device_added(state, &mut device) - }) { - Some(drm_handler) => { - let dev_token = evlh.state().insert(device); - if let Ok(fd_event_source) = - drm_device_bind(&mut evlh, dev_token.clone(), drm_handler) - { - evlh.state() - .get_mut(token) - .devices - .insert(devnum, (dev_token, fd_event_source)); - } else { - evlh.state().with_value(token, |state, udev| { - let mut state: StateProxy = state.into(); - udev.handler.device_removed(&mut state, &dev_token); - let device = state.remove(dev_token); - drop(device); - if let Err(err) = udev.session.close(fd) { - warn!( - udev.logger, - "Failed to close dropped device. Error: {:?}. Ignoring", - err - ); - }; - }) + match udev.handler.device_added(evlh, &mut device) { + Some(drm_handler) => match drm_device_bind(&mut evlh, device, drm_handler) { + Ok(fd_event_source) => { + udev.devices.borrow_mut().insert(devnum, fd_event_source); } - } - None => { - drop(device); - evlh.state().with_value(token, |_state, udev| { + Err((err, (mut device, _))) => { + warn!(udev.logger, "Failed to bind device. Error: {:?}.", err); + udev.handler.device_removed(evlh, &mut device); + drop(device); if let Err(err) = udev.session.close(fd) { warn!( udev.logger, - "Failed to close unused device. Error: {:?}", err + "Failed to close dropped device. Error: {:?}. Ignoring", err ); - } - }) + }; + } + }, + None => { + udev.handler.device_removed(evlh, &mut device); + drop(device); + if let Err(err) = udev.session.close(fd) { + warn!( + udev.logger, + "Failed to close unused device. Error: {:?}", err + ); + } } }; } } // Device removed - EventType::Remove => evlh.state().with_value(token, |state, udev| { + EventType::Remove => { info!(udev.logger, "Device Remove"); if let Some(devnum) = event.devnum() { - if let Some((device, fd_event_source)) = udev.devices.remove(&devnum) { - fd_event_source.remove(); - let mut state: StateProxy = state.into(); - udev.handler.device_removed(&mut state, &device); - let device = state.remove(device); + if let Some(fd_event_source) = udev.devices.borrow_mut().remove(&devnum) { + let (mut device, _) = fd_event_source.remove(); + udev.handler.device_removed(evlh, &mut device); let fd = device.as_raw_fd(); drop(device); if let Err(err) = udev.session.close(fd) { @@ -331,30 +322,31 @@ where }; } } - }), + } // New connector - EventType::Change => evlh.state().with_value(token, |state, udev| { + EventType::Change => { info!(udev.logger, "Device Changed"); if let Some(devnum) = event.devnum() { info!(udev.logger, "Devnum: {:b}", devnum); - if let Some(&(ref device, _)) = udev.devices.get(&devnum) { - info!(udev.logger, "changed successful"); - udev.handler.device_changed(state, device); + if let Some(fd_event_source) = udev.devices.borrow_mut().get_mut(&devnum) { + let handler = &mut udev.handler; + let logger = &udev.logger; + fd_event_source.with_idata(evlh, move |&mut (ref mut device, _), evlh| { + info!(logger, "changed successful"); + handler.device_changed(evlh, device); + }) } else { info!(udev.logger, "changed, but device not tracked by backend"); - } + }; } else { info!(udev.logger, "changed, but no devnum"); } - }), + } _ => {} } } }, - error: |evlh, token, _, err| { - evlh.state() - .with_value(token, |state, udev| udev.handler.error(state, err)) - }, + error: |evlh, udev, _, err| udev.handler.error(evlh, err), } } @@ -366,8 +358,8 @@ pub trait UdevHandler + 'static> { /// /// ## Panics /// Panics if you try to borrow the token of the belonging `UdevBackend` using this `StateProxy`. - fn device_added<'a, S: Into>>( - &mut self, state: S, device: &mut DrmDevice + fn device_added( + &mut self, evlh: &mut EventLoopHandle, device: &mut DrmDevice ) -> Option; /// Called when an open device is changed. /// @@ -376,9 +368,7 @@ pub trait UdevHandler + 'static> { /// /// ## Panics /// Panics if you try to borrow the token of the belonging `UdevBackend` using this `StateProxy`. - fn device_changed<'a, S: Into>>( - &mut self, state: S, device: &StateToken> - ); + fn device_changed(&mut self, evlh: &mut EventLoopHandle, device: &mut DrmDevice); /// Called when a device was removed. /// /// The device will not accept any operations anymore and its file descriptor will be closed once @@ -386,14 +376,12 @@ pub trait UdevHandler + 'static> { /// /// ## Panics /// Panics if you try to borrow the token of the belonging `UdevBackend` using this `StateProxy`. - fn device_removed<'a, S: Into>>( - &mut self, state: S, device: &StateToken> - ); + fn device_removed(&mut self, evlh: &mut EventLoopHandle, device: &mut DrmDevice); /// Called when the udev context has encountered and error. /// /// ## Panics /// Panics if you try to borrow the token of the belonging `UdevBackend` using this `StateProxy`. - fn error<'a, S: Into>>(&mut self, state: S, error: IoError); + fn error(&mut self, evlh: &mut EventLoopHandle, error: IoError); } /// Returns the path of the primary gpu device if any