From 0ed69bf2dad234496fb6b0e404a30555b9809d93 Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Fri, 23 Nov 2018 15:10:51 +0100 Subject: [PATCH] session: Add multiplexer --- anvil/src/udev.rs | 105 ++++++++++++++++++++--------- src/backend/drm/legacy/session.rs | 6 +- src/backend/session/auto.rs | 22 +----- src/backend/session/dbus/logind.rs | 18 +---- src/backend/session/direct.rs | 18 ++--- src/backend/session/mod.rs | 10 +-- src/backend/session/multi.rs | 64 ++++++++++++++++++ 7 files changed, 152 insertions(+), 91 deletions(-) create mode 100644 src/backend/session/multi.rs diff --git a/anvil/src/udev.rs b/anvil/src/udev.rs index ccbfbef..e85b9c6 100644 --- a/anvil/src/udev.rs +++ b/anvil/src/udev.rs @@ -17,7 +17,7 @@ use slog::Logger; use smithay::{ backend::{ drm::{ - dev_t, + dev_t, device_bind, egl::{EglDevice, EglSurface}, gbm::{egl::Gbm as EglGbmBackend, GbmDevice}, legacy::LegacyDrmDevice, @@ -29,7 +29,7 @@ use smithay::{ libinput::{libinput_bind, LibinputInputBackend, LibinputSessionInterface}, session::{ auto::{auto_session_bind, AutoSession}, - OFlag, Session, SessionNotifier, + notify_multiplexer, AsSessionObserver, OFlag, Session, SessionNotifier, }, udev::{primary_gpu, udev_backend_bind, UdevBackend, UdevHandler}, }, @@ -48,7 +48,14 @@ use smithay::{ seat::{Seat, XkbConfig}, shm::init_shm_global, }, - wayland_server::{calloop::EventLoop, protocol::wl_output, Display}, + wayland_server::{ + calloop::{ + generic::{EventedFd, Generic}, + EventLoop, LoopHandle, Source, + }, + protocol::wl_output, + Display, + }, }; use glium_drawer::GliumDrawer; @@ -87,6 +94,8 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop<()>, log: Logger * Initialize session */ let (session, mut notifier) = AutoSession::new(log.clone()).ok_or(())?; + let (udev_observer, udev_notifier) = notify_multiplexer(); + let udev_session_id = notifier.register(udev_observer); let running = Arc::new(AtomicBool::new(true)); @@ -113,6 +122,8 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop<()>, log: Logger window_map: window_map.clone(), pointer_location: pointer_location.clone(), pointer_image: ImageBuffer::from_raw(64, 64, bytes.to_vec()).unwrap(), + loop_handle: event_loop.handle(), + notifier: udev_notifier, logger: log.clone(), }, seat.clone(), @@ -168,7 +179,7 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop<()>, log: Logger */ let mut libinput_context = Libinput::new_from_udev::>(session.clone().into(), &context); - let libinput_session_id = notifier.register(&mut libinput_context); + let libinput_session_id = notifier.register(libinput_context.observer()); libinput_context.udev_assign_seat(&seat).unwrap(); let mut libinput_backend = LibinputInputBackend::new(libinput_context, log.clone()); libinput_backend.set_handler(AnvilInputHandler::new_with_session( @@ -205,6 +216,7 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop<()>, log: Logger let mut notifier = session_event_source.unbind(); notifier.unregister(libinput_session_id); + notifier.unregister(udev_session_id); libinput_event_source.remove(); udev_event_source.remove(); @@ -212,14 +224,15 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop<()>, log: Logger Ok(()) } -struct UdevHandlerImpl { +struct UdevHandlerImpl { compositor_token: CompositorToken, active_egl_context: Rc>>, session: AutoSession, backends: HashMap< dev_t, ( - RenderDevice, + S::Id, + Source>>, Rc>>>, ), >, @@ -228,14 +241,15 @@ struct UdevHandlerImpl { window_map: Rc>, pointer_location: Rc>, pointer_image: ImageBuffer, Vec>, + loop_handle: LoopHandle, + notifier: S, logger: ::slog::Logger, } -impl UdevHandlerImpl { +impl UdevHandlerImpl { pub fn scan_connectors( device: &mut RenderDevice, egl_display: Rc>>, - pointer_image: &ImageBuffer, Vec>, logger: &::slog::Logger, ) -> HashMap> { // Get a set of all modesetting resource handles (excluding planes): @@ -272,19 +286,6 @@ impl UdevHandlerImpl { logger.clone(), ); - // create cursor - renderer - .borrow() - .set_cursor_representation(pointer_image, (2, 2)) - .unwrap(); - - // render first frame - { - let mut frame = renderer.draw(); - frame.clear_color(0.8, 0.8, 0.9, 1.0); - frame.finish().unwrap(); - } - backends.insert(crtc, renderer); break; } @@ -296,7 +297,7 @@ impl UdevHandlerImpl { } } -impl UdevHandler for UdevHandlerImpl { +impl UdevHandler for UdevHandlerImpl { fn device_added(&mut self, _device: dev_t, path: PathBuf) { if let Some(mut device) = self .session @@ -313,10 +314,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(UdevHandlerImpl::scan_connectors( + let backends = Rc::new(RefCell::new(UdevHandlerImpl::::scan_connectors( &mut device, self.active_egl_context.clone(), - &self.pointer_image, &self.logger, ))); @@ -328,29 +328,72 @@ impl UdevHandler for UdevHandlerImpl { logger: self.logger.clone(), }); - self.backends.insert(device.device_id(), (device, backends)); + let device_session_id = self.notifier.register(device.observer()); + let dev_id = device.device_id(); + let event_source = device_bind(&self.loop_handle, device) + .map_err(|e| -> IoError { e.into() }) + .unwrap(); + + for renderer in backends.borrow_mut().values() { + // create cursor + renderer + .borrow() + .set_cursor_representation(&self.pointer_image, (2, 2)) + .unwrap(); + + // render first frame + { + let mut frame = renderer.draw(); + frame.clear_color(0.8, 0.8, 0.9, 1.0); + frame.finish().unwrap(); + } + } + + self.backends + .insert(dev_id, (device_session_id, event_source, backends)); } } fn device_changed(&mut self, device: dev_t) { //quick and dirty, just re-init all backends - if let Some((ref mut device, ref backends)) = self.backends.get_mut(&device) { - *backends.borrow_mut() = UdevHandlerImpl::scan_connectors( - device, + if let Some((_, ref mut evt_source, ref backends)) = self.backends.get_mut(&device) { + let source = evt_source.clone_inner(); + let mut evented = source.borrow_mut(); + let mut backends = backends.borrow_mut(); + *backends = UdevHandlerImpl::::scan_connectors( + &mut (*evented).0, self.active_egl_context.clone(), - &self.pointer_image, &self.logger, ); + + for renderer in backends.values() { + // create cursor + renderer + .borrow() + .set_cursor_representation(&self.pointer_image, (2, 2)) + .unwrap(); + + // render first frame + { + let mut frame = renderer.draw(); + frame.clear_color(0.8, 0.8, 0.9, 1.0); + frame.finish().unwrap(); + } + } } } fn device_removed(&mut self, device: dev_t) { // drop the backends on this side - if let Some((dev, _)) = self.backends.remove(&device) { + if let Some((id, evt_source, _)) = self.backends.remove(&device) { // don't use hardware acceleration anymore, if this was the primary gpu - if dev.dev_path().and_then(|path| path.canonicalize().ok()) == self.primary_gpu { + let source = evt_source.clone_inner(); + let evented = source.borrow(); + if (*evented).0.dev_path().and_then(|path| path.canonicalize().ok()) == self.primary_gpu { *self.active_egl_context.borrow_mut() = None; } + + self.notifier.unregister(id); } } } diff --git a/src/backend/drm/legacy/session.rs b/src/backend/drm/legacy/session.rs index 5d00f0a..b188985 100644 --- a/src/backend/drm/legacy/session.rs +++ b/src/backend/drm/legacy/session.rs @@ -1,4 +1,4 @@ -use drm::control::{connector, crtc, Device as ControlDevice}; +use drm::control::{connector, crtc}; use drm::Device as BasicDevice; use nix::libc::dev_t; use nix::sys::stat; @@ -23,7 +23,7 @@ pub struct LegacyDrmDeviceObserver { logger: ::slog::Logger, } -impl AsSessionObserver> for LegacyDrmDevice { +impl AsSessionObserver> for LegacyDrmDevice { fn observer(&mut self) -> LegacyDrmDeviceObserver { LegacyDrmDeviceObserver { dev: Rc::downgrade(&self.dev), @@ -37,7 +37,7 @@ impl AsSessionObserver> f } } -impl SessionObserver for LegacyDrmDeviceObserver { +impl SessionObserver for LegacyDrmDeviceObserver { fn pause(&mut self, devnum: Option<(u32, u32)>) { if let Some((major, minor)) = devnum { if major as u64 != stat::major(self.dev_id) || minor as u64 != stat::minor(self.dev_id) { diff --git a/src/backend/session/auto.rs b/src/backend/session/auto.rs index d5612c8..e1dd62f 100644 --- a/src/backend/session/auto.rs +++ b/src/backend/session/auto.rs @@ -31,7 +31,7 @@ use super::logind::{self, logind_session_bind, BoundLogindSession, LogindSession, LogindSessionNotifier}; use super::{ direct::{self, direct_session_bind, BoundDirectSession, DirectSession, DirectSessionNotifier}, - AsErrno, AsSessionObserver, Session, SessionNotifier, SessionObserver, + AsErrno, Session, SessionNotifier, SessionObserver, }; use nix::fcntl::OFlag; use std::{cell::RefCell, io::Error as IoError, os::unix::io::RawFd, path::Path, rc::Rc}; @@ -202,10 +202,7 @@ impl Session for AutoSession { impl SessionNotifier for AutoSessionNotifier { type Id = AutoId; - fn register>( - &mut self, - signal: &mut A, - ) -> Self::Id { + fn register(&mut self, signal: S) -> Self::Id { match *self { #[cfg(feature = "backend_session_logind")] AutoSessionNotifier::Logind(ref mut logind) => { @@ -231,21 +228,6 @@ impl SessionNotifier for AutoSessionNotifier { _ => unreachable!(), } } - - fn is_active(&self) -> bool { - match *self { - #[cfg(feature = "backend_session_logind")] - AutoSessionNotifier::Logind(ref logind) => logind.is_active(), - AutoSessionNotifier::Direct(ref direct) => direct.is_active(), - } - } - fn seat(&self) -> &str { - match *self { - #[cfg(feature = "backend_session_logind")] - AutoSessionNotifier::Logind(ref logind) => logind.seat(), - AutoSessionNotifier::Direct(ref direct) => direct.seat(), - } - } } impl BoundAutoSession { diff --git a/src/backend/session/dbus/logind.rs b/src/backend/session/dbus/logind.rs index 147abd0..e144422 100644 --- a/src/backend/session/dbus/logind.rs +++ b/src/backend/session/dbus/logind.rs @@ -404,27 +404,13 @@ pub struct Id(usize); impl SessionNotifier for LogindSessionNotifier { type Id = Id; - fn register>( - &mut self, - signal: &mut A, - ) -> Self::Id { - self.internal - .signals - .borrow_mut() - .push(Some(Box::new(signal.observer()))); + fn register(&mut self, signal: S) -> Self::Id { + self.internal.signals.borrow_mut().push(Some(Box::new(signal))); Id(self.internal.signals.borrow().len() - 1) } fn unregister(&mut self, signal: Id) { self.internal.signals.borrow_mut()[signal.0] = None; } - - fn is_active(&self) -> bool { - self.internal.active.load(Ordering::SeqCst) - } - - fn seat(&self) -> &str { - &self.internal.seat - } } /// Bound logind session that is driven by the `wayland_server::EventLoop`. diff --git a/src/backend/session/direct.rs b/src/backend/session/direct.rs index d7bc3a9..d879731 100644 --- a/src/backend/session/direct.rs +++ b/src/backend/session/direct.rs @@ -45,7 +45,7 @@ //! for notifications are the `Libinput` context, the `UdevBackend` or a `DrmDevice` (handled //! automatically by the `UdevBackend`, if not done manually). -use super::{AsErrno, AsSessionObserver, Session, SessionNotifier, SessionObserver}; +use super::{AsErrno, Session, SessionNotifier, SessionObserver}; use nix::{ fcntl::{self, open, OFlag}, libc::c_int, @@ -350,28 +350,18 @@ pub struct Id(usize); impl SessionNotifier for DirectSessionNotifier { type Id = Id; - fn register>( - &mut self, - signal: &mut A, - ) -> Self::Id { - self.signals.push(Some(Box::new(signal.observer()))); + fn register(&mut self, signal: S) -> Self::Id { + self.signals.push(Some(Box::new(signal))); Id(self.signals.len() - 1) } fn unregister(&mut self, signal: Id) { self.signals[signal.0] = None; } - - fn is_active(&self) -> bool { - self.active.load(Ordering::SeqCst) - } - fn seat(&self) -> &str { - "seat0" - } } impl DirectSessionNotifier { fn signal_received(&mut self) { - if self.is_active() { + if self.active.load(Ordering::SeqCst) { info!(self.logger, "Session shall become inactive."); for signal in &mut self.signals { if let Some(ref mut signal) = *signal { diff --git a/src/backend/session/mod.rs b/src/backend/session/mod.rs index 2eeeee8..8967233 100644 --- a/src/backend/session/mod.rs +++ b/src/backend/session/mod.rs @@ -54,15 +54,9 @@ 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: &mut A) - -> Self::Id; + fn register(&mut self, signal: S) -> Self::Id; /// Removes an observer by its given id from `SessionNotifier::register`. fn unregister(&mut self, signal: Self::Id); - - /// Check if this session is currently active - fn is_active(&self) -> bool; - /// Which seat this session is on - fn seat(&self) -> &str; } /// Trait describing the ability to return a `SessionObserver` related to Self. @@ -186,3 +180,5 @@ pub mod auto; mod dbus; pub mod direct; pub use self::dbus::*; +mod multi; +pub use self::multi::*; diff --git a/src/backend/session/multi.rs b/src/backend/session/multi.rs new file mode 100644 index 0000000..8fa57b3 --- /dev/null +++ b/src/backend/session/multi.rs @@ -0,0 +1,64 @@ +use std::{ + collections::HashMap, + os::unix::io::RawFd, + sync::{ + atomic::{AtomicUsize, Ordering}, + Arc, Mutex, + }, +}; + +use super::{SessionNotifier, SessionObserver}; + +static ID_COUNTER: AtomicUsize = AtomicUsize::new(0); + +/// Ids of registered `SessionObserver`s of the `DirectSessionNotifier` +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] +pub struct Id(usize); + +struct MultiObserver { + observer: Arc>>>, +} + +impl SessionObserver for MultiObserver { + fn pause(&mut self, device: Option<(u32, u32)>) { + let mut lock = self.observer.lock().unwrap(); + for mut observer in lock.values_mut() { + observer.pause(device) + } + } + fn activate(&mut self, device: Option<(u32, u32, Option)>) { + let mut lock = self.observer.lock().unwrap(); + for mut observer in lock.values_mut() { + observer.activate(device) + } + } +} + +struct MultiNotifier { + observer: Arc>>>, +} + +impl SessionNotifier for MultiNotifier { + type Id = Id; + + fn register(&mut self, signal: S) -> Self::Id { + let id = Id(ID_COUNTER.fetch_add(1, Ordering::SeqCst)); + self.observer.lock().unwrap().insert(id, Box::new(signal)); + id + } + + fn unregister(&mut self, signal: Self::Id) { + self.observer.lock().unwrap().remove(&signal); + } +} + +pub fn notify_multiplexer() -> (impl SessionObserver, impl SessionNotifier) { + let observer = Arc::new(Mutex::new(HashMap::new())); + + ( + MultiObserver { + observer: observer.clone(), + }, + MultiNotifier { observer }, + ) +}