session: Add multiplexer

This commit is contained in:
Victor Brekenfeld 2018-11-23 15:10:51 +01:00
parent 5741ccdd46
commit 0ed69bf2da
7 changed files with 152 additions and 91 deletions

View File

@ -17,7 +17,7 @@ use slog::Logger;
use smithay::{ use smithay::{
backend::{ backend::{
drm::{ drm::{
dev_t, dev_t, device_bind,
egl::{EglDevice, EglSurface}, egl::{EglDevice, EglSurface},
gbm::{egl::Gbm as EglGbmBackend, GbmDevice}, gbm::{egl::Gbm as EglGbmBackend, GbmDevice},
legacy::LegacyDrmDevice, legacy::LegacyDrmDevice,
@ -29,7 +29,7 @@ use smithay::{
libinput::{libinput_bind, LibinputInputBackend, LibinputSessionInterface}, libinput::{libinput_bind, LibinputInputBackend, LibinputSessionInterface},
session::{ session::{
auto::{auto_session_bind, AutoSession}, auto::{auto_session_bind, AutoSession},
OFlag, Session, SessionNotifier, notify_multiplexer, AsSessionObserver, OFlag, Session, SessionNotifier,
}, },
udev::{primary_gpu, udev_backend_bind, UdevBackend, UdevHandler}, udev::{primary_gpu, udev_backend_bind, UdevBackend, UdevHandler},
}, },
@ -48,7 +48,14 @@ use smithay::{
seat::{Seat, XkbConfig}, seat::{Seat, XkbConfig},
shm::init_shm_global, 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; use glium_drawer::GliumDrawer;
@ -87,6 +94,8 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop<()>, log: Logger
* Initialize session * Initialize session
*/ */
let (session, mut notifier) = AutoSession::new(log.clone()).ok_or(())?; 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)); 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(), window_map: window_map.clone(),
pointer_location: pointer_location.clone(), pointer_location: pointer_location.clone(),
pointer_image: ImageBuffer::from_raw(64, 64, bytes.to_vec()).unwrap(), pointer_image: ImageBuffer::from_raw(64, 64, bytes.to_vec()).unwrap(),
loop_handle: event_loop.handle(),
notifier: udev_notifier,
logger: log.clone(), logger: log.clone(),
}, },
seat.clone(), seat.clone(),
@ -168,7 +179,7 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop<()>, log: Logger
*/ */
let mut libinput_context = let mut libinput_context =
Libinput::new_from_udev::<LibinputSessionInterface<AutoSession>>(session.clone().into(), &context); Libinput::new_from_udev::<LibinputSessionInterface<AutoSession>>(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(); libinput_context.udev_assign_seat(&seat).unwrap();
let mut libinput_backend = LibinputInputBackend::new(libinput_context, log.clone()); let mut libinput_backend = LibinputInputBackend::new(libinput_context, log.clone());
libinput_backend.set_handler(AnvilInputHandler::new_with_session( 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(); let mut notifier = session_event_source.unbind();
notifier.unregister(libinput_session_id); notifier.unregister(libinput_session_id);
notifier.unregister(udev_session_id);
libinput_event_source.remove(); libinput_event_source.remove();
udev_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(()) Ok(())
} }
struct UdevHandlerImpl { struct UdevHandlerImpl<S: SessionNotifier, Data: 'static> {
compositor_token: CompositorToken<SurfaceData, Roles>, compositor_token: CompositorToken<SurfaceData, Roles>,
active_egl_context: Rc<RefCell<Option<EGLDisplay>>>, active_egl_context: Rc<RefCell<Option<EGLDisplay>>>,
session: AutoSession, session: AutoSession,
backends: HashMap< backends: HashMap<
dev_t, dev_t,
( (
RenderDevice, S::Id,
Source<Generic<EventedFd<RenderDevice>>>,
Rc<RefCell<HashMap<crtc::Handle, GliumDrawer<RenderSurface>>>>, Rc<RefCell<HashMap<crtc::Handle, GliumDrawer<RenderSurface>>>>,
), ),
>, >,
@ -228,14 +241,15 @@ struct UdevHandlerImpl {
window_map: Rc<RefCell<MyWindowMap>>, window_map: Rc<RefCell<MyWindowMap>>,
pointer_location: Rc<RefCell<(f64, f64)>>, pointer_location: Rc<RefCell<(f64, f64)>>,
pointer_image: ImageBuffer<Rgba<u8>, Vec<u8>>, pointer_image: ImageBuffer<Rgba<u8>, Vec<u8>>,
loop_handle: LoopHandle<Data>,
notifier: S,
logger: ::slog::Logger, logger: ::slog::Logger,
} }
impl UdevHandlerImpl { impl<S: SessionNotifier, Data: 'static> UdevHandlerImpl<S, Data> {
pub fn scan_connectors( pub fn scan_connectors(
device: &mut RenderDevice, device: &mut RenderDevice,
egl_display: Rc<RefCell<Option<EGLDisplay>>>, egl_display: Rc<RefCell<Option<EGLDisplay>>>,
pointer_image: &ImageBuffer<Rgba<u8>, Vec<u8>>,
logger: &::slog::Logger, logger: &::slog::Logger,
) -> HashMap<crtc::Handle, GliumDrawer<RenderSurface>> { ) -> HashMap<crtc::Handle, GliumDrawer<RenderSurface>> {
// Get a set of all modesetting resource handles (excluding planes): // Get a set of all modesetting resource handles (excluding planes):
@ -272,19 +286,6 @@ impl UdevHandlerImpl {
logger.clone(), 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); backends.insert(crtc, renderer);
break; break;
} }
@ -296,7 +297,7 @@ impl UdevHandlerImpl {
} }
} }
impl UdevHandler for UdevHandlerImpl { impl<S: SessionNotifier, Data: 'static> UdevHandler for UdevHandlerImpl<S, Data> {
fn device_added(&mut self, _device: dev_t, path: PathBuf) { fn device_added(&mut self, _device: dev_t, path: PathBuf) {
if let Some(mut device) = self if let Some(mut device) = self
.session .session
@ -313,10 +314,9 @@ impl UdevHandler for UdevHandlerImpl {
*self.active_egl_context.borrow_mut() = device.bind_wl_display(&*self.display.borrow()).ok(); *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::<S, Data>::scan_connectors(
&mut device, &mut device,
self.active_egl_context.clone(), self.active_egl_context.clone(),
&self.pointer_image,
&self.logger, &self.logger,
))); )));
@ -328,29 +328,72 @@ impl UdevHandler for UdevHandlerImpl {
logger: self.logger.clone(), 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) { fn device_changed(&mut self, device: dev_t) {
//quick and dirty, just re-init all backends //quick and dirty, just re-init all backends
if let Some((ref mut device, ref backends)) = self.backends.get_mut(&device) { if let Some((_, ref mut evt_source, ref backends)) = self.backends.get_mut(&device) {
*backends.borrow_mut() = UdevHandlerImpl::scan_connectors( let source = evt_source.clone_inner();
device, let mut evented = source.borrow_mut();
let mut backends = backends.borrow_mut();
*backends = UdevHandlerImpl::<S, Data>::scan_connectors(
&mut (*evented).0,
self.active_egl_context.clone(), self.active_egl_context.clone(),
&self.pointer_image,
&self.logger, &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) { fn device_removed(&mut self, device: dev_t) {
// drop the backends on this side // 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 // 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.active_egl_context.borrow_mut() = None;
} }
self.notifier.unregister(id);
} }
} }
} }

View File

@ -1,4 +1,4 @@
use drm::control::{connector, crtc, Device as ControlDevice}; use drm::control::{connector, crtc};
use drm::Device as BasicDevice; use drm::Device as BasicDevice;
use nix::libc::dev_t; use nix::libc::dev_t;
use nix::sys::stat; use nix::sys::stat;
@ -23,7 +23,7 @@ pub struct LegacyDrmDeviceObserver<A: AsRawFd + 'static> {
logger: ::slog::Logger, logger: ::slog::Logger,
} }
impl<A: ControlDevice + 'static> AsSessionObserver<LegacyDrmDeviceObserver<A>> for LegacyDrmDevice<A> { impl<A: AsRawFd + 'static> AsSessionObserver<LegacyDrmDeviceObserver<A>> for LegacyDrmDevice<A> {
fn observer(&mut self) -> LegacyDrmDeviceObserver<A> { fn observer(&mut self) -> LegacyDrmDeviceObserver<A> {
LegacyDrmDeviceObserver { LegacyDrmDeviceObserver {
dev: Rc::downgrade(&self.dev), dev: Rc::downgrade(&self.dev),
@ -37,7 +37,7 @@ impl<A: ControlDevice + 'static> AsSessionObserver<LegacyDrmDeviceObserver<A>> f
} }
} }
impl<A: ControlDevice + 'static> SessionObserver for LegacyDrmDeviceObserver<A> { impl<A: AsRawFd + 'static> SessionObserver for LegacyDrmDeviceObserver<A> {
fn pause(&mut self, devnum: Option<(u32, u32)>) { fn pause(&mut self, devnum: Option<(u32, u32)>) {
if let Some((major, minor)) = devnum { if let Some((major, minor)) = devnum {
if major as u64 != stat::major(self.dev_id) || minor as u64 != stat::minor(self.dev_id) { if major as u64 != stat::major(self.dev_id) || minor as u64 != stat::minor(self.dev_id) {

View File

@ -31,7 +31,7 @@
use super::logind::{self, logind_session_bind, BoundLogindSession, LogindSession, LogindSessionNotifier}; use super::logind::{self, logind_session_bind, BoundLogindSession, LogindSession, LogindSessionNotifier};
use super::{ use super::{
direct::{self, direct_session_bind, BoundDirectSession, DirectSession, DirectSessionNotifier}, direct::{self, direct_session_bind, BoundDirectSession, DirectSession, DirectSessionNotifier},
AsErrno, AsSessionObserver, Session, SessionNotifier, SessionObserver, AsErrno, Session, SessionNotifier, SessionObserver,
}; };
use nix::fcntl::OFlag; use nix::fcntl::OFlag;
use std::{cell::RefCell, io::Error as IoError, os::unix::io::RawFd, path::Path, rc::Rc}; 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 { impl SessionNotifier for AutoSessionNotifier {
type Id = AutoId; type Id = AutoId;
fn register<S: SessionObserver + 'static, A: AsSessionObserver<S>>( fn register<S: SessionObserver + 'static>(&mut self, signal: S) -> Self::Id {
&mut self,
signal: &mut A,
) -> Self::Id {
match *self { match *self {
#[cfg(feature = "backend_session_logind")] #[cfg(feature = "backend_session_logind")]
AutoSessionNotifier::Logind(ref mut logind) => { AutoSessionNotifier::Logind(ref mut logind) => {
@ -231,21 +228,6 @@ impl SessionNotifier for AutoSessionNotifier {
_ => unreachable!(), _ => 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 { impl BoundAutoSession {

View File

@ -404,27 +404,13 @@ pub struct Id(usize);
impl SessionNotifier for LogindSessionNotifier { impl SessionNotifier for LogindSessionNotifier {
type Id = Id; type Id = Id;
fn register<S: SessionObserver + 'static, A: AsSessionObserver<S>>( fn register<S: SessionObserver + 'static>(&mut self, signal: S) -> Self::Id {
&mut self, self.internal.signals.borrow_mut().push(Some(Box::new(signal)));
signal: &mut A,
) -> Self::Id {
self.internal
.signals
.borrow_mut()
.push(Some(Box::new(signal.observer())));
Id(self.internal.signals.borrow().len() - 1) Id(self.internal.signals.borrow().len() - 1)
} }
fn unregister(&mut self, signal: Id) { fn unregister(&mut self, signal: Id) {
self.internal.signals.borrow_mut()[signal.0] = None; 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`. /// Bound logind session that is driven by the `wayland_server::EventLoop`.

View File

@ -45,7 +45,7 @@
//! for notifications are the `Libinput` context, the `UdevBackend` or a `DrmDevice` (handled //! for notifications are the `Libinput` context, the `UdevBackend` or a `DrmDevice` (handled
//! automatically by the `UdevBackend`, if not done manually). //! automatically by the `UdevBackend`, if not done manually).
use super::{AsErrno, AsSessionObserver, Session, SessionNotifier, SessionObserver}; use super::{AsErrno, Session, SessionNotifier, SessionObserver};
use nix::{ use nix::{
fcntl::{self, open, OFlag}, fcntl::{self, open, OFlag},
libc::c_int, libc::c_int,
@ -350,28 +350,18 @@ pub struct Id(usize);
impl SessionNotifier for DirectSessionNotifier { impl SessionNotifier for DirectSessionNotifier {
type Id = Id; type Id = Id;
fn register<S: SessionObserver + 'static, A: AsSessionObserver<S>>( fn register<S: SessionObserver + 'static>(&mut self, signal: S) -> Self::Id {
&mut self, self.signals.push(Some(Box::new(signal)));
signal: &mut A,
) -> Self::Id {
self.signals.push(Some(Box::new(signal.observer())));
Id(self.signals.len() - 1) Id(self.signals.len() - 1)
} }
fn unregister(&mut self, signal: Id) { fn unregister(&mut self, signal: Id) {
self.signals[signal.0] = None; self.signals[signal.0] = None;
} }
fn is_active(&self) -> bool {
self.active.load(Ordering::SeqCst)
}
fn seat(&self) -> &str {
"seat0"
}
} }
impl DirectSessionNotifier { impl DirectSessionNotifier {
fn signal_received(&mut self) { fn signal_received(&mut self) {
if self.is_active() { if self.active.load(Ordering::SeqCst) {
info!(self.logger, "Session shall become inactive."); info!(self.logger, "Session shall become inactive.");
for signal in &mut self.signals { for signal in &mut self.signals {
if let Some(ref mut signal) = *signal { if let Some(ref mut signal) = *signal {

View File

@ -54,15 +54,9 @@ pub trait SessionNotifier {
/// Registers a given `SessionObserver`. /// Registers a given `SessionObserver`.
/// ///
/// Returns an id of the inserted observer, can be used to remove it again. /// Returns an id of the inserted observer, can be used to remove it again.
fn register<S: SessionObserver + 'static, A: AsSessionObserver<S>>(&mut self, signal: &mut A) fn register<S: SessionObserver + 'static>(&mut self, signal: S) -> Self::Id;
-> Self::Id;
/// Removes an observer by its given id from `SessionNotifier::register`. /// Removes an observer by its given id from `SessionNotifier::register`.
fn unregister(&mut self, signal: Self::Id); 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. /// Trait describing the ability to return a `SessionObserver` related to Self.
@ -186,3 +180,5 @@ pub mod auto;
mod dbus; mod dbus;
pub mod direct; pub mod direct;
pub use self::dbus::*; pub use self::dbus::*;
mod multi;
pub use self::multi::*;

View File

@ -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<Mutex<HashMap<Id, Box<SessionObserver>>>>,
}
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<RawFd>)>) {
let mut lock = self.observer.lock().unwrap();
for mut observer in lock.values_mut() {
observer.activate(device)
}
}
}
struct MultiNotifier {
observer: Arc<Mutex<HashMap<Id, Box<SessionObserver>>>>,
}
impl SessionNotifier for MultiNotifier {
type Id = Id;
fn register<S: SessionObserver + 'static>(&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<Id = Id>) {
let observer = Arc::new(Mutex::new(HashMap::new()));
(
MultiObserver {
observer: observer.clone(),
},
MultiNotifier { observer },
)
}