backend.session: Migrate to using Signaler
Change the session backend to rely on Signaler to propagate its signals. Also introduce the Linkable trait to allow generic composition of objects needing to listen for signals.
This commit is contained in:
parent
c3859d999b
commit
a717fa36cd
|
@ -28,10 +28,7 @@ use smithay::{
|
||||||
},
|
},
|
||||||
graphics::{CursorBackend, SwapBuffersError},
|
graphics::{CursorBackend, SwapBuffersError},
|
||||||
libinput::{LibinputInputBackend, LibinputSessionInterface},
|
libinput::{LibinputInputBackend, LibinputSessionInterface},
|
||||||
session::{
|
session::{auto::AutoSession, Session, Signal as SessionSignal},
|
||||||
auto::AutoSession, notify_multiplexer, AsSessionObserver, Session, SessionNotifier,
|
|
||||||
SessionObserver,
|
|
||||||
},
|
|
||||||
udev::{primary_gpu, UdevBackend, UdevEvent},
|
udev::{primary_gpu, UdevBackend, UdevEvent},
|
||||||
},
|
},
|
||||||
reexports::{
|
reexports::{
|
||||||
|
@ -56,6 +53,7 @@ use smithay::{
|
||||||
Display,
|
Display,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
signaling::{Linkable, SignalToken, Signaler},
|
||||||
wayland::{
|
wayland::{
|
||||||
compositor::CompositorToken,
|
compositor::CompositorToken,
|
||||||
output::{Mode, Output, PhysicalProperties},
|
output::{Mode, Output, PhysicalProperties},
|
||||||
|
@ -117,9 +115,8 @@ pub fn run_udev(
|
||||||
/*
|
/*
|
||||||
* Initialize session
|
* Initialize session
|
||||||
*/
|
*/
|
||||||
let (session, mut notifier) = AutoSession::new(log.clone()).ok_or(())?;
|
let (session, notifier) = AutoSession::new(log.clone()).ok_or(())?;
|
||||||
let (udev_observer, udev_notifier) = notify_multiplexer();
|
let session_signal = notifier.signaler();
|
||||||
let udev_session_id = notifier.register(udev_observer);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize the compositor
|
* Initialize the compositor
|
||||||
|
@ -154,7 +151,7 @@ pub fn run_udev(
|
||||||
cursor_status: state.cursor_status.clone(),
|
cursor_status: state.cursor_status.clone(),
|
||||||
dnd_icon: state.dnd_icon.clone(),
|
dnd_icon: state.dnd_icon.clone(),
|
||||||
loop_handle: event_loop.handle(),
|
loop_handle: event_loop.handle(),
|
||||||
notifier: udev_notifier,
|
signaler: session_signal.clone(),
|
||||||
logger: log.clone(),
|
logger: log.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -196,9 +193,9 @@ pub fn run_udev(
|
||||||
let mut libinput_context = Libinput::new_with_udev::<LibinputSessionInterface<AutoSession>>(
|
let mut libinput_context = Libinput::new_with_udev::<LibinputSessionInterface<AutoSession>>(
|
||||||
state.session.clone().unwrap().into(),
|
state.session.clone().unwrap().into(),
|
||||||
);
|
);
|
||||||
let libinput_session_id = notifier.register(libinput_context.observer());
|
|
||||||
libinput_context.udev_assign_seat(&state.seat_name).unwrap();
|
libinput_context.udev_assign_seat(&state.seat_name).unwrap();
|
||||||
let libinput_backend = LibinputInputBackend::new(libinput_context, log.clone());
|
let mut libinput_backend = LibinputInputBackend::new(libinput_context, log.clone());
|
||||||
|
libinput_backend.link(session_signal);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Bind all our objects that get driven by the event loop
|
* Bind all our objects that get driven by the event loop
|
||||||
|
@ -246,29 +243,25 @@ pub fn run_udev(
|
||||||
// Cleanup stuff
|
// Cleanup stuff
|
||||||
state.window_map.borrow_mut().clear();
|
state.window_map.borrow_mut().clear();
|
||||||
|
|
||||||
let mut notifier = event_loop.handle().remove(session_event_source);
|
event_loop.handle().remove(session_event_source);
|
||||||
notifier.unregister(libinput_session_id);
|
|
||||||
notifier.unregister(udev_session_id);
|
|
||||||
|
|
||||||
event_loop.handle().remove(libinput_event_source);
|
event_loop.handle().remove(libinput_event_source);
|
||||||
event_loop.handle().remove(udev_event_source);
|
event_loop.handle().remove(udev_event_source);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
struct BackendData<S: SessionNotifier> {
|
struct BackendData {
|
||||||
id: S::Id,
|
_restart_token: SignalToken,
|
||||||
restart_id: S::Id,
|
|
||||||
event_source: Source<Generic<RenderDevice>>,
|
event_source: Source<Generic<RenderDevice>>,
|
||||||
surfaces: Rc<RefCell<HashMap<crtc::Handle, Rc<GliumDrawer<RenderSurface>>>>>,
|
surfaces: Rc<RefCell<HashMap<crtc::Handle, Rc<GliumDrawer<RenderSurface>>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct UdevHandlerImpl<S: SessionNotifier, Data: 'static> {
|
struct UdevHandlerImpl<Data: 'static> {
|
||||||
compositor_token: CompositorToken<Roles>,
|
compositor_token: CompositorToken<Roles>,
|
||||||
#[cfg(feature = "egl")]
|
#[cfg(feature = "egl")]
|
||||||
egl_buffer_reader: Rc<RefCell<Option<EGLBufferReader>>>,
|
egl_buffer_reader: Rc<RefCell<Option<EGLBufferReader>>>,
|
||||||
session: AutoSession,
|
session: AutoSession,
|
||||||
backends: HashMap<dev_t, BackendData<S>>,
|
backends: HashMap<dev_t, BackendData>,
|
||||||
display: Rc<RefCell<Display>>,
|
display: Rc<RefCell<Display>>,
|
||||||
primary_gpu: Option<PathBuf>,
|
primary_gpu: Option<PathBuf>,
|
||||||
window_map: Rc<RefCell<MyWindowMap>>,
|
window_map: Rc<RefCell<MyWindowMap>>,
|
||||||
|
@ -277,11 +270,11 @@ struct UdevHandlerImpl<S: SessionNotifier, Data: 'static> {
|
||||||
cursor_status: Arc<Mutex<CursorImageStatus>>,
|
cursor_status: Arc<Mutex<CursorImageStatus>>,
|
||||||
dnd_icon: Arc<Mutex<Option<wl_surface::WlSurface>>>,
|
dnd_icon: Arc<Mutex<Option<wl_surface::WlSurface>>>,
|
||||||
loop_handle: LoopHandle<Data>,
|
loop_handle: LoopHandle<Data>,
|
||||||
notifier: S,
|
signaler: Signaler<SessionSignal>,
|
||||||
logger: ::slog::Logger,
|
logger: ::slog::Logger,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: SessionNotifier, Data: 'static> UdevHandlerImpl<S, Data> {
|
impl<Data: 'static> UdevHandlerImpl<Data> {
|
||||||
#[cfg(feature = "egl")]
|
#[cfg(feature = "egl")]
|
||||||
pub fn scan_connectors(
|
pub fn scan_connectors(
|
||||||
device: &mut RenderDevice,
|
device: &mut RenderDevice,
|
||||||
|
@ -375,7 +368,7 @@ impl<S: SessionNotifier, Data: 'static> UdevHandlerImpl<S, Data> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: SessionNotifier, Data: 'static> UdevHandlerImpl<S, Data> {
|
impl<Data: 'static> UdevHandlerImpl<Data> {
|
||||||
fn device_added(&mut self, _device: dev_t, path: PathBuf) {
|
fn device_added(&mut self, _device: dev_t, path: PathBuf) {
|
||||||
// Try to open the device
|
// Try to open the device
|
||||||
if let Some(mut device) = self
|
if let Some(mut device) = self
|
||||||
|
@ -425,14 +418,14 @@ impl<S: SessionNotifier, Data: 'static> UdevHandlerImpl<S, Data> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "egl")]
|
#[cfg(feature = "egl")]
|
||||||
let backends = Rc::new(RefCell::new(UdevHandlerImpl::<S, Data>::scan_connectors(
|
let backends = Rc::new(RefCell::new(UdevHandlerImpl::<Data>::scan_connectors(
|
||||||
&mut device,
|
&mut device,
|
||||||
self.egl_buffer_reader.clone(),
|
self.egl_buffer_reader.clone(),
|
||||||
&self.logger,
|
&self.logger,
|
||||||
)));
|
)));
|
||||||
|
|
||||||
#[cfg(not(feature = "egl"))]
|
#[cfg(not(feature = "egl"))]
|
||||||
let backends = Rc::new(RefCell::new(UdevHandlerImpl::<S, Data>::scan_connectors(
|
let backends = Rc::new(RefCell::new(UdevHandlerImpl::<Data>::scan_connectors(
|
||||||
&mut device,
|
&mut device,
|
||||||
&self.logger,
|
&self.logger,
|
||||||
)));
|
)));
|
||||||
|
@ -449,16 +442,20 @@ impl<S: SessionNotifier, Data: 'static> UdevHandlerImpl<S, Data> {
|
||||||
dnd_icon: self.dnd_icon.clone(),
|
dnd_icon: self.dnd_icon.clone(),
|
||||||
logger: self.logger.clone(),
|
logger: self.logger.clone(),
|
||||||
});
|
});
|
||||||
let restart_id = self.notifier.register(DrmRendererSessionListener {
|
let mut listener = DrmRendererSessionListener {
|
||||||
renderer: renderer.clone(),
|
renderer: renderer.clone(),
|
||||||
loop_handle: self.loop_handle.clone(),
|
loop_handle: self.loop_handle.clone(),
|
||||||
|
};
|
||||||
|
let restart_token = self.signaler.register(move |signal| match signal {
|
||||||
|
SessionSignal::ActivateSession | SessionSignal::ActivateDevice { .. } => listener.activate(),
|
||||||
|
_ => {}
|
||||||
});
|
});
|
||||||
device.set_handler(DrmHandlerImpl {
|
device.set_handler(DrmHandlerImpl {
|
||||||
renderer,
|
renderer,
|
||||||
loop_handle: self.loop_handle.clone(),
|
loop_handle: self.loop_handle.clone(),
|
||||||
});
|
});
|
||||||
|
|
||||||
let device_session_id = self.notifier.register(device.observer());
|
device.link(self.signaler.clone());
|
||||||
let dev_id = device.device_id();
|
let dev_id = device.device_id();
|
||||||
let event_source = device_bind(&self.loop_handle, device)
|
let event_source = device_bind(&self.loop_handle, device)
|
||||||
.map_err(|e| -> IoError { e.into() })
|
.map_err(|e| -> IoError { e.into() })
|
||||||
|
@ -478,8 +475,7 @@ impl<S: SessionNotifier, Data: 'static> UdevHandlerImpl<S, Data> {
|
||||||
self.backends.insert(
|
self.backends.insert(
|
||||||
dev_id,
|
dev_id,
|
||||||
BackendData {
|
BackendData {
|
||||||
id: device_session_id,
|
_restart_token: restart_token,
|
||||||
restart_id,
|
|
||||||
event_source,
|
event_source,
|
||||||
surfaces: backends,
|
surfaces: backends,
|
||||||
},
|
},
|
||||||
|
@ -498,13 +494,10 @@ impl<S: SessionNotifier, Data: 'static> UdevHandlerImpl<S, Data> {
|
||||||
.with_source(&backend_data.event_source, |source| {
|
.with_source(&backend_data.event_source, |source| {
|
||||||
let mut backends = backend_data.surfaces.borrow_mut();
|
let mut backends = backend_data.surfaces.borrow_mut();
|
||||||
#[cfg(feature = "egl")]
|
#[cfg(feature = "egl")]
|
||||||
let new_backends = UdevHandlerImpl::<S, Data>::scan_connectors(
|
let new_backends =
|
||||||
&mut source.file,
|
UdevHandlerImpl::<Data>::scan_connectors(&mut source.file, egl_buffer_reader, logger);
|
||||||
egl_buffer_reader,
|
|
||||||
logger,
|
|
||||||
);
|
|
||||||
#[cfg(not(feature = "egl"))]
|
#[cfg(not(feature = "egl"))]
|
||||||
let new_backends = UdevHandlerImpl::<S, Data>::scan_connectors(&mut source.file, logger);
|
let new_backends = UdevHandlerImpl::<Data>::scan_connectors(&mut source.file, logger);
|
||||||
*backends = new_backends;
|
*backends = new_backends;
|
||||||
|
|
||||||
for renderer in backends.values() {
|
for renderer in backends.values() {
|
||||||
|
@ -537,9 +530,6 @@ impl<S: SessionNotifier, Data: 'static> UdevHandlerImpl<S, Data> {
|
||||||
*self.egl_buffer_reader.borrow_mut() = None;
|
*self.egl_buffer_reader.borrow_mut() = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.notifier.unregister(backend_data.id);
|
|
||||||
self.notifier.unregister(backend_data.restart_id);
|
|
||||||
debug!(self.logger, "Dropping device");
|
debug!(self.logger, "Dropping device");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -567,9 +557,8 @@ pub struct DrmRendererSessionListener<Data: 'static> {
|
||||||
loop_handle: LoopHandle<Data>,
|
loop_handle: LoopHandle<Data>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Data: 'static> SessionObserver for DrmRendererSessionListener<Data> {
|
impl<Data: 'static> DrmRendererSessionListener<Data> {
|
||||||
fn pause(&mut self, _device: Option<(u32, u32)>) {}
|
fn activate(&mut self) {
|
||||||
fn activate(&mut self, _device: Option<(u32, u32, Option<RawFd>)>) {
|
|
||||||
// we want to be called, after all session handling is done (TODO this is not so nice)
|
// we want to be called, after all session handling is done (TODO this is not so nice)
|
||||||
let renderer = self.renderer.clone();
|
let renderer = self.renderer.clone();
|
||||||
let handle = self.loop_handle.clone();
|
let handle = self.loop_handle.clone();
|
||||||
|
|
|
@ -44,6 +44,8 @@ pub struct AtomicDrmDevice<A: AsRawFd + 'static> {
|
||||||
active: Arc<AtomicBool>,
|
active: Arc<AtomicBool>,
|
||||||
backends: Rc<RefCell<HashMap<crtc::Handle, Weak<AtomicDrmSurfaceInternal<A>>>>>,
|
backends: Rc<RefCell<HashMap<crtc::Handle, Weak<AtomicDrmSurfaceInternal<A>>>>>,
|
||||||
handler: Option<RefCell<Box<dyn DeviceHandler<Device = AtomicDrmDevice<A>>>>>,
|
handler: Option<RefCell<Box<dyn DeviceHandler<Device = AtomicDrmDevice<A>>>>>,
|
||||||
|
#[cfg(feature = "backend_session")]
|
||||||
|
links: Vec<crate::signaling::SignalToken>,
|
||||||
logger: ::slog::Logger,
|
logger: ::slog::Logger,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,6 +326,8 @@ impl<A: AsRawFd + 'static> AtomicDrmDevice<A> {
|
||||||
active,
|
active,
|
||||||
backends: Rc::new(RefCell::new(HashMap::new())),
|
backends: Rc::new(RefCell::new(HashMap::new())),
|
||||||
handler: None,
|
handler: None,
|
||||||
|
#[cfg(feature = "backend_session")]
|
||||||
|
links: Vec::new(),
|
||||||
logger: log.clone(),
|
logger: log.clone(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,10 @@ use std::sync::Arc;
|
||||||
|
|
||||||
use super::{AtomicDrmDevice, AtomicDrmSurfaceInternal, Dev};
|
use super::{AtomicDrmDevice, AtomicDrmSurfaceInternal, Dev};
|
||||||
use crate::backend::drm::{common::Error, DevPath, Surface};
|
use crate::backend::drm::{common::Error, DevPath, Surface};
|
||||||
use crate::backend::session::{AsSessionObserver, SessionObserver};
|
use crate::{
|
||||||
|
backend::session::Signal as SessionSignal,
|
||||||
|
signaling::{Linkable, Signaler},
|
||||||
|
};
|
||||||
|
|
||||||
/// [`SessionObserver`](SessionObserver)
|
/// [`SessionObserver`](SessionObserver)
|
||||||
/// linked to the [`AtomicDrmDevice`](AtomicDrmDevice)
|
/// linked to the [`AtomicDrmDevice`](AtomicDrmDevice)
|
||||||
|
@ -31,20 +34,34 @@ pub struct AtomicDrmDeviceObserver<A: AsRawFd + 'static> {
|
||||||
logger: ::slog::Logger,
|
logger: ::slog::Logger,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A: AsRawFd + 'static> AsSessionObserver<AtomicDrmDeviceObserver<A>> for AtomicDrmDevice<A> {
|
impl<A: AsRawFd + 'static> Linkable<SessionSignal> for AtomicDrmDevice<A> {
|
||||||
fn observer(&mut self) -> AtomicDrmDeviceObserver<A> {
|
fn link(&mut self, signaler: Signaler<SessionSignal>) {
|
||||||
AtomicDrmDeviceObserver {
|
let mut observer = AtomicDrmDeviceObserver {
|
||||||
dev: Rc::downgrade(&self.dev),
|
dev: Rc::downgrade(&self.dev),
|
||||||
dev_id: self.dev_id,
|
dev_id: self.dev_id,
|
||||||
active: self.active.clone(),
|
active: self.active.clone(),
|
||||||
privileged: self.dev.privileged,
|
privileged: self.dev.privileged,
|
||||||
backends: Rc::downgrade(&self.backends),
|
backends: Rc::downgrade(&self.backends),
|
||||||
logger: self.logger.clone(),
|
logger: self.logger.clone(),
|
||||||
}
|
};
|
||||||
|
|
||||||
|
let token = signaler.register(move |signal| observer.signal(*signal));
|
||||||
|
self.links.push(token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A: AsRawFd + 'static> SessionObserver for AtomicDrmDeviceObserver<A> {
|
impl<A: AsRawFd + 'static> AtomicDrmDeviceObserver<A> {
|
||||||
|
fn signal(&mut self, signal: SessionSignal) {
|
||||||
|
match signal {
|
||||||
|
SessionSignal::PauseSession => self.pause(None),
|
||||||
|
SessionSignal::PauseDevice { major, minor } => self.pause(Some((major, minor))),
|
||||||
|
SessionSignal::ActivateSession => self.activate(None),
|
||||||
|
SessionSignal::ActivateDevice { major, minor, new_fd } => {
|
||||||
|
self.activate(Some((major, minor, new_fd)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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) {
|
||||||
|
@ -104,9 +121,7 @@ impl<A: AsRawFd + 'static> SessionObserver for AtomicDrmDeviceObserver<A> {
|
||||||
// TODO call drm-handler::error
|
// TODO call drm-handler::error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<A: AsRawFd + 'static> AtomicDrmDeviceObserver<A> {
|
|
||||||
fn reset_state(&mut self) -> Result<(), Error> {
|
fn reset_state(&mut self) -> Result<(), Error> {
|
||||||
if let Some(dev) = self.dev.upgrade() {
|
if let Some(dev) = self.dev.upgrade() {
|
||||||
let res_handles = ControlDevice::resource_handles(&*dev)
|
let res_handles = ControlDevice::resource_handles(&*dev)
|
||||||
|
|
|
@ -24,7 +24,6 @@ use crate::backend::graphics::gl::GLGraphicsBackend;
|
||||||
#[cfg(feature = "renderer_gl")]
|
#[cfg(feature = "renderer_gl")]
|
||||||
use crate::backend::graphics::PixelFormat;
|
use crate::backend::graphics::PixelFormat;
|
||||||
use crate::backend::graphics::{CursorBackend, SwapBuffersError};
|
use crate::backend::graphics::{CursorBackend, SwapBuffersError};
|
||||||
use crate::backend::session::{AsSessionObserver, SessionObserver};
|
|
||||||
|
|
||||||
use drm::{
|
use drm::{
|
||||||
control::{connector, crtc, encoder, framebuffer, plane, Device as ControlDevice, Mode, ResourceHandles},
|
control::{connector, crtc, encoder, framebuffer, plane, Device as ControlDevice, Mode, ResourceHandles},
|
||||||
|
@ -111,44 +110,16 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// [`SessionObserver`](::backend::session::SessionObserver) Wrapper to assist fallback
|
#[cfg(feature = "backend_session")]
|
||||||
/// in case initialization of the preferred device type fails.
|
impl<D1, D2> crate::signaling::Linkable<crate::backend::session::Signal> for FallbackDevice<D1, D2>
|
||||||
pub enum FallbackDeviceObserver<O1: SessionObserver + 'static, O2: SessionObserver + 'static> {
|
|
||||||
/// Variant for successful initialization of the preferred device
|
|
||||||
Preference(O1),
|
|
||||||
/// Variant for the fallback device
|
|
||||||
Fallback(O2),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<O1, O2, D1, D2> AsSessionObserver<FallbackDeviceObserver<O1, O2>> for FallbackDevice<D1, D2>
|
|
||||||
where
|
where
|
||||||
O1: SessionObserver + 'static,
|
D1: Device + crate::signaling::Linkable<crate::backend::session::Signal> + 'static,
|
||||||
O2: SessionObserver + 'static,
|
D2: Device + crate::signaling::Linkable<crate::backend::session::Signal> + 'static,
|
||||||
D1: Device + AsSessionObserver<O1> + 'static,
|
|
||||||
D2: Device + AsSessionObserver<O2> + 'static,
|
|
||||||
{
|
{
|
||||||
fn observer(&mut self) -> FallbackDeviceObserver<O1, O2> {
|
fn link(&mut self, signal: crate::signaling::Signaler<crate::backend::session::Signal>) {
|
||||||
match self {
|
match self {
|
||||||
FallbackDevice::Preference(dev) => FallbackDeviceObserver::Preference(dev.observer()),
|
FallbackDevice::Preference(d) => d.link(signal),
|
||||||
FallbackDevice::Fallback(dev) => FallbackDeviceObserver::Fallback(dev.observer()),
|
FallbackDevice::Fallback(d) => d.link(signal),
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<O1: SessionObserver + 'static, O2: SessionObserver + 'static> SessionObserver
|
|
||||||
for FallbackDeviceObserver<O1, O2>
|
|
||||||
{
|
|
||||||
fn pause(&mut self, device: Option<(u32, u32)>) {
|
|
||||||
match self {
|
|
||||||
FallbackDeviceObserver::Preference(dev) => dev.pause(device),
|
|
||||||
FallbackDeviceObserver::Fallback(dev) => dev.pause(device),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn activate(&mut self, device: Option<(u32, u32, Option<RawFd>)>) {
|
|
||||||
match self {
|
|
||||||
FallbackDeviceObserver::Preference(dev) => dev.activate(device),
|
|
||||||
FallbackDeviceObserver::Fallback(dev) => dev.activate(device),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,6 +62,8 @@ where
|
||||||
default_attributes: GlAttributes,
|
default_attributes: GlAttributes,
|
||||||
default_requirements: PixelFormatRequirements,
|
default_requirements: PixelFormatRequirements,
|
||||||
backends: Rc<RefCell<HashMap<crtc::Handle, BackendRef<D>>>>,
|
backends: Rc<RefCell<HashMap<crtc::Handle, BackendRef<D>>>>,
|
||||||
|
#[cfg(feature = "backend_session")]
|
||||||
|
links: Vec<crate::signaling::SignalToken>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B, D> AsRawFd for EglDevice<B, D>
|
impl<B, D> AsRawFd for EglDevice<B, D>
|
||||||
|
@ -129,6 +131,8 @@ where
|
||||||
default_requirements,
|
default_requirements,
|
||||||
backends: Rc::new(RefCell::new(HashMap::new())),
|
backends: Rc::new(RefCell::new(HashMap::new())),
|
||||||
logger: log,
|
logger: log,
|
||||||
|
#[cfg(feature = "backend_session")]
|
||||||
|
links: Vec::new(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
use drm::control::{connector, crtc, Mode};
|
use drm::control::{connector, crtc, Mode};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::os::unix::io::RawFd;
|
|
||||||
use std::rc::{Rc, Weak};
|
use std::rc::{Rc, Weak};
|
||||||
|
|
||||||
use super::{EglDevice, EglSurfaceInternal};
|
use super::{EglDevice, EglSurfaceInternal};
|
||||||
|
@ -15,42 +14,52 @@ use crate::backend::egl::{
|
||||||
ffi,
|
ffi,
|
||||||
native::{Backend, NativeDisplay, NativeSurface},
|
native::{Backend, NativeDisplay, NativeSurface},
|
||||||
};
|
};
|
||||||
use crate::backend::session::{AsSessionObserver, SessionObserver};
|
use crate::{
|
||||||
|
backend::session::Signal as SessionSignal,
|
||||||
|
signaling::{Linkable, Signaler},
|
||||||
|
};
|
||||||
|
|
||||||
/// [`SessionObserver`](SessionObserver)
|
/// [`SessionObserver`](SessionObserver)
|
||||||
/// linked to the [`EglDevice`](EglDevice) it was
|
/// linked to the [`EglDevice`](EglDevice) it was
|
||||||
/// created from.
|
/// created from.
|
||||||
pub struct EglDeviceObserver<S: SessionObserver + 'static, N: NativeSurface + Surface> {
|
pub struct EglDeviceObserver<N: NativeSurface + Surface> {
|
||||||
observer: S,
|
|
||||||
backends: Weak<RefCell<HashMap<crtc::Handle, Weak<EglSurfaceInternal<N>>>>>,
|
backends: Weak<RefCell<HashMap<crtc::Handle, Weak<EglSurfaceInternal<N>>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, B, D> AsSessionObserver<EglDeviceObserver<S, <D as Device>::Surface>> for EglDevice<B, D>
|
impl<B, D> Linkable<SessionSignal> for EglDevice<B, D>
|
||||||
where
|
where
|
||||||
S: SessionObserver + 'static,
|
|
||||||
B: Backend<Surface = <D as Device>::Surface, Error = <<D as Device>::Surface as Surface>::Error>
|
B: Backend<Surface = <D as Device>::Surface, Error = <<D as Device>::Surface as Surface>::Error>
|
||||||
+ 'static,
|
+ 'static,
|
||||||
D: Device
|
D: Device
|
||||||
+ NativeDisplay<B, Arguments = (crtc::Handle, Mode, Vec<connector::Handle>)>
|
+ NativeDisplay<B, Arguments = (crtc::Handle, Mode, Vec<connector::Handle>)>
|
||||||
+ AsSessionObserver<S>
|
+ Linkable<SessionSignal>
|
||||||
+ 'static,
|
+ 'static,
|
||||||
<D as Device>::Surface: NativeSurface<Error = <<D as Device>::Surface as Surface>::Error>,
|
<D as Device>::Surface: NativeSurface<Error = <<D as Device>::Surface as Surface>::Error>,
|
||||||
{
|
{
|
||||||
fn observer(&mut self) -> EglDeviceObserver<S, <D as Device>::Surface> {
|
fn link(&mut self, signaler: Signaler<SessionSignal>) {
|
||||||
EglDeviceObserver {
|
let lower_signal = Signaler::new();
|
||||||
observer: self.dev.borrow_mut().observer(),
|
self.dev.borrow_mut().link(lower_signal.clone());
|
||||||
|
let mut observer = EglDeviceObserver {
|
||||||
backends: Rc::downgrade(&self.backends),
|
backends: Rc::downgrade(&self.backends),
|
||||||
|
};
|
||||||
|
|
||||||
|
let token = signaler.register(move |&signal| match signal {
|
||||||
|
SessionSignal::ActivateSession | SessionSignal::ActivateDevice { .. } => {
|
||||||
|
// Activate lower *before* we process the event
|
||||||
|
lower_signal.signal(signal);
|
||||||
|
observer.activate()
|
||||||
}
|
}
|
||||||
|
_ => {
|
||||||
|
lower_signal.signal(signal);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
self.links.push(token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: SessionObserver + 'static, N: NativeSurface + Surface> SessionObserver for EglDeviceObserver<S, N> {
|
impl<N: NativeSurface + Surface> EglDeviceObserver<N> {
|
||||||
fn pause(&mut self, devnum: Option<(u32, u32)>) {
|
fn activate(&mut self) {
|
||||||
self.observer.pause(devnum);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn activate(&mut self, devnum: Option<(u32, u32, Option<RawFd>)>) {
|
|
||||||
self.observer.activate(devnum);
|
|
||||||
if let Some(backends) = self.backends.upgrade() {
|
if let Some(backends) = self.backends.upgrade() {
|
||||||
for (_crtc, backend) in backends.borrow().iter() {
|
for (_crtc, backend) in backends.borrow().iter() {
|
||||||
if let Some(backend) = backend.upgrade() {
|
if let Some(backend) = backend.upgrade() {
|
||||||
|
|
|
@ -82,6 +82,8 @@ pub struct EglStreamDevice<D: RawDevice + ControlDevice + 'static> {
|
||||||
raw: D,
|
raw: D,
|
||||||
backends: Rc<RefCell<HashMap<crtc::Handle, Weak<EglStreamSurfaceInternal<D>>>>>,
|
backends: Rc<RefCell<HashMap<crtc::Handle, Weak<EglStreamSurfaceInternal<D>>>>>,
|
||||||
logger: ::slog::Logger,
|
logger: ::slog::Logger,
|
||||||
|
#[cfg(feature = "backend_session")]
|
||||||
|
links: Vec<crate::signaling::SignalToken>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D: RawDevice + ControlDevice + 'static> EglStreamDevice<D> {
|
impl<D: RawDevice + ControlDevice + 'static> EglStreamDevice<D> {
|
||||||
|
@ -202,6 +204,8 @@ impl<D: RawDevice + ControlDevice + 'static> EglStreamDevice<D> {
|
||||||
raw,
|
raw,
|
||||||
backends: Rc::new(RefCell::new(HashMap::new())),
|
backends: Rc::new(RefCell::new(HashMap::new())),
|
||||||
logger: log,
|
logger: log,
|
||||||
|
#[cfg(feature = "backend_session")]
|
||||||
|
links: Vec::new(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,11 +6,11 @@
|
||||||
use super::{EglStreamDevice, EglStreamSurfaceInternal};
|
use super::{EglStreamDevice, EglStreamSurfaceInternal};
|
||||||
use crate::backend::drm::{RawDevice, Surface};
|
use crate::backend::drm::{RawDevice, Surface};
|
||||||
use crate::backend::egl::ffi;
|
use crate::backend::egl::ffi;
|
||||||
use crate::backend::session::{AsSessionObserver, SessionObserver};
|
use crate::backend::session::Signal as SessionSignal;
|
||||||
|
use crate::signaling::{Linkable, Signaler};
|
||||||
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::os::unix::io::RawFd;
|
|
||||||
use std::rc::{Rc, Weak};
|
use std::rc::{Rc, Weak};
|
||||||
|
|
||||||
use drm::control::{crtc, Device as ControlDevice};
|
use drm::control::{crtc, Device as ControlDevice};
|
||||||
|
@ -18,31 +18,42 @@ use drm::control::{crtc, Device as ControlDevice};
|
||||||
/// [`SessionObserver`](SessionObserver)
|
/// [`SessionObserver`](SessionObserver)
|
||||||
/// linked to the [`EglStreamDevice`](EglStreamDevice) it was
|
/// linked to the [`EglStreamDevice`](EglStreamDevice) it was
|
||||||
/// created from.
|
/// created from.
|
||||||
pub struct EglStreamDeviceObserver<
|
pub struct EglStreamDeviceObserver<D: RawDevice + 'static> {
|
||||||
O: SessionObserver + 'static,
|
|
||||||
D: RawDevice + AsSessionObserver<O> + 'static,
|
|
||||||
> {
|
|
||||||
observer: O,
|
|
||||||
backends: Weak<RefCell<HashMap<crtc::Handle, Weak<EglStreamSurfaceInternal<D>>>>>,
|
backends: Weak<RefCell<HashMap<crtc::Handle, Weak<EglStreamSurfaceInternal<D>>>>>,
|
||||||
logger: ::slog::Logger,
|
logger: ::slog::Logger,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<O: SessionObserver + 'static, D: RawDevice + ControlDevice + AsSessionObserver<O> + 'static>
|
impl<D> Linkable<SessionSignal> for EglStreamDevice<D>
|
||||||
AsSessionObserver<EglStreamDeviceObserver<O, D>> for EglStreamDevice<D>
|
where
|
||||||
|
D: RawDevice + ControlDevice + Linkable<SessionSignal> + 'static,
|
||||||
{
|
{
|
||||||
fn observer(&mut self) -> EglStreamDeviceObserver<O, D> {
|
fn link(&mut self, signaler: Signaler<SessionSignal>) {
|
||||||
EglStreamDeviceObserver {
|
let lower_signal = Signaler::new();
|
||||||
observer: self.raw.observer(),
|
self.raw.link(lower_signal.clone());
|
||||||
|
let mut observer = EglStreamDeviceObserver {
|
||||||
backends: Rc::downgrade(&self.backends),
|
backends: Rc::downgrade(&self.backends),
|
||||||
logger: self.logger.clone(),
|
logger: self.logger.clone(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let token = signaler.register(move |&signal| match signal {
|
||||||
|
SessionSignal::ActivateSession | SessionSignal::ActivateDevice { .. } => {
|
||||||
|
// activate lower device *before* we process the signal
|
||||||
|
lower_signal.signal(signal);
|
||||||
|
observer.activate();
|
||||||
}
|
}
|
||||||
|
SessionSignal::PauseSession | SessionSignal::PauseDevice { .. } => {
|
||||||
|
// pause lower device *after* we process the signal
|
||||||
|
observer.pause();
|
||||||
|
lower_signal.signal(signal);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
self.links.push(token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<O: SessionObserver + 'static, D: RawDevice + AsSessionObserver<O> + 'static> SessionObserver
|
impl<D: RawDevice + 'static> EglStreamDeviceObserver<D> {
|
||||||
for EglStreamDeviceObserver<O, D>
|
fn pause(&mut self) {
|
||||||
{
|
|
||||||
fn pause(&mut self, devnum: Option<(u32, u32)>) {
|
|
||||||
if let Some(backends) = self.backends.upgrade() {
|
if let Some(backends) = self.backends.upgrade() {
|
||||||
for (_, backend) in backends.borrow().iter() {
|
for (_, backend) in backends.borrow().iter() {
|
||||||
if let Some(backend) = backend.upgrade() {
|
if let Some(backend) = backend.upgrade() {
|
||||||
|
@ -60,12 +71,9 @@ impl<O: SessionObserver + 'static, D: RawDevice + AsSessionObserver<O> + 'static
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.observer.pause(devnum);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn activate(&mut self, devnum: Option<(u32, u32, Option<RawFd>)>) {
|
fn activate(&mut self) {
|
||||||
self.observer.activate(devnum);
|
|
||||||
if let Some(backends) = self.backends.upgrade() {
|
if let Some(backends) = self.backends.upgrade() {
|
||||||
for (_, backend) in backends.borrow().iter() {
|
for (_, backend) in backends.borrow().iter() {
|
||||||
if let Some(backend) = backend.upgrade() {
|
if let Some(backend) = backend.upgrade() {
|
||||||
|
|
|
@ -76,6 +76,8 @@ static LOAD: Once = Once::new();
|
||||||
pub struct GbmDevice<D: RawDevice + ControlDevice + 'static> {
|
pub struct GbmDevice<D: RawDevice + ControlDevice + 'static> {
|
||||||
pub(self) dev: Rc<RefCell<gbm::Device<D>>>,
|
pub(self) dev: Rc<RefCell<gbm::Device<D>>>,
|
||||||
backends: Rc<RefCell<HashMap<crtc::Handle, Weak<GbmSurfaceInternal<D>>>>>,
|
backends: Rc<RefCell<HashMap<crtc::Handle, Weak<GbmSurfaceInternal<D>>>>>,
|
||||||
|
#[cfg(feature = "backend_session")]
|
||||||
|
links: Vec<crate::signaling::SignalToken>,
|
||||||
logger: ::slog::Logger,
|
logger: ::slog::Logger,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,6 +112,8 @@ impl<D: RawDevice + ControlDevice + 'static> GbmDevice<D> {
|
||||||
// Open the gbm device from the drm device
|
// Open the gbm device from the drm device
|
||||||
dev: Rc::new(RefCell::new(gbm::Device::new(dev).map_err(Error::InitFailed)?)),
|
dev: Rc::new(RefCell::new(gbm::Device::new(dev).map_err(Error::InitFailed)?)),
|
||||||
backends: Rc::new(RefCell::new(HashMap::new())),
|
backends: Rc::new(RefCell::new(HashMap::new())),
|
||||||
|
#[cfg(feature = "backend_session")]
|
||||||
|
links: Vec::new(),
|
||||||
logger: log,
|
logger: log,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,53 +7,57 @@ use drm::control::crtc;
|
||||||
use gbm::BufferObject;
|
use gbm::BufferObject;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::os::unix::io::RawFd;
|
|
||||||
use std::rc::{Rc, Weak};
|
use std::rc::{Rc, Weak};
|
||||||
|
|
||||||
use super::{GbmDevice, GbmSurfaceInternal};
|
use super::{GbmDevice, GbmSurfaceInternal};
|
||||||
use crate::backend::drm::{RawDevice, RawSurface};
|
use crate::backend::drm::{Device, RawDevice};
|
||||||
use crate::backend::graphics::CursorBackend;
|
use crate::backend::graphics::CursorBackend;
|
||||||
use crate::backend::session::{AsSessionObserver, SessionObserver};
|
use crate::{
|
||||||
|
backend::session::Signal as SessionSignal,
|
||||||
|
signaling::{Linkable, Signaler},
|
||||||
|
};
|
||||||
|
|
||||||
/// [`SessionObserver`](SessionObserver)
|
/// [`SessionObserver`](SessionObserver)
|
||||||
/// linked to the [`GbmDevice`](GbmDevice) it was
|
/// linked to the [`GbmDevice`](GbmDevice) it was
|
||||||
/// created from.
|
/// created from.
|
||||||
pub struct GbmDeviceObserver<
|
pub(crate) struct GbmDeviceObserver<D: RawDevice + ::drm::control::Device + 'static> {
|
||||||
S: SessionObserver + 'static,
|
|
||||||
D: RawDevice + ::drm::control::Device + AsSessionObserver<S> + 'static,
|
|
||||||
> {
|
|
||||||
observer: S,
|
|
||||||
backends: Weak<RefCell<HashMap<crtc::Handle, Weak<GbmSurfaceInternal<D>>>>>,
|
backends: Weak<RefCell<HashMap<crtc::Handle, Weak<GbmSurfaceInternal<D>>>>>,
|
||||||
logger: ::slog::Logger,
|
logger: ::slog::Logger,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<
|
impl<D> Linkable<SessionSignal> for GbmDevice<D>
|
||||||
O: SessionObserver + 'static,
|
where
|
||||||
S: CursorBackend<CursorFormat = dyn drm::buffer::Buffer> + RawSurface + 'static,
|
D: RawDevice + drm::control::Device + Linkable<SessionSignal> + 'static,
|
||||||
D: RawDevice<Surface = S> + drm::control::Device + AsSessionObserver<O> + 'static,
|
<D as Device>::Surface: CursorBackend<CursorFormat = dyn drm::buffer::Buffer>,
|
||||||
> AsSessionObserver<GbmDeviceObserver<O, D>> for GbmDevice<D>
|
|
||||||
{
|
{
|
||||||
fn observer(&mut self) -> GbmDeviceObserver<O, D> {
|
fn link(&mut self, signaler: Signaler<SessionSignal>) {
|
||||||
GbmDeviceObserver {
|
let lower_signal = Signaler::new();
|
||||||
observer: (**self.dev.borrow_mut()).observer(),
|
self.dev.borrow_mut().link(lower_signal.clone());
|
||||||
|
let mut observer = GbmDeviceObserver {
|
||||||
backends: Rc::downgrade(&self.backends),
|
backends: Rc::downgrade(&self.backends),
|
||||||
logger: self.logger.clone(),
|
logger: self.logger.clone(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let token = signaler.register(move |&signal| match signal {
|
||||||
|
SessionSignal::ActivateSession | SessionSignal::ActivateDevice { .. } => {
|
||||||
|
// Activate lower *before* we process the event
|
||||||
|
lower_signal.signal(signal);
|
||||||
|
observer.activate()
|
||||||
}
|
}
|
||||||
|
_ => {
|
||||||
|
lower_signal.signal(signal);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
self.links.push(token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<
|
impl<D: RawDevice + drm::control::Device + 'static> GbmDeviceObserver<D>
|
||||||
O: SessionObserver + 'static,
|
where
|
||||||
S: CursorBackend<CursorFormat = dyn drm::buffer::Buffer> + RawSurface + 'static,
|
<D as Device>::Surface: CursorBackend<CursorFormat = dyn drm::buffer::Buffer>,
|
||||||
D: RawDevice<Surface = S> + drm::control::Device + AsSessionObserver<O> + 'static,
|
|
||||||
> SessionObserver for GbmDeviceObserver<O, D>
|
|
||||||
{
|
{
|
||||||
fn pause(&mut self, devnum: Option<(u32, u32)>) {
|
fn activate(&mut self) {
|
||||||
self.observer.pause(devnum);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn activate(&mut self, devnum: Option<(u32, u32, Option<RawFd>)>) {
|
|
||||||
self.observer.activate(devnum);
|
|
||||||
let mut crtcs = Vec::new();
|
let mut crtcs = Vec::new();
|
||||||
if let Some(backends) = self.backends.upgrade() {
|
if let Some(backends) = self.backends.upgrade() {
|
||||||
for (crtc, backend) in backends.borrow().iter() {
|
for (crtc, backend) in backends.borrow().iter() {
|
||||||
|
|
|
@ -40,6 +40,8 @@ pub struct LegacyDrmDevice<A: AsRawFd + 'static> {
|
||||||
active: Arc<AtomicBool>,
|
active: Arc<AtomicBool>,
|
||||||
backends: Rc<RefCell<HashMap<crtc::Handle, Weak<LegacyDrmSurfaceInternal<A>>>>>,
|
backends: Rc<RefCell<HashMap<crtc::Handle, Weak<LegacyDrmSurfaceInternal<A>>>>>,
|
||||||
handler: Option<RefCell<Box<dyn DeviceHandler<Device = LegacyDrmDevice<A>>>>>,
|
handler: Option<RefCell<Box<dyn DeviceHandler<Device = LegacyDrmDevice<A>>>>>,
|
||||||
|
#[cfg(feature = "backend_session")]
|
||||||
|
links: Vec<crate::signaling::SignalToken>,
|
||||||
logger: ::slog::Logger,
|
logger: ::slog::Logger,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,6 +186,8 @@ impl<A: AsRawFd + 'static> LegacyDrmDevice<A> {
|
||||||
active,
|
active,
|
||||||
backends: Rc::new(RefCell::new(HashMap::new())),
|
backends: Rc::new(RefCell::new(HashMap::new())),
|
||||||
handler: None,
|
handler: None,
|
||||||
|
#[cfg(feature = "backend_session")]
|
||||||
|
links: Vec::new(),
|
||||||
logger: log.clone(),
|
logger: log.clone(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,12 +16,15 @@ use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use super::{Dev, DevPath, Error, LegacyDrmDevice, LegacyDrmSurfaceInternal};
|
use super::{Dev, DevPath, Error, LegacyDrmDevice, LegacyDrmSurfaceInternal};
|
||||||
use crate::backend::session::{AsSessionObserver, SessionObserver};
|
use crate::{
|
||||||
|
backend::session::Signal as SessionSignal,
|
||||||
|
signaling::{Linkable, Signaler},
|
||||||
|
};
|
||||||
|
|
||||||
/// [`SessionObserver`](SessionObserver)
|
/// [`SessionObserver`](SessionObserver)
|
||||||
/// linked to the [`LegacyDrmDevice`](LegacyDrmDevice)
|
/// linked to the [`LegacyDrmDevice`](LegacyDrmDevice)
|
||||||
/// it was created from.
|
/// it was created from.
|
||||||
pub struct LegacyDrmDeviceObserver<A: AsRawFd + 'static> {
|
pub(crate) struct LegacyDrmDeviceObserver<A: AsRawFd + 'static> {
|
||||||
dev: Weak<Dev<A>>,
|
dev: Weak<Dev<A>>,
|
||||||
dev_id: dev_t,
|
dev_id: dev_t,
|
||||||
privileged: bool,
|
privileged: bool,
|
||||||
|
@ -30,20 +33,34 @@ pub struct LegacyDrmDeviceObserver<A: AsRawFd + 'static> {
|
||||||
logger: ::slog::Logger,
|
logger: ::slog::Logger,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A: AsRawFd + 'static> AsSessionObserver<LegacyDrmDeviceObserver<A>> for LegacyDrmDevice<A> {
|
impl<A: AsRawFd + 'static> Linkable<SessionSignal> for LegacyDrmDevice<A> {
|
||||||
fn observer(&mut self) -> LegacyDrmDeviceObserver<A> {
|
fn link(&mut self, signaler: Signaler<SessionSignal>) {
|
||||||
LegacyDrmDeviceObserver {
|
let mut observer = LegacyDrmDeviceObserver {
|
||||||
dev: Rc::downgrade(&self.dev),
|
dev: Rc::downgrade(&self.dev),
|
||||||
dev_id: self.dev_id,
|
dev_id: self.dev_id,
|
||||||
active: self.active.clone(),
|
active: self.active.clone(),
|
||||||
privileged: self.dev.privileged,
|
privileged: self.dev.privileged,
|
||||||
backends: Rc::downgrade(&self.backends),
|
backends: Rc::downgrade(&self.backends),
|
||||||
logger: self.logger.clone(),
|
logger: self.logger.clone(),
|
||||||
}
|
};
|
||||||
|
|
||||||
|
let token = signaler.register(move |signal| observer.signal(*signal));
|
||||||
|
self.links.push(token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A: AsRawFd + 'static> SessionObserver for LegacyDrmDeviceObserver<A> {
|
impl<A: AsRawFd + 'static> LegacyDrmDeviceObserver<A> {
|
||||||
|
fn signal(&mut self, signal: SessionSignal) {
|
||||||
|
match signal {
|
||||||
|
SessionSignal::PauseSession => self.pause(None),
|
||||||
|
SessionSignal::PauseDevice { major, minor } => self.pause(Some((major, minor))),
|
||||||
|
SessionSignal::ActivateSession => self.activate(None),
|
||||||
|
SessionSignal::ActivateDevice { major, minor, new_fd } => {
|
||||||
|
self.activate(Some((major, minor, new_fd)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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) {
|
||||||
|
|
|
@ -5,7 +5,10 @@ use helpers::{on_device_event, on_keyboard_event, on_pointer_event, on_touch_eve
|
||||||
|
|
||||||
use crate::backend::input::{self as backend, Axis, InputBackend, InputEvent};
|
use crate::backend::input::{self as backend, Axis, InputBackend, InputEvent};
|
||||||
#[cfg(feature = "backend_session")]
|
#[cfg(feature = "backend_session")]
|
||||||
use crate::backend::session::{AsErrno, Session, SessionObserver};
|
use crate::{
|
||||||
|
backend::session::{AsErrno, Session, Signal as SessionSignal},
|
||||||
|
signaling::{Linkable, SignalToken, Signaler},
|
||||||
|
};
|
||||||
use input as libinput;
|
use input as libinput;
|
||||||
use input::event;
|
use input::event;
|
||||||
|
|
||||||
|
@ -33,6 +36,7 @@ pub struct LibinputInputBackend {
|
||||||
context: libinput::Libinput,
|
context: libinput::Libinput,
|
||||||
config: LibinputConfig,
|
config: LibinputConfig,
|
||||||
seats: HashMap<libinput::Seat, backend::Seat>,
|
seats: HashMap<libinput::Seat, backend::Seat>,
|
||||||
|
links: Vec<SignalToken>,
|
||||||
logger: ::slog::Logger,
|
logger: ::slog::Logger,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,11 +53,35 @@ impl LibinputInputBackend {
|
||||||
context,
|
context,
|
||||||
config: LibinputConfig { devices: Vec::new() },
|
config: LibinputConfig { devices: Vec::new() },
|
||||||
seats: HashMap::new(),
|
seats: HashMap::new(),
|
||||||
|
links: Vec::new(),
|
||||||
logger: log,
|
logger: log,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "backend_session")]
|
||||||
|
impl Linkable<SessionSignal> for LibinputInputBackend {
|
||||||
|
fn link(&mut self, signaler: Signaler<SessionSignal>) {
|
||||||
|
let mut input = self.context.clone();
|
||||||
|
let log = self.logger.clone();
|
||||||
|
let token = signaler.register(move |s| match s {
|
||||||
|
SessionSignal::PauseSession
|
||||||
|
| SessionSignal::PauseDevice {
|
||||||
|
major: INPUT_MAJOR, ..
|
||||||
|
} => {
|
||||||
|
input.suspend();
|
||||||
|
}
|
||||||
|
SessionSignal::ActivateSession | SessionSignal::ActivateDevice { .. } => {
|
||||||
|
if input.resume().is_err() {
|
||||||
|
error!(log, "Failed to resume libinput context");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
});
|
||||||
|
self.links.push(token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl backend::Event for event::keyboard::KeyboardKeyEvent {
|
impl backend::Event for event::keyboard::KeyboardKeyEvent {
|
||||||
fn time(&self) -> u32 {
|
fn time(&self) -> u32 {
|
||||||
event::keyboard::KeyboardEventTrait::time(self)
|
event::keyboard::KeyboardEventTrait::time(self)
|
||||||
|
@ -390,25 +418,6 @@ impl From<event::pointer::ButtonState> for backend::MouseButtonState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "backend_session")]
|
|
||||||
impl SessionObserver for libinput::Libinput {
|
|
||||||
fn pause(&mut self, device: Option<(u32, u32)>) {
|
|
||||||
if let Some((major, _)) = device {
|
|
||||||
if major != INPUT_MAJOR {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// lets hope multiple suspends are okay in case of logind?
|
|
||||||
self.suspend()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn activate(&mut self, _device: Option<(u32, u32, Option<RawFd>)>) {
|
|
||||||
// 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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Wrapper for types implementing the [`Session`] trait to provide
|
/// Wrapper for types implementing the [`Session`] trait to provide
|
||||||
/// a [`libinput::LibinputInterface`] implementation.
|
/// a [`libinput::LibinputInterface`] implementation.
|
||||||
#[cfg(feature = "backend_session")]
|
#[cfg(feature = "backend_session")]
|
||||||
|
|
|
@ -35,8 +35,9 @@
|
||||||
use super::logind::{self, LogindSession, LogindSessionNotifier};
|
use super::logind::{self, LogindSession, LogindSessionNotifier};
|
||||||
use super::{
|
use super::{
|
||||||
direct::{self, DirectSession, DirectSessionNotifier},
|
direct::{self, DirectSession, DirectSessionNotifier},
|
||||||
AsErrno, Session, SessionNotifier, SessionObserver,
|
AsErrno, Session, Signal as SessionSignal,
|
||||||
};
|
};
|
||||||
|
use crate::signaling::Signaler;
|
||||||
use nix::fcntl::OFlag;
|
use nix::fcntl::OFlag;
|
||||||
use std::{cell::RefCell, io, os::unix::io::RawFd, path::Path, rc::Rc};
|
use std::{cell::RefCell, io, os::unix::io::RawFd, path::Path, rc::Rc};
|
||||||
|
|
||||||
|
@ -61,16 +62,6 @@ pub enum AutoSessionNotifier {
|
||||||
Direct(DirectSessionNotifier),
|
Direct(DirectSessionNotifier),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Id's used by the [`AutoSessionNotifier`] internally.
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
|
||||||
pub struct AutoId(AutoIdInternal);
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
|
||||||
enum AutoIdInternal {
|
|
||||||
#[cfg(feature = "backend_session_logind")]
|
|
||||||
Logind(logind::Id),
|
|
||||||
Direct(direct::Id),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AutoSession {
|
impl AutoSession {
|
||||||
/// Tries to create a new session via the best available interface.
|
/// Tries to create a new session via the best available interface.
|
||||||
#[cfg(feature = "backend_session_logind")]
|
#[cfg(feature = "backend_session_logind")]
|
||||||
|
@ -171,33 +162,15 @@ impl Session for AutoSession {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SessionNotifier for AutoSessionNotifier {
|
impl AutoSessionNotifier {
|
||||||
type Id = AutoId;
|
/// Get a handle to the Signaler of this session.
|
||||||
|
///
|
||||||
fn register<S: SessionObserver + 'static>(&mut self, signal: S) -> Self::Id {
|
/// You can use it to listen for signals generated by the session.
|
||||||
|
pub fn signaler(&self) -> Signaler<SessionSignal> {
|
||||||
match *self {
|
match *self {
|
||||||
#[cfg(feature = "backend_session_logind")]
|
#[cfg(feature = "backend_session_logind")]
|
||||||
AutoSessionNotifier::Logind(ref mut logind) => {
|
AutoSessionNotifier::Logind(ref logind) => logind.signaler(),
|
||||||
AutoId(AutoIdInternal::Logind(SessionNotifier::register(logind, signal)))
|
AutoSessionNotifier::Direct(ref direct) => direct.signaler(),
|
||||||
}
|
|
||||||
AutoSessionNotifier::Direct(ref mut direct) => {
|
|
||||||
AutoId(AutoIdInternal::Direct(SessionNotifier::register(direct, signal)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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))) => {
|
|
||||||
SessionNotifier::unregister(logind, signal)
|
|
||||||
}
|
|
||||||
(&mut AutoSessionNotifier::Direct(ref mut direct), AutoId(AutoIdInternal::Direct(signal))) => {
|
|
||||||
SessionNotifier::unregister(direct, signal)
|
|
||||||
}
|
|
||||||
// this pattern is needed when the logind backend is activated
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,10 @@
|
||||||
//! The [`LogindSessionNotifier`](::backend::session::dbus::logind::LogindSessionNotifier) is to be inserted into
|
//! The [`LogindSessionNotifier`](::backend::session::dbus::logind::LogindSessionNotifier) is to be inserted into
|
||||||
//! a calloop event source to have its events processed.
|
//! a calloop event source to have its events processed.
|
||||||
|
|
||||||
use crate::backend::session::{AsErrno, Session, SessionNotifier, SessionObserver};
|
use crate::{
|
||||||
|
backend::session::{AsErrno, Session, Signal as SessionSignal},
|
||||||
|
signaling::Signaler,
|
||||||
|
};
|
||||||
use dbus::{
|
use dbus::{
|
||||||
arg::{messageitem::MessageItem, OwnedFd},
|
arg::{messageitem::MessageItem, OwnedFd},
|
||||||
strings::{BusName, Interface, Member, Path as DbusPath},
|
strings::{BusName, Interface, Member, Path as DbusPath},
|
||||||
|
@ -62,7 +65,7 @@ struct LogindSessionImpl {
|
||||||
conn: RefCell<DBusConnection>,
|
conn: RefCell<DBusConnection>,
|
||||||
session_path: DbusPath<'static>,
|
session_path: DbusPath<'static>,
|
||||||
active: AtomicBool,
|
active: AtomicBool,
|
||||||
signals: RefCell<Vec<Option<Box<dyn SessionObserver>>>>,
|
signaler: Signaler<SessionSignal>,
|
||||||
seat: String,
|
seat: String,
|
||||||
logger: ::slog::Logger,
|
logger: ::slog::Logger,
|
||||||
}
|
}
|
||||||
|
@ -165,7 +168,6 @@ impl LogindSession {
|
||||||
Some(vec![false.into()]),
|
Some(vec![false.into()]),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let signals = RefCell::new(Vec::new());
|
|
||||||
let conn = RefCell::new(conn);
|
let conn = RefCell::new(conn);
|
||||||
|
|
||||||
let internal = Rc::new(LogindSessionImpl {
|
let internal = Rc::new(LogindSessionImpl {
|
||||||
|
@ -173,7 +175,7 @@ impl LogindSession {
|
||||||
conn,
|
conn,
|
||||||
session_path,
|
session_path,
|
||||||
active: AtomicBool::new(true),
|
active: AtomicBool::new(true),
|
||||||
signals,
|
signaler: Signaler::new(),
|
||||||
seat: seat.clone(),
|
seat: seat.clone(),
|
||||||
logger: logger.new(o!("id" => session_id, "seat" => seat.clone(), "vt" => format!("{:?}", &vt))),
|
logger: logger.new(o!("id" => session_id, "seat" => seat.clone(), "vt" => format!("{:?}", &vt))),
|
||||||
});
|
});
|
||||||
|
@ -196,6 +198,13 @@ impl LogindSessionNotifier {
|
||||||
seat: self.internal.seat.clone(),
|
seat: self.internal.seat.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a handle to the Signaler of this session.
|
||||||
|
///
|
||||||
|
/// You can use it to listen for signals generated by the session.
|
||||||
|
pub fn signaler(&self) -> Signaler<SessionSignal> {
|
||||||
|
self.internal.signaler.clone()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LogindSessionImpl {
|
impl LogindSessionImpl {
|
||||||
|
@ -256,11 +265,7 @@ impl LogindSessionImpl {
|
||||||
//Ok... now what?
|
//Ok... now what?
|
||||||
//This session will never live again, but the user maybe has other sessions open
|
//This session will never live again, but the user maybe has other sessions open
|
||||||
//So lets just put it to sleep.. forever
|
//So lets just put it to sleep.. forever
|
||||||
for signal in &mut *self.signals.borrow_mut() {
|
self.signaler.signal(SessionSignal::PauseSession);
|
||||||
if let Some(ref mut signal) = signal {
|
|
||||||
signal.pause(None);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.active.store(false, Ordering::SeqCst);
|
self.active.store(false, Ordering::SeqCst);
|
||||||
warn!(self.logger, "Session is now considered inactive");
|
warn!(self.logger, "Session is now considered inactive");
|
||||||
} else if &*message.interface().unwrap() == "org.freedesktop.login1.Session" {
|
} else if &*message.interface().unwrap() == "org.freedesktop.login1.Session" {
|
||||||
|
@ -287,11 +292,7 @@ impl LogindSessionImpl {
|
||||||
// notifications about it.
|
// notifications about it.
|
||||||
// This is handled via udev and is not part of our session api.
|
// This is handled via udev and is not part of our session api.
|
||||||
if pause_type != "gone" {
|
if pause_type != "gone" {
|
||||||
for signal in &mut *self.signals.borrow_mut() {
|
self.signaler.signal(SessionSignal::PauseDevice { major, minor });
|
||||||
if let Some(ref mut signal) = signal {
|
|
||||||
signal.pause(Some((major, minor)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// the other possible types are "force" or "gone" (unplugged),
|
// the other possible types are "force" or "gone" (unplugged),
|
||||||
// both expect no acknowledgement (note even this is not *really* necessary,
|
// both expect no acknowledgement (note even this is not *really* necessary,
|
||||||
|
@ -313,11 +314,11 @@ impl LogindSessionImpl {
|
||||||
let minor = minor.ok_or(Error::UnexpectedMethodReturn)?;
|
let minor = minor.ok_or(Error::UnexpectedMethodReturn)?;
|
||||||
let fd = fd.ok_or(Error::UnexpectedMethodReturn)?.into_fd();
|
let fd = fd.ok_or(Error::UnexpectedMethodReturn)?.into_fd();
|
||||||
debug!(self.logger, "Reactivating device ({},{})", major, minor);
|
debug!(self.logger, "Reactivating device ({},{})", major, minor);
|
||||||
for signal in &mut *self.signals.borrow_mut() {
|
self.signaler.signal(SessionSignal::ActivateDevice {
|
||||||
if let Some(ref mut signal) = signal {
|
major,
|
||||||
signal.activate(Some((major, minor, Some(fd))));
|
minor,
|
||||||
}
|
new_fd: Some(fd),
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
} else if &*message.interface().unwrap() == "org.freedesktop.DBus.Properties"
|
} else if &*message.interface().unwrap() == "org.freedesktop.DBus.Properties"
|
||||||
&& &*message.member().unwrap() == "PropertiesChanged"
|
&& &*message.member().unwrap() == "PropertiesChanged"
|
||||||
|
@ -421,22 +422,6 @@ impl Session for LogindSession {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ids of registered [`SessionObserver`]s of the [`LogindSessionNotifier`]
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
|
||||||
pub struct Id(usize);
|
|
||||||
|
|
||||||
impl SessionNotifier for LogindSessionNotifier {
|
|
||||||
type Id = Id;
|
|
||||||
|
|
||||||
fn register<S: SessionObserver + 'static>(&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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for LogindSessionNotifier {
|
impl Drop for LogindSessionNotifier {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
info!(self.internal.logger, "Closing logind session");
|
info!(self.internal.logger, "Closing logind session");
|
||||||
|
|
|
@ -45,7 +45,9 @@
|
||||||
//! The [`DirectSessionNotifier`](::backend::session::direct::DirectSessionNotifier) is to be inserted into
|
//! The [`DirectSessionNotifier`](::backend::session::direct::DirectSessionNotifier) is to be inserted into
|
||||||
//! a calloop event source to have its events processed.
|
//! a calloop event source to have its events processed.
|
||||||
|
|
||||||
use super::{AsErrno, Session, SessionNotifier, SessionObserver};
|
use super::{AsErrno, Session, Signal as SessionSignal};
|
||||||
|
use crate::signaling::Signaler;
|
||||||
|
|
||||||
use calloop::signals::{Signal, Signals};
|
use calloop::signals::{Signal, Signals};
|
||||||
use nix::{
|
use nix::{
|
||||||
fcntl::{self, open, OFlag},
|
fcntl::{self, open, OFlag},
|
||||||
|
@ -152,7 +154,7 @@ pub struct DirectSession {
|
||||||
pub struct DirectSessionNotifier {
|
pub struct DirectSessionNotifier {
|
||||||
tty: RawFd,
|
tty: RawFd,
|
||||||
active: Arc<AtomicBool>,
|
active: Arc<AtomicBool>,
|
||||||
signals: Vec<Option<Box<dyn SessionObserver>>>,
|
signaler: Signaler<SessionSignal>,
|
||||||
signal: Signal,
|
signal: Signal,
|
||||||
logger: ::slog::Logger,
|
logger: ::slog::Logger,
|
||||||
source: Option<Signals>,
|
source: Option<Signals>,
|
||||||
|
@ -196,7 +198,7 @@ impl DirectSession {
|
||||||
DirectSessionNotifier {
|
DirectSessionNotifier {
|
||||||
tty: fd,
|
tty: fd,
|
||||||
active,
|
active,
|
||||||
signals: Vec::new(),
|
signaler: Signaler::new(),
|
||||||
signal,
|
signal,
|
||||||
logger: logger.new(o!("vt" => format!("{}", vt), "component" => "session_notifier")),
|
logger: logger.new(o!("vt" => format!("{}", vt), "component" => "session_notifier")),
|
||||||
source: None,
|
source: None,
|
||||||
|
@ -347,27 +349,11 @@ impl Drop for DirectSession {
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
pub struct Id(usize);
|
pub struct Id(usize);
|
||||||
|
|
||||||
impl SessionNotifier for DirectSessionNotifier {
|
|
||||||
type Id = Id;
|
|
||||||
|
|
||||||
fn register<S: SessionObserver + 'static>(&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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DirectSessionNotifier {
|
impl DirectSessionNotifier {
|
||||||
fn signal_received(&mut self) {
|
fn signal_received(&mut self) {
|
||||||
if self.active.load(Ordering::SeqCst) {
|
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 {
|
self.signaler.signal(SessionSignal::PauseSession);
|
||||||
if let Some(ref mut signal) = *signal {
|
|
||||||
signal.pause(None);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.active.store(false, Ordering::SeqCst);
|
self.active.store(false, Ordering::SeqCst);
|
||||||
unsafe {
|
unsafe {
|
||||||
tty::vt_rel_disp(self.tty, 1).expect("Unable to release tty lock");
|
tty::vt_rel_disp(self.tty, 1).expect("Unable to release tty lock");
|
||||||
|
@ -378,15 +364,18 @@ impl DirectSessionNotifier {
|
||||||
unsafe {
|
unsafe {
|
||||||
tty::vt_rel_disp(self.tty, tty::VT_ACKACQ).expect("Unable to acquire tty lock");
|
tty::vt_rel_disp(self.tty, tty::VT_ACKACQ).expect("Unable to acquire tty lock");
|
||||||
}
|
}
|
||||||
for signal in &mut self.signals {
|
self.signaler.signal(SessionSignal::ActivateSession);
|
||||||
if let Some(ref mut signal) = *signal {
|
|
||||||
signal.activate(None);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.active.store(true, Ordering::SeqCst);
|
self.active.store(true, Ordering::SeqCst);
|
||||||
info!(self.logger, "Session is now active again");
|
info!(self.logger, "Session is now active again");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a handle to the Signaler of this session.
|
||||||
|
///
|
||||||
|
/// You can use it to listen for signals generated by the session.
|
||||||
|
pub fn signaler(&self) -> Signaler<SessionSignal> {
|
||||||
|
self.signaler.clone()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl calloop::EventSource for DirectSessionNotifier {
|
impl calloop::EventSource for DirectSessionNotifier {
|
||||||
|
|
|
@ -42,57 +42,39 @@ pub trait Session {
|
||||||
fn seat(&self) -> String;
|
fn seat(&self) -> String;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Interface for registering for notifications for a given session.
|
/// Signals that can be generated by a session
|
||||||
///
|
///
|
||||||
/// Part of the session API which allows to get notified, when the given session
|
/// Objects that need to be notifier about activation and deactivation
|
||||||
/// gets paused or becomes active again. Any object implementing the [`SessionObserver`]
|
/// of devices need to be linked to the `Signaler` of the session providing
|
||||||
/// trait may be registered.
|
/// these signals.
|
||||||
pub trait SessionNotifier {
|
#[derive(Copy, Clone, Debug)]
|
||||||
/// Id type of registered observers
|
pub enum Signal {
|
||||||
type Id: PartialEq + Eq;
|
/// The whole session has been paused
|
||||||
|
|
||||||
/// Registers a given [`SessionObserver`].
|
|
||||||
///
|
///
|
||||||
/// Returns an id of the inserted observer, can be used to remove it again.
|
/// All devices should be considered as paused
|
||||||
fn register<S: SessionObserver + 'static>(&mut self, signal: S) -> Self::Id;
|
PauseSession,
|
||||||
/// Removes an observer by its given id from [`SessionNotifier::register`].
|
/// A given device has been paused
|
||||||
fn unregister(&mut self, signal: Self::Id);
|
PauseDevice {
|
||||||
}
|
/// Major number identifying the device
|
||||||
|
major: u32,
|
||||||
/// Trait describing the ability to return a [`SessionObserver`] related to Self.
|
/// Minor number identifying the device
|
||||||
///
|
minor: u32,
|
||||||
/// The returned [`SessionObserver`] is responsible to handle the [`pause`](SessionObserver::pause)
|
},
|
||||||
/// and [`activate`](SessionObserver::activate) signals.
|
/// The whole session has been activated
|
||||||
pub trait AsSessionObserver<S: SessionObserver + 'static> {
|
ActivateSession,
|
||||||
/// Create a [`SessionObserver`] linked to this object
|
/// A given device has been activated
|
||||||
fn observer(&mut self) -> S;
|
ActivateDevice {
|
||||||
}
|
/// Major number identifying the device
|
||||||
|
major: u32,
|
||||||
impl<T: SessionObserver + Clone + 'static> AsSessionObserver<T> for T {
|
/// Minor number identifying the device
|
||||||
fn observer(&mut self) -> T {
|
minor: u32,
|
||||||
self.clone()
|
/// New file descriptor for accessing the device
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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.
|
|
||||||
/// This interface provides callbacks for when that happens.
|
|
||||||
pub trait SessionObserver {
|
|
||||||
/// Session/Device is about to be paused.
|
|
||||||
///
|
///
|
||||||
/// If only a specific device shall be closed a device number in the form of
|
/// If it is not `None`, you should use this FD in place of the
|
||||||
/// (major, minor) is provided. All observers not using the specified device should
|
/// previous one for accessing this device. In case the old FD
|
||||||
/// ignore the signal in that case.
|
/// is different from the new one, the old one should be closed.
|
||||||
fn pause(&mut self, device: Option<(u32, u32)>);
|
new_fd: Option<RawFd>,
|
||||||
/// Session/Device got active again
|
},
|
||||||
///
|
|
||||||
/// If only a specific device shall be activated again a device number in the form of
|
|
||||||
/// `(major, major, Option<RawFd>)` 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(&mut self, device: Option<(u32, u32, Option<RawFd>)>);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Session for () {
|
impl Session for () {
|
||||||
|
@ -181,5 +163,3 @@ 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::*;
|
|
||||||
|
|
|
@ -1,69 +0,0 @@
|
||||||
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`](SessionObserver)s
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
|
|
||||||
pub struct Id(usize);
|
|
||||||
|
|
||||||
struct MultiObserver {
|
|
||||||
observer: Arc<Mutex<HashMap<Id, Box<dyn SessionObserver>>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SessionObserver for MultiObserver {
|
|
||||||
fn pause(&mut self, device: Option<(u32, u32)>) {
|
|
||||||
let mut lock = self.observer.lock().unwrap();
|
|
||||||
for 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 observer in lock.values_mut() {
|
|
||||||
observer.activate(device)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct MultiNotifier {
|
|
||||||
observer: Arc<Mutex<HashMap<Id, Box<dyn 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a pair of a linked [`SessionObserver`] and a
|
|
||||||
/// [`SessionNotifier`](SessionNotifier).
|
|
||||||
///
|
|
||||||
/// Observers added to the returned notifier are notified,
|
|
||||||
/// when the returned observer is notified.
|
|
||||||
pub fn notify_multiplexer() -> (impl SessionObserver, impl SessionNotifier<Id = Id>) {
|
|
||||||
let observer = Arc::new(Mutex::new(HashMap::new()));
|
|
||||||
|
|
||||||
(
|
|
||||||
MultiObserver {
|
|
||||||
observer: observer.clone(),
|
|
||||||
},
|
|
||||||
MultiNotifier { observer },
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -25,11 +25,19 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A signaler, main type for signaling
|
/// A signaler, main type for signaling
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Signaler<S> {
|
pub struct Signaler<S> {
|
||||||
inner: Rc<SignalInner<S>>,
|
inner: Rc<SignalInner<S>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Manual clone impl because of type parameters
|
||||||
|
impl<S> Clone for Signaler<S> {
|
||||||
|
fn clone(&self) -> Signaler<S> {
|
||||||
|
Signaler {
|
||||||
|
inner: self.inner.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<S> Signaler<S> {
|
impl<S> Signaler<S> {
|
||||||
/// Create a new signaler for given signal type
|
/// Create a new signaler for given signal type
|
||||||
pub fn new() -> Signaler<S> {
|
pub fn new() -> Signaler<S> {
|
||||||
|
@ -161,6 +169,15 @@ impl<S> SignalInner<S> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Trait representing the capability of an object to listen for some signals
|
||||||
|
///
|
||||||
|
/// It is provided so that the signaling system can play nicely into generic
|
||||||
|
/// constructs.
|
||||||
|
pub trait Linkable<S> {
|
||||||
|
/// Make this object listen for signals from given signaler
|
||||||
|
fn link(&mut self, signaler: Signaler<S>);
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
Loading…
Reference in New Issue