Introduce SessionObserver

`DrmDevice` and `UdevBackend` now do not need to be wrapped into `StateToken`s anymore, but can return a separate `SessionObserver` object using the new `AsSessionObserver` trait.

This change was motivated by allowing the `UdevHandle` to obtain a mutable reference to an `EventLoopHandle` to create wayland object, e.g. a `wl_output` object.

Previously this was not possible.

Depends on https://github.com/Smithay/wayland-rs/pull/164
This commit is contained in:
Drakulix 2018-01-31 17:23:05 +01:00
parent bdd8770ba6
commit b80674bdf5
10 changed files with 262 additions and 236 deletions

View File

@ -47,3 +47,9 @@ backend_session_udev = ["udev", "backend_session"]
backend_session_logind = ["dbus", "systemd", "backend_session"] backend_session_logind = ["dbus", "systemd", "backend_session"]
backend_udev = ["udev", "backend_drm", "backend_session_udev"] backend_udev = ["udev", "backend_drm", "backend_session_udev"]
renderer_glium = ["glium"] renderer_glium = ["glium"]
[patch.crates-io]
wayland-server = { git = "https://github.com/Drakulix/wayland-rs.git", branch = "feature/with_idata" }
wayland-protocols = { git = "https://github.com/Drakulix/wayland-rs.git", branch = "feature/with_idata" }
wayland-client = { git = "https://github.com/Drakulix/wayland-rs.git", branch = "feature/with_idata" }
wayland-sys = { git = "https://github.com/Drakulix/wayland-rs.git", branch = "feature/with_idata" }

View File

@ -137,10 +137,9 @@ fn main() {
/* /*
* Register the DrmDevice on the EventLoop * Register the DrmDevice on the EventLoop
*/ */
let device_token = event_loop.state().insert(device);
let _source = drm_device_bind( let _source = drm_device_bind(
&mut event_loop, &mut event_loop,
device_token, device,
DrmHandlerImpl { DrmHandlerImpl {
compositor_token, compositor_token,
window_map: window_map.clone(), window_map: window_map.clone(),

View File

@ -54,7 +54,8 @@ use std::rc::Rc;
use std::sync::Arc; use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use std::time::Duration; use std::time::Duration;
use wayland_server::{Display, EventLoopHandle, StateProxy, StateToken}; use wayland_server::{Display, EventLoopHandle};
use wayland_server::sources::EventSource;
use wayland_server::protocol::{wl_output, wl_pointer}; use wayland_server::protocol::{wl_output, wl_pointer};
use xkbcommon::xkb::keysyms as xkb; use xkbcommon::xkb::keysyms as xkb;
@ -270,7 +271,7 @@ fn main() {
let primary_gpu = primary_gpu(&context, &seat).unwrap_or_default(); let primary_gpu = primary_gpu(&context, &seat).unwrap_or_default();
let bytes = include_bytes!("resources/cursor2.rgba"); let bytes = include_bytes!("resources/cursor2.rgba");
let udev_token = UdevBackend::new( let mut udev_backend = UdevBackend::new(
&mut event_loop, &mut event_loop,
&context, &context,
session.clone(), session.clone(),
@ -288,7 +289,7 @@ fn main() {
log.clone(), log.clone(),
).unwrap(); ).unwrap();
let udev_session_id = notifier.register(udev_token.clone()); let udev_session_id = notifier.register(&mut udev_backend);
let (seat_token, _) = Seat::new(&mut event_loop, session.seat().into(), log.clone()); let (seat_token, _) = Seat::new(&mut event_loop, session.seat().into(), log.clone());
@ -339,7 +340,7 @@ fn main() {
*/ */
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(libinput_context.clone()); let libinput_session_id = notifier.register(&mut libinput_context);
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( libinput_backend.set_handler(
@ -359,7 +360,7 @@ fn main() {
let libinput_event_source = libinput_bind(libinput_backend, &mut event_loop).unwrap(); let libinput_event_source = libinput_bind(libinput_backend, &mut event_loop).unwrap();
let session_event_source = auto_session_bind(notifier, &mut event_loop).unwrap(); let session_event_source = auto_session_bind(notifier, &mut event_loop).unwrap();
let udev_event_source = udev_backend_bind(&mut event_loop, udev_token).unwrap(); let udev_event_source = udev_backend_bind(&mut event_loop, udev_backend).unwrap();
while running.load(Ordering::SeqCst) { while running.load(Ordering::SeqCst) {
if let Err(_) = event_loop.dispatch(Some(16)) { if let Err(_) = event_loop.dispatch(Some(16)) {
@ -378,9 +379,8 @@ fn main() {
libinput_event_source.remove(); libinput_event_source.remove();
let udev_token = udev_event_source.remove(); // destroy the udev backend freeing the drm devices
let udev = event_loop.state().remove(udev_token); udev_event_source.remove().close(&mut event_loop)
udev.close(event_loop.state());
} }
struct UdevHandlerImpl { struct UdevHandlerImpl {
@ -455,8 +455,8 @@ impl UdevHandlerImpl {
} }
impl UdevHandler<DrmHandlerImpl> for UdevHandlerImpl { impl UdevHandler<DrmHandlerImpl> for UdevHandlerImpl {
fn device_added<'a, S: Into<StateProxy<'a>>>( fn device_added(
&mut self, _state: S, device: &mut DrmDevice<SessionFdDrmDevice> &mut self, _evlh: &mut EventLoopHandle, device: &mut DrmDevice<SessionFdDrmDevice>
) -> Option<DrmHandlerImpl> { ) -> Option<DrmHandlerImpl> {
// init hardware acceleration on the primary gpu. // init hardware acceleration on the primary gpu.
if device.dev_path().and_then(|path| path.canonicalize().ok()) == self.primary_gpu { if device.dev_path().and_then(|path| path.canonicalize().ok()) == self.primary_gpu {
@ -475,21 +475,17 @@ impl UdevHandler<DrmHandlerImpl> for UdevHandlerImpl {
}) })
} }
fn device_changed<'a, S: Into<StateProxy<'a>>>( fn device_changed(
&mut self, state: S, device: &StateToken<DrmDevice<SessionFdDrmDevice>> &mut self, _evlh: &mut EventLoopHandle, device: &mut DrmDevice<SessionFdDrmDevice>
) { ) {
//quick and dirt, just re-init all backends //quick and dirt, just re-init all backends
let mut state = state.into(); let backends = self.backends.get(&device.device_id()).unwrap();
let backends = self.backends.get(&state.get(device).device_id()).unwrap(); *backends.borrow_mut() = self.scan_connectors(device);
*backends.borrow_mut() = self.scan_connectors(state.get_mut(device));
} }
fn device_removed<'a, S: Into<StateProxy<'a>>>( fn device_removed(
&mut self, state: S, device: &StateToken<DrmDevice<SessionFdDrmDevice>> &mut self, _evlh: &mut EventLoopHandle, device: &mut DrmDevice<SessionFdDrmDevice>
) { ) {
let state = state.into();
let device = state.get(device);
// drop the backends on this side // drop the backends on this side
self.backends.remove(&device.device_id()); self.backends.remove(&device.device_id());
@ -499,7 +495,7 @@ impl UdevHandler<DrmHandlerImpl> for UdevHandlerImpl {
} }
} }
fn error<'a, S: Into<StateProxy<'a>>>(&mut self, _state: S, error: IoError) { fn error(&mut self, _evlh: &mut EventLoopHandle, error: IoError) {
error!(self.logger, "{:?}", error); error!(self.logger, "{:?}", error);
} }
} }

View File

@ -52,7 +52,6 @@
//! use std::os::unix::io::RawFd; //! use std::os::unix::io::RawFd;
//! use std::os::unix::io::AsRawFd; //! use std::os::unix::io::AsRawFd;
//! use smithay::backend::drm::{DrmDevice, DrmBackend}; //! use smithay::backend::drm::{DrmDevice, DrmBackend};
//! use wayland_server::StateToken;
//! //!
//! #[derive(Debug)] //! #[derive(Debug)]
//! pub struct Card(File); //! pub struct Card(File);
@ -201,8 +200,7 @@
//! // render something (like clear_color) //! // render something (like clear_color)
//! backend.swap_buffers().unwrap(); //! backend.swap_buffers().unwrap();
//! //!
//! let device_token = event_loop.state().insert(device); //! let _source = drm_device_bind(&mut event_loop, device, MyDrmHandler(backend)).unwrap();
//! let _source = drm_device_bind(&mut event_loop, device_token, MyDrmHandler(backend)).unwrap();
//! //!
//! event_loop.run().unwrap(); //! event_loop.run().unwrap();
//! # } //! # }
@ -213,7 +211,7 @@ use backend::graphics::egl::error::Result as EGLResult;
use backend::graphics::egl::native::Gbm; use backend::graphics::egl::native::Gbm;
use backend::graphics::egl::wayland::{EGLDisplay, EGLWaylandExtensions}; use backend::graphics::egl::wayland::{EGLDisplay, EGLWaylandExtensions};
#[cfg(feature = "backend_session")] #[cfg(feature = "backend_session")]
use backend::session::SessionObserver; use backend::session::{AsSessionObserver, SessionObserver};
use drm::Device as BasicDevice; use drm::Device as BasicDevice;
use drm::control::{connector, crtc, encoder, Mode, ResourceInfo}; use drm::control::{connector, crtc, encoder, Mode, ResourceInfo};
use drm::control::Device as ControlDevice; use drm::control::Device as ControlDevice;
@ -222,17 +220,17 @@ use drm::result::Error as DrmError;
use gbm::{BufferObject, Device as GbmDevice}; use gbm::{BufferObject, Device as GbmDevice};
use nix; use nix;
use nix::sys::stat::{self, dev_t, fstat}; use nix::sys::stat::{self, dev_t, fstat};
use std::cell::RefCell;
use std::collections::HashMap; use std::collections::HashMap;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::io::Result as IoResult; use std::io::Result as IoResult;
use std::os::unix::io::{AsRawFd, RawFd}; use std::os::unix::io::{AsRawFd, RawFd};
use std::path::PathBuf; use std::path::PathBuf;
use std::rc::{Rc, Weak}; use std::rc::{Rc, Weak};
use std::sync::{Once, ONCE_INIT}; use std::sync::{Arc, Once, ONCE_INIT};
use std::sync::atomic::{AtomicBool, Ordering};
use std::time::Duration; use std::time::Duration;
use wayland_server::{Display, EventLoopHandle, StateToken}; use wayland_server::{Display, EventLoopHandle};
#[cfg(feature = "backend_session")]
use wayland_server::StateProxy;
use wayland_server::sources::{FdEventSource, FdEventSourceImpl, FdInterest}; use wayland_server::sources::{FdEventSource, FdEventSourceImpl, FdInterest};
mod backend; mod backend;
@ -249,8 +247,8 @@ pub struct DrmDevice<A: ControlDevice + 'static> {
context: Rc<EGLContext<Gbm<framebuffer::Info>, GbmDevice<A>>>, context: Rc<EGLContext<Gbm<framebuffer::Info>, GbmDevice<A>>>,
old_state: HashMap<crtc::Handle, (crtc::Info, Vec<connector::Handle>)>, old_state: HashMap<crtc::Handle, (crtc::Info, Vec<connector::Handle>)>,
device_id: dev_t, device_id: dev_t,
backends: HashMap<crtc::Handle, Weak<DrmBackendInternal<A>>>, backends: Rc<RefCell<HashMap<crtc::Handle, Weak<DrmBackendInternal<A>>>>>,
active: bool, active: Arc<AtomicBool>,
priviledged: bool, priviledged: bool,
logger: ::slog::Logger, logger: ::slog::Logger,
} }
@ -316,10 +314,10 @@ impl<A: ControlDevice + 'static> DrmDevice<A> {
Default::default(), Default::default(),
log.clone(), log.clone(),
).map_err(Error::from)?), ).map_err(Error::from)?),
backends: HashMap::new(), backends: Rc::new(RefCell::new(HashMap::new())),
device_id, device_id,
old_state: HashMap::new(), old_state: HashMap::new(),
active: true, active: Arc::new(AtomicBool::new(true)),
priviledged: true, priviledged: true,
logger: log.clone(), logger: log.clone(),
}; };
@ -382,11 +380,11 @@ impl<A: ControlDevice + 'static> DrmDevice<A> {
where where
I: Into<Vec<connector::Handle>>, I: Into<Vec<connector::Handle>>,
{ {
if self.backends.contains_key(&crtc) { if self.backends.borrow().contains_key(&crtc) {
bail!(ErrorKind::CrtcAlreadyInUse(crtc)); bail!(ErrorKind::CrtcAlreadyInUse(crtc));
} }
if !self.active { if !self.active.load(Ordering::SeqCst) {
bail!(ErrorKind::DeviceInactive); bail!(ErrorKind::DeviceInactive);
} }
@ -441,7 +439,7 @@ impl<A: ControlDevice + 'static> DrmDevice<A> {
let logger = self.logger.new(o!("crtc" => format!("{:?}", crtc))); let logger = self.logger.new(o!("crtc" => format!("{:?}", crtc)));
let backend = DrmBackend::new(self.context.clone(), crtc, mode, connectors, logger)?; let backend = DrmBackend::new(self.context.clone(), crtc, mode, connectors, logger)?;
self.backends.insert(crtc, backend.weak()); self.backends.borrow_mut().insert(crtc, backend.weak());
Ok(backend) Ok(backend)
} }
@ -543,13 +541,13 @@ pub trait DrmHandler<A: ControlDevice + 'static> {
/// ///
/// This will cause it to recieve events and feed them into an `DrmHandler` /// This will cause it to recieve events and feed them into an `DrmHandler`
pub fn drm_device_bind<A, H>( pub fn drm_device_bind<A, H>(
evlh: &mut EventLoopHandle, device: StateToken<DrmDevice<A>>, handler: H evlh: &mut EventLoopHandle, device: DrmDevice<A>, handler: H
) -> IoResult<FdEventSource<(StateToken<DrmDevice<A>>, H)>> ) -> IoResult<FdEventSource<(DrmDevice<A>, H)>>
where where
A: ControlDevice + 'static, A: ControlDevice + 'static,
H: DrmHandler<A> + 'static, H: DrmHandler<A> + 'static,
{ {
let fd = evlh.state().get(&device).as_raw_fd(); let fd = device.as_raw_fd();
evlh.add_fd_event_source( evlh.add_fd_event_source(
fd, fd,
fd_event_source_implementation(), fd_event_source_implementation(),
@ -558,26 +556,19 @@ where
) )
} }
fn fd_event_source_implementation<A, H>() -> FdEventSourceImpl<(StateToken<DrmDevice<A>>, H)> fn fd_event_source_implementation<A, H>() -> FdEventSourceImpl<(DrmDevice<A>, H)>
where where
A: ControlDevice + 'static, A: ControlDevice + 'static,
H: DrmHandler<A> + 'static, H: DrmHandler<A> + 'static,
{ {
FdEventSourceImpl { FdEventSourceImpl {
ready: |evlh, &mut (ref mut dev_token, ref mut handler), _, _| { ready: |_evlh, &mut (ref mut device, ref mut handler), _, _| {
let (events, logger) = { match crtc::receive_events(device) {
let dev = evlh.state().get(dev_token);
let events = crtc::receive_events(dev);
let logger = dev.logger.clone();
(events, logger)
};
match events {
Ok(events) => for event in events { Ok(events) => for event in events {
if let crtc::Event::PageFlip(event) = event { if let crtc::Event::PageFlip(event) = event {
let dev = evlh.state().get_mut(dev_token); if device.active.load(Ordering::SeqCst) {
if dev.active { let backends = device.backends.borrow().clone();
if let Some(backend) = dev.backends if let Some(backend) = backends
.get(&event.crtc) .get(&event.crtc)
.iter() .iter()
.flat_map(|x| x.upgrade()) .flat_map(|x| x.upgrade())
@ -585,39 +576,60 @@ where
{ {
// we can now unlock the buffer // we can now unlock the buffer
backend.unlock_buffer(); backend.unlock_buffer();
trace!(logger, "Handling event for backend {:?}", event.crtc); trace!(device.logger, "Handling event for backend {:?}", event.crtc);
// and then call the user to render the next frame // and then call the user to render the next frame
handler.ready(dev, event.crtc, event.frame, event.duration); handler.ready(device, event.crtc, event.frame, event.duration);
} else { } else {
dev.backends.remove(&event.crtc); device.backends.borrow_mut().remove(&event.crtc);
} }
} }
} }
}, },
Err(err) => handler.error(evlh.state().get_mut(dev_token), err), Err(err) => handler.error(device, err),
}; };
}, },
error: |evlh, &mut (ref mut dev_token, ref mut handler), _, error| { error: |_evlh, &mut (ref mut device, ref mut handler), _, error| {
let mut dev = evlh.state().get_mut(dev_token); warn!(device.logger, "DrmDevice errored: {}", error);
warn!(dev.logger, "DrmDevice errored: {}", error); handler.error(device, error.into());
handler.error(&mut dev, error.into());
}, },
} }
} }
/// `SessionObserver` linked to the `DrmDevice` it was created from.
pub struct DrmDeviceObserver<A: ControlDevice + 'static> {
context: Weak<EGLContext<Gbm<framebuffer::Info>, GbmDevice<A>>>,
device_id: dev_t,
backends: Rc<RefCell<HashMap<crtc::Handle, Weak<DrmBackendInternal<A>>>>>,
active: Arc<AtomicBool>,
priviledged: bool,
logger: ::slog::Logger,
}
impl<A: ControlDevice + 'static> AsSessionObserver<DrmDeviceObserver<A>> for DrmDevice<A> {
fn observer(&mut self) -> DrmDeviceObserver<A> {
DrmDeviceObserver {
context: Rc::downgrade(&self.context),
device_id: self.device_id.clone(),
backends: self.backends.clone(),
active: self.active.clone(),
priviledged: self.priviledged,
logger: self.logger.clone(),
}
}
}
#[cfg(feature = "backend_session")] #[cfg(feature = "backend_session")]
impl<A: ControlDevice + 'static> SessionObserver for StateToken<DrmDevice<A>> { impl<A: ControlDevice + 'static> SessionObserver for DrmDeviceObserver<A> {
fn pause<'a>(&mut self, state: &mut StateProxy<'a>, devnum: Option<(u32, u32)>) { fn pause(&mut self, _evlh: &mut EventLoopHandle, devnum: Option<(u32, u32)>) {
let device = state.get_mut(self);
if let Some((major, minor)) = devnum { if let Some((major, minor)) = devnum {
if major as u64 != stat::major(device.device_id) || minor as u64 != stat::minor(device.device_id) if major as u64 != stat::major(self.device_id) || minor as u64 != stat::minor(self.device_id)
{ {
return; return;
} }
} }
for (handle, &(ref info, ref connectors)) in device.old_state.iter() { for (handle, &(ref info, ref connectors)) in self.old_state.iter() {
if let Err(err) = crtc::set( if let Err(err) = crtc::set(
&*device.context, &*self.context,
*handle, *handle,
info.fb(), info.fb(),
connectors, connectors,
@ -625,51 +637,56 @@ impl<A: ControlDevice + 'static> SessionObserver for StateToken<DrmDevice<A>> {
info.mode(), info.mode(),
) { ) {
error!( error!(
device.logger, self.logger,
"Failed to reset crtc ({:?}). Error: {}", handle, err "Failed to reset crtc ({:?}). Error: {}", handle, err
); );
} }
} }
device.active = false; self.active.store(false, Ordering::SeqCst);
if device.priviledged { if self.priviledged {
if let Some(device) = self.context.upgrade() {
if let Err(err) = device.drop_master() { if let Err(err) = device.drop_master() {
error!( error!(
device.logger, self.logger,
"Failed to drop drm master state. Error: {}", err "Failed to drop drm master state. Error: {}", err
); );
} }
} }
} }
}
fn activate<'a>(&mut self, state: &mut StateProxy<'a>, devnum: Option<(u32, u32, Option<RawFd>)>) { fn activate(&mut self, _evlh: &mut EventLoopHandle, devnum: Option<(u32, u32, Option<RawFd>)>) {
let device = state.get_mut(self);
if let Some((major, minor, fd)) = devnum { if let Some((major, minor, fd)) = devnum {
if major as u64 != stat::major(device.device_id) || minor as u64 != stat::minor(device.device_id) if major as u64 != stat::major(self.device_id) || minor as u64 != stat::minor(self.device_id)
{ {
return; return;
} else if let Some(fd) = fd { } else if let Some(fd) = fd {
info!(device.logger, "Replacing fd"); info!(self.logger, "Replacing fd");
if let Some(device) = self.context.upgrade() {
nix::unistd::dup2(device.as_raw_fd(), fd) nix::unistd::dup2(device.as_raw_fd(), fd)
.expect("Failed to replace file descriptor of drm device"); .expect("Failed to replace file descriptor of drm device");
} }
} }
device.active = true; }
if device.priviledged { self.active.store(true, Ordering::SeqCst);
if self.priviledged {
if let Some(device) = self.context.upgrade() {
if let Err(err) = device.set_master() { if let Err(err) = device.set_master() {
crit!( crit!(
device.logger, self.logger,
"Failed to acquire drm master again. Error: {}", "Failed to acquire drm master again. Error: {}",
err err
); );
} }
} }
}
let mut crtcs = Vec::new(); let mut crtcs = Vec::new();
for (crtc, backend) in device.backends.iter() { for (crtc, backend) in self.backends.borrow().iter() {
if let Some(backend) = backend.upgrade() { if let Some(backend) = backend.upgrade() {
backend.unlock_buffer(); backend.unlock_buffer();
if let Err(err) = backend.page_flip(None) { if let Err(err) = backend.page_flip(None) {
error!( error!(
device.logger, self.logger,
"Failed to activate crtc ({:?}) again. Error: {}", crtc, err "Failed to activate crtc ({:?}) again. Error: {}", crtc, err
); );
} }
@ -685,7 +702,7 @@ impl<A: ControlDevice + 'static> SessionObserver for StateToken<DrmDevice<A>> {
).is_err() ).is_err()
{ {
if let Err(err) = crtc::set_cursor(&*backend.context, *crtc, cursor) { if let Err(err) = crtc::set_cursor(&*backend.context, *crtc, cursor) {
error!(device.logger, "Failed to reset cursor. Error: {}", err); error!(self.logger, "Failed to reset cursor. Error: {}", err);
} }
} }
} }
@ -694,7 +711,7 @@ impl<A: ControlDevice + 'static> SessionObserver for StateToken<DrmDevice<A>> {
} }
} }
for crtc in crtcs { for crtc in crtcs {
device.backends.remove(&crtc); self.backends.borrow_mut().remove(&crtc);
} }
} }
} }

View File

@ -11,7 +11,7 @@ use std::io::{Error as IoError, Result as IoResult};
use std::os::unix::io::RawFd; use std::os::unix::io::RawFd;
use std::path::Path; use std::path::Path;
use std::rc::Rc; use std::rc::Rc;
use wayland_server::{EventLoopHandle, StateProxy}; use wayland_server::EventLoopHandle;
use wayland_server::sources::{FdEventSource, FdEventSourceImpl, FdInterest}; use wayland_server::sources::{FdEventSource, FdEventSourceImpl, FdInterest};
// No idea if this is the same across unix platforms // No idea if this is the same across unix platforms
@ -586,7 +586,7 @@ impl From<event::pointer::ButtonState> for backend::MouseButtonState {
#[cfg(feature = "backend_session")] #[cfg(feature = "backend_session")]
impl SessionObserver for libinput::Libinput { impl SessionObserver for libinput::Libinput {
fn pause<'a>(&mut self, _state: &mut StateProxy<'a>, device: Option<(u32, u32)>) { fn pause(&mut self, _state: &mut EventLoopHandle, device: Option<(u32, u32)>) {
if let Some((major, _)) = device { if let Some((major, _)) = device {
if major != INPUT_MAJOR { if major != INPUT_MAJOR {
return; return;
@ -596,7 +596,7 @@ impl SessionObserver for libinput::Libinput {
self.suspend() self.suspend()
} }
fn activate<'a>(&mut self, _state: &mut StateProxy<'a>, _device: Option<(u32, u32, Option<RawFd>)>) { fn activate(&mut self, _state: &mut EventLoopHandle, _device: Option<(u32, u32, Option<RawFd>)>) {
// libinput closes the devices on suspend, so we should not get any INPUT_MAJOR calls // 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 // also lets hope multiple resumes are okay in case of logind
self.resume().expect("Unable to resume libinput context"); self.resume().expect("Unable to resume libinput context");

View File

@ -29,7 +29,7 @@
//! automatically by the `UdevBackend`, if not done manually). //! automatically by the `UdevBackend`, if not done manually).
//! ``` //! ```
use super::{AsErrno, Session, SessionNotifier, SessionObserver}; use super::{AsErrno, Session, SessionNotifier, SessionObserver, AsSessionObserver};
use super::direct::{self, direct_session_bind, DirectSession, DirectSessionNotifier}; use super::direct::{self, direct_session_bind, DirectSession, DirectSessionNotifier};
#[cfg(feature = "backend_session_logind")] #[cfg(feature = "backend_session_logind")]
use super::logind::{self, logind_session_bind, BoundLogindSession, LogindSession, LogindSessionNotifier}; use super::logind::{self, logind_session_bind, BoundLogindSession, LogindSession, LogindSessionNotifier};
@ -40,7 +40,7 @@ use std::os::unix::io::RawFd;
use std::path::Path; use std::path::Path;
use std::rc::Rc; use std::rc::Rc;
use wayland_server::EventLoopHandle; use wayland_server::EventLoopHandle;
use wayland_server::sources::SignalEventSource; use wayland_server::sources::{EventSource, SignalEventSource};
/// `Session` using the best available inteface /// `Session` using the best available inteface
#[derive(Clone)] #[derive(Clone)]
@ -207,7 +207,9 @@ impl Session for AutoSession {
impl SessionNotifier for AutoSessionNotifier { impl SessionNotifier for AutoSessionNotifier {
type Id = AutoId; type Id = AutoId;
fn register<S: SessionObserver + 'static>(&mut self, signal: S) -> Self::Id { fn register<S: SessionObserver + 'static, A: AsSessionObserver<S>>(&mut self, signal: &mut A)
-> Self::Id
{
match self { match self {
#[cfg(feature = "backend_session_logind")] #[cfg(feature = "backend_session_logind")]
&mut AutoSessionNotifier::Logind(ref mut logind) => { &mut AutoSessionNotifier::Logind(ref mut logind) => {

View File

@ -30,7 +30,7 @@
//! automatically by the `UdevBackend`, if not done manually). //! automatically by the `UdevBackend`, if not done manually).
//! ``` //! ```
use backend::session::{AsErrno, Session, SessionNotifier, SessionObserver}; use backend::session::{AsErrno, Session, SessionNotifier, SessionObserver, AsSessionObserver};
use dbus::{BusName, BusType, Connection, ConnectionItem, ConnectionItems, Interface, Member, Message, use dbus::{BusName, BusType, Connection, ConnectionItem, ConnectionItems, Interface, Member, Message,
MessageItem, OwnedFd, Path as DbusPath, Watch, WatchEvent}; MessageItem, OwnedFd, Path as DbusPath, Watch, WatchEvent};
use nix::fcntl::OFlag; use nix::fcntl::OFlag;
@ -43,7 +43,7 @@ use std::rc::{Rc, Weak};
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use systemd::login; use systemd::login;
use wayland_server::EventLoopHandle; use wayland_server::EventLoopHandle;
use wayland_server::sources::{FdEventSource, FdEventSourceImpl, FdInterest}; use wayland_server::sources::{EventSource, FdEventSource, FdEventSourceImpl, FdInterest};
struct LogindSessionImpl { struct LogindSessionImpl {
conn: RefCell<Connection>, conn: RefCell<Connection>,
@ -246,7 +246,7 @@ impl LogindSessionImpl {
//So lets just put it to sleep.. forever //So lets just put it to sleep.. forever
for signal in &mut *self.signals.borrow_mut() { for signal in &mut *self.signals.borrow_mut() {
if let &mut Some(ref mut signal) = signal { if let &mut Some(ref mut signal) = signal {
signal.pause(&mut evlh.state().as_proxy(), None); signal.pause(evlh, None);
} }
} }
self.active.store(false, Ordering::SeqCst); self.active.store(false, Ordering::SeqCst);
@ -263,7 +263,7 @@ impl LogindSessionImpl {
); );
for signal in &mut *self.signals.borrow_mut() { for signal in &mut *self.signals.borrow_mut() {
if let &mut Some(ref mut signal) = signal { if let &mut Some(ref mut signal) = signal {
signal.pause(&mut evlh.state().as_proxy(), Some((major, minor))); signal.pause(evlh, Some((major, minor)));
} }
} }
// the other possible types are "force" or "gone" (unplugged), // the other possible types are "force" or "gone" (unplugged),
@ -289,7 +289,7 @@ impl LogindSessionImpl {
debug!(self.logger, "Reactivating device ({},{})", major, minor); debug!(self.logger, "Reactivating device ({},{})", major, minor);
for signal in &mut *self.signals.borrow_mut() { for signal in &mut *self.signals.borrow_mut() {
if let &mut Some(ref mut signal) = signal { if let &mut Some(ref mut signal) = signal {
signal.activate(&mut evlh.state().as_proxy(), Some((major, minor, Some(fd)))); signal.activate(evlh, Some((major, minor, Some(fd))));
} }
} }
} }
@ -392,11 +392,13 @@ pub struct Id(usize);
impl SessionNotifier for LogindSessionNotifier { impl SessionNotifier for LogindSessionNotifier {
type Id = Id; type Id = Id;
fn register<S: SessionObserver + 'static>(&mut self, signal: S) -> Id { fn register<S: SessionObserver + 'static, A: AsSessionObserver<S>>(&mut self, signal: &mut A)
-> Self::Id
{
self.internal self.internal
.signals .signals
.borrow_mut() .borrow_mut()
.push(Some(Box::new(signal))); .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) {

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, Session, SessionNotifier, SessionObserver}; use super::{AsErrno, Session, SessionNotifier, SessionObserver, AsSessionObserver};
use nix::{Error as NixError, Result as NixResult}; use nix::{Error as NixError, Result as NixResult};
use nix::fcntl::{self, open, OFlag}; use nix::fcntl::{self, open, OFlag};
use nix::libc::c_int; use nix::libc::c_int;
@ -344,8 +344,10 @@ pub struct Id(usize);
impl SessionNotifier for DirectSessionNotifier { impl SessionNotifier for DirectSessionNotifier {
type Id = Id; type Id = Id;
fn register<S: SessionObserver + 'static>(&mut self, signal: S) -> Id { fn register<S: SessionObserver + 'static, A: AsSessionObserver<S>>(&mut self, signal: &mut A)
self.signals.push(Some(Box::new(signal))); -> 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) {
@ -376,7 +378,7 @@ pub fn direct_session_bind(
info!(notifier.logger, "Session shall become inactive"); info!(notifier.logger, "Session shall become inactive");
for signal in &mut notifier.signals { for signal in &mut notifier.signals {
if let &mut Some(ref mut signal) = signal { if let &mut Some(ref mut signal) = signal {
signal.pause(&mut evlh.state().as_proxy(), None); signal.pause(evlh, None);
} }
} }
notifier.active.store(false, Ordering::SeqCst); notifier.active.store(false, Ordering::SeqCst);
@ -391,7 +393,7 @@ pub fn direct_session_bind(
} }
for signal in &mut notifier.signals { for signal in &mut notifier.signals {
if let &mut Some(ref mut signal) = signal { if let &mut Some(ref mut signal) = signal {
signal.activate(&mut evlh.state().as_proxy(), None); signal.activate(evlh, None);
} }
} }
notifier.active.store(true, Ordering::SeqCst); notifier.active.store(true, Ordering::SeqCst);

View File

@ -16,7 +16,7 @@ use std::os::unix::io::RawFd;
use std::path::Path; use std::path::Path;
use std::rc::Rc; use std::rc::Rc;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use wayland_server::StateProxy; use wayland_server::EventLoopHandle;
/// General session interface. /// General session interface.
/// ///
@ -53,7 +53,7 @@ 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>(&mut self, signal: S) -> Self::Id; fn register<S: SessionObserver + 'static, A: AsSessionObserver<S>>(&mut self, signal: &mut A) -> 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);
@ -63,6 +63,20 @@ pub trait SessionNotifier {
fn seat(&self) -> &str; fn seat(&self) -> &str;
} }
/// Trait describing the ability to return a `SessionObserver` related to Self.
///
/// The returned `SessionObserver` is responsible to handle the `pause` and `activate` signals.
pub trait AsSessionObserver<S: SessionObserver + 'static> {
/// Create a `SessionObserver` linked to this object
fn observer(&mut self) -> S;
}
impl<T: SessionObserver + Clone + 'static> AsSessionObserver<T> for T {
fn observer(&mut self) -> T {
self.clone()
}
}
/// Trait describing the ability to be notified when the session pauses or becomes active again. /// 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. /// It might be impossible to interact with devices while the session is disabled.
@ -70,24 +84,18 @@ pub trait SessionNotifier {
pub trait SessionObserver { pub trait SessionObserver {
/// Session/Device is about to be paused. /// Session/Device is about to be paused.
/// ///
/// In case the implementor is a `StateToken` the state of the `EventLoop`
/// is provided via a `StateProxy`.
///
/// If only a specific device shall be closed a device number in the form of /// If only a specific device shall be closed a device number in the form of
/// (major, minor) is provided. All observers not using the specified device should /// (major, minor) is provided. All observers not using the specified device should
/// ignore the signal in that case. /// ignore the signal in that case.
fn pause<'a>(&mut self, state: &mut StateProxy<'a>, device: Option<(u32, u32)>); fn pause(&mut self, evlh: &mut EventLoopHandle, device: Option<(u32, u32)>);
/// Session/Device got active again /// Session/Device got active again
/// ///
/// In case the implementor is a `StateToken` the state of the `EventLoop`
/// is provided via a `StateProxy`.
///
/// If only a specific device shall be activated again a device number in the form of /// 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 /// (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 /// 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 /// should not be used anymore and be closed. All observers not using the specified device should
/// ignore the signal in that case. /// ignore the signal in that case.
fn activate<'a>(&mut self, state: &mut StateProxy<'a>, device: Option<(u32, u32, Option<RawFd>)>); fn activate(&mut self, evlh: &mut EventLoopHandle, device: Option<(u32, u32, Option<RawFd>)>);
} }
impl Session for () { impl Session for () {

View File

@ -10,20 +10,22 @@
//! backend. //! backend.
use backend::drm::{drm_device_bind, DrmDevice, DrmHandler}; use backend::drm::{drm_device_bind, DrmDevice, DrmHandler};
use backend::session::{Session, SessionObserver}; use backend::session::{Session, SessionObserver, AsSessionObserver};
use drm::Device as BasicDevice; use drm::Device as BasicDevice;
use drm::control::Device as ControlDevice; use drm::control::Device as ControlDevice;
use nix::fcntl; use nix::fcntl;
use nix::sys::stat::dev_t; use nix::sys::stat::dev_t;
use std::cell::RefCell;
use std::collections::HashMap; use std::collections::HashMap;
use std::ffi::OsString; use std::ffi::OsString;
use std::io::{Error as IoError, Result as IoResult}; use std::io::{Error as IoError, Result as IoResult};
use std::mem::drop; use std::mem::drop;
use std::os::unix::io::{AsRawFd, RawFd}; use std::os::unix::io::{AsRawFd, RawFd};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::rc::{Rc, Weak};
use udev::{Context, Enumerator, Event, EventType, MonitorBuilder, MonitorSocket, Result as UdevResult}; use udev::{Context, Enumerator, Event, EventType, MonitorBuilder, MonitorSocket, Result as UdevResult};
use wayland_server::{EventLoopHandle, StateProxy, StateToken}; use wayland_server::EventLoopHandle;
use wayland_server::sources::{FdEventSource, FdEventSourceImpl, FdInterest}; use wayland_server::sources::{EventSource, FdEventSource, FdEventSourceImpl, FdInterest};
/// Udev's `DrmDevice` type based on the underlying session /// Udev's `DrmDevice` type based on the underlying session
pub struct SessionFdDrmDevice(RawFd); pub struct SessionFdDrmDevice(RawFd);
@ -46,13 +48,7 @@ pub struct UdevBackend<
S: Session + 'static, S: Session + 'static,
T: UdevHandler<H> + 'static, T: UdevHandler<H> + 'static,
> { > {
devices: HashMap< devices: Rc<RefCell<HashMap<dev_t, FdEventSource<(DrmDevice<SessionFdDrmDevice>, H)>>>>,
dev_t,
(
StateToken<DrmDevice<SessionFdDrmDevice>>,
FdEventSource<(StateToken<DrmDevice<SessionFdDrmDevice>>, H)>,
),
>,
monitor: MonitorSocket, monitor: MonitorSocket,
session: S, session: S,
handler: T, handler: T,
@ -72,7 +68,7 @@ impl<H: DrmHandler<SessionFdDrmDevice> + 'static, S: Session + 'static, T: UdevH
/// `logger` - slog Logger to be used by the backend and its `DrmDevices`. /// `logger` - slog Logger to be used by the backend and its `DrmDevices`.
pub fn new<'a, L>( pub fn new<'a, L>(
mut evlh: &mut EventLoopHandle, context: &Context, mut session: S, mut handler: T, logger: L mut evlh: &mut EventLoopHandle, context: &Context, mut session: S, mut handler: T, logger: L
) -> Result<StateToken<UdevBackend<H, S, T>>> ) -> Result<UdevBackend<H, S, T>>
where where
L: Into<Option<::slog::Logger>>, L: Into<Option<::slog::Logger>>,
{ {
@ -98,15 +94,14 @@ impl<H: DrmHandler<SessionFdDrmDevice> + 'static, S: Session + 'static, T: UdevH
Ok(mut device) => { Ok(mut device) => {
let fd = device.as_raw_fd(); let fd = device.as_raw_fd();
let devnum = device.device_id(); let devnum = device.device_id();
match handler.device_added(&mut evlh.state().as_proxy(), &mut device) { match handler.device_added(evlh, &mut device) {
Some(drm_handler) => { Some(drm_handler) => {
let token = evlh.state().insert(device); if let Ok(event_source) = drm_device_bind(&mut evlh, device, drm_handler) {
if let Ok(event_source) = drm_device_bind(&mut evlh, token.clone(), drm_handler) { Some((devnum, event_source))
Some((devnum, (token, event_source)))
} else { } else {
handler.device_removed(evlh.state(), &token); //TODO fix wayland_server to return idata on error
let device = evlh.state().remove(token); // handler.device_removed(evlh, &mut device);
drop(device); // drop(device);
if let Err(err) = session.close(fd) { if let Err(err) = session.close(fd) {
warn!(logger, "Failed to close dropped device. Error: {:?}. Ignoring", err); warn!(logger, "Failed to close dropped device. Error: {:?}. Ignoring", err);
}; };
@ -128,7 +123,7 @@ impl<H: DrmHandler<SessionFdDrmDevice> + 'static, S: Session + 'static, T: UdevH
} }
} }
}) })
.collect::<HashMap<dev_t, (StateToken<DrmDevice<SessionFdDrmDevice>>, FdEventSource<(StateToken<DrmDevice<SessionFdDrmDevice>>, H)>)>>(); .collect::<HashMap<dev_t, FdEventSource<(DrmDevice<SessionFdDrmDevice>, H)>>>();
let mut builder = MonitorBuilder::new(context).chain_err(|| ErrorKind::FailedToInitMonitor)?; let mut builder = MonitorBuilder::new(context).chain_err(|| ErrorKind::FailedToInitMonitor)?;
builder builder
@ -138,29 +133,21 @@ impl<H: DrmHandler<SessionFdDrmDevice> + 'static, S: Session + 'static, T: UdevH
.listen() .listen()
.chain_err(|| ErrorKind::FailedToInitMonitor)?; .chain_err(|| ErrorKind::FailedToInitMonitor)?;
Ok(evlh.state().insert(UdevBackend { Ok(UdevBackend {
devices, devices: Rc::new(RefCell::new(devices)),
monitor, monitor,
session, session,
handler, handler,
logger, logger,
})) })
} }
/// Closes the udev backend and frees all remaining open devices. /// Closes the udev backend and frees all remaining open devices.
/// pub fn close(&mut self, evlh: &mut EventLoopHandle) {
/// Needs to be called after the `FdEventSource` was removed and the backend was removed from let mut devices = self.devices.borrow_mut();
/// the `EventLoop`'s `State`. for (_, event_source) in devices.drain() {
/// let (mut device, _) = event_source.remove();
/// ## Panics self.handler.device_removed(evlh, &mut device);
/// The given state might be passed to the registered `UdevHandler::device_removed` callback.
/// Make sure not to borrow any tokens twice.
pub fn close<'a, ST: Into<StateProxy<'a>>>(mut self, state: ST) {
let mut state = state.into();
for (_, (device, event_source)) in self.devices.drain() {
event_source.remove();
self.handler.device_removed(&mut state, &device);
let device = state.remove(device);
let fd = device.as_raw_fd(); let fd = device.as_raw_fd();
drop(device); drop(device);
if let Err(err) = self.session.close(fd) { if let Err(err) = self.session.close(fd) {
@ -174,26 +161,47 @@ impl<H: DrmHandler<SessionFdDrmDevice> + 'static, S: Session + 'static, T: UdevH
} }
} }
/// `SessionObserver` linked to the `UdevBackend` it was created from.
pub struct UdevBackendObserver<H: DrmHandler<SessionFdDrmDevice> + 'static> {
devices: Weak<RefCell<HashMap<dev_t, FdEventSource<(DrmDevice<SessionFdDrmDevice>, H)>>>>,
logger: ::slog::Logger,
}
impl< impl<
H: DrmHandler<SessionFdDrmDevice> + 'static, H: DrmHandler<SessionFdDrmDevice> + 'static,
S: Session + 'static, S: Session + 'static,
T: UdevHandler<H> + 'static, T: UdevHandler<H> + 'static,
> SessionObserver for StateToken<UdevBackend<H, S, T>> > AsSessionObserver<UdevBackendObserver<H>> for UdevBackend<H, S, T> {
{ fn observer(&mut self) -> UdevBackendObserver<H> {
fn pause<'a>(&mut self, state: &mut StateProxy<'a>, devnum: Option<(u32, u32)>) { UdevBackendObserver {
state.with_value(self, |state, udev| { devices: Rc::downgrade(&self.devices),
for &mut (ref mut device, _) in udev.devices.values_mut() { logger: self.logger.clone(),
device.pause(state, devnum); }
} }
});
} }
fn activate<'a>(&mut self, state: &mut StateProxy<'a>, devnum: Option<(u32, u32, Option<RawFd>)>) { impl<H: DrmHandler<SessionFdDrmDevice> + 'static> SessionObserver for UdevBackendObserver<H>
state.with_value(self, |state, udev| { {
for &mut (ref mut device, _) in udev.devices.values_mut() { fn pause<'a>(&mut self, evlh: &mut EventLoopHandle, devnum: Option<(u32, u32)>) {
device.activate(state, devnum); if let Some(devices) = self.devices.upgrade() {
for fd_event_source in devices.borrow_mut().values_mut() {
fd_event_source.with_idata(evlh, |&mut (ref mut device, _), evlh| {
info!(self.logger, "changed successful");
device.observer().pause(evlh, devnum);
})
}
}
}
fn activate<'a>(&mut self, evlh: &mut EventLoopHandle, devnum: Option<(u32, u32, Option<RawFd>)>) {
if let Some(devices) = self.devices.upgrade() {
for fd_event_source in devices.borrow_mut().values_mut() {
fd_event_source.with_idata(evlh, |&mut (ref mut device, _), evlh| {
info!(self.logger, "changed successful");
device.observer().activate(evlh, devnum);
})
}
} }
});
} }
} }
@ -202,41 +210,37 @@ impl<
/// Allows the backend to recieve kernel events and thus to drive the `UdevHandler`. /// Allows the backend to recieve kernel events and thus to drive the `UdevHandler`.
/// No runtime functionality can be provided without using this function. /// No runtime functionality can be provided without using this function.
pub fn udev_backend_bind<S, H, T>( pub fn udev_backend_bind<S, H, T>(
evlh: &mut EventLoopHandle, udev: StateToken<UdevBackend<H, S, T>> evlh: &mut EventLoopHandle, udev: UdevBackend<H, S, T>
) -> IoResult<FdEventSource<StateToken<UdevBackend<H, S, T>>>> ) -> IoResult<FdEventSource<UdevBackend<H, S, T>>>
where where
H: DrmHandler<SessionFdDrmDevice> + 'static, H: DrmHandler<SessionFdDrmDevice> + 'static,
T: UdevHandler<H> + 'static, T: UdevHandler<H> + 'static,
S: Session + 'static, S: Session + 'static,
{ {
let fd = evlh.state().get(&udev).monitor.as_raw_fd(); let fd = udev.monitor.as_raw_fd();
evlh.add_fd_event_source(fd, fd_event_source_implementation(), udev, FdInterest::READ) evlh.add_fd_event_source(fd, fd_event_source_implementation(), udev, FdInterest::READ)
} }
fn fd_event_source_implementation<S, H, T>() -> FdEventSourceImpl<StateToken<UdevBackend<H, S, T>>> fn fd_event_source_implementation<S, H, T>() -> FdEventSourceImpl<UdevBackend<H, S, T>>
where where
H: DrmHandler<SessionFdDrmDevice> + 'static, H: DrmHandler<SessionFdDrmDevice> + 'static,
T: UdevHandler<H> + 'static, T: UdevHandler<H> + 'static,
S: Session + 'static, S: Session + 'static,
{ {
FdEventSourceImpl { FdEventSourceImpl {
ready: |mut evlh, token, _, _| { ready: |mut evlh, udev, _, _| {
let events = evlh.state() let events = udev.monitor.clone().collect::<Vec<Event>>();
.get(token)
.monitor
.clone()
.collect::<Vec<Event>>();
for event in events { for event in events {
match event.event_type() { match event.event_type() {
// New device // New device
EventType::Add => { EventType::Add => {
info!(evlh.state().get(token).logger, "Device Added"); info!(udev.logger, "Device Added");
if let (Some(path), Some(devnum)) = (event.devnode(), event.devnum()) { if let (Some(path), Some(devnum)) = (event.devnode(), event.devnum()) {
let mut device = { let mut device = {
match DrmDevice::new( match DrmDevice::new(
{ {
let logger = evlh.state().get(token).logger.clone(); let logger = udev.logger.clone();
match evlh.state().get_mut(token).session.open( match udev.session.open(
path, path,
fcntl::O_RDWR | fcntl::O_CLOEXEC | fcntl::O_NOCTTY fcntl::O_RDWR | fcntl::O_CLOEXEC | fcntl::O_NOCTTY
| fcntl::O_NONBLOCK, | fcntl::O_NONBLOCK,
@ -253,12 +257,12 @@ where
} }
} }
}, },
evlh.state().get(token).logger.clone(), udev.logger.clone(),
) { ) {
Ok(dev) => dev, Ok(dev) => dev,
Err(err) => { Err(err) => {
warn!( warn!(
evlh.state().get(token).logger, udev.logger,
"Failed to initialize device {:?}. Error: {}. Skipping", "Failed to initialize device {:?}. Error: {}. Skipping",
path, path,
err err
@ -268,24 +272,16 @@ where
} }
}; };
let fd = device.as_raw_fd(); let fd = device.as_raw_fd();
match evlh.state().with_value(token, |state, udev| { match udev.handler.device_added(evlh, &mut device) {
udev.handler.device_added(state, &mut device)
}) {
Some(drm_handler) => { Some(drm_handler) => {
let dev_token = evlh.state().insert(device);
if let Ok(fd_event_source) = if let Ok(fd_event_source) =
drm_device_bind(&mut evlh, dev_token.clone(), drm_handler) drm_device_bind(&mut evlh, device, drm_handler)
{ {
evlh.state() udev.devices.borrow_mut().insert(devnum, fd_event_source);
.get_mut(token)
.devices
.insert(devnum, (dev_token, fd_event_source));
} else { } else {
evlh.state().with_value(token, |state, udev| { //TODO fix wayland_server to return idata on error
let mut state: StateProxy = state.into(); //udev.handler.device_removed(evlh, &mut device);
udev.handler.device_removed(&mut state, &dev_token); //drop(device);
let device = state.remove(dev_token);
drop(device);
if let Err(err) = udev.session.close(fd) { if let Err(err) = udev.session.close(fd) {
warn!( warn!(
udev.logger, udev.logger,
@ -293,32 +289,27 @@ where
err err
); );
}; };
})
} }
} }
None => { None => {
drop(device); drop(device);
evlh.state().with_value(token, |_state, udev| {
if let Err(err) = udev.session.close(fd) { if let Err(err) = udev.session.close(fd) {
warn!( warn!(
udev.logger, udev.logger,
"Failed to close unused device. Error: {:?}", err "Failed to close unused device. Error: {:?}", err
); );
} }
})
} }
}; };
} }
} }
// Device removed // Device removed
EventType::Remove => evlh.state().with_value(token, |state, udev| { EventType::Remove => {
info!(udev.logger, "Device Remove"); info!(udev.logger, "Device Remove");
if let Some(devnum) = event.devnum() { if let Some(devnum) = event.devnum() {
if let Some((device, fd_event_source)) = udev.devices.remove(&devnum) { if let Some(fd_event_source) = udev.devices.borrow_mut().remove(&devnum) {
fd_event_source.remove(); let (mut device, _) = fd_event_source.remove();
let mut state: StateProxy = state.into(); udev.handler.device_removed(evlh, &mut device);
udev.handler.device_removed(&mut state, &device);
let device = state.remove(device);
let fd = device.as_raw_fd(); let fd = device.as_raw_fd();
drop(device); drop(device);
if let Err(err) = udev.session.close(fd) { if let Err(err) = udev.session.close(fd) {
@ -331,29 +322,32 @@ where
}; };
} }
} }
}), },
// New connector // New connector
EventType::Change => evlh.state().with_value(token, |state, udev| { EventType::Change => {
info!(udev.logger, "Device Changed"); info!(udev.logger, "Device Changed");
if let Some(devnum) = event.devnum() { if let Some(devnum) = event.devnum() {
info!(udev.logger, "Devnum: {:b}", devnum); info!(udev.logger, "Devnum: {:b}", devnum);
if let Some(&(ref device, _)) = udev.devices.get(&devnum) { if let Some(fd_event_source) = udev.devices.borrow_mut().get_mut(&devnum) {
info!(udev.logger, "changed successful"); let handler = &mut udev.handler;
udev.handler.device_changed(state, device); let logger = &udev.logger;
fd_event_source.with_idata(evlh, move |&mut (ref mut device, _), evlh| {
info!(logger, "changed successful");
handler.device_changed(evlh, device);
})
} else { } else {
info!(udev.logger, "changed, but device not tracked by backend"); info!(udev.logger, "changed, but device not tracked by backend");
} };
} else { } else {
info!(udev.logger, "changed, but no devnum"); info!(udev.logger, "changed, but no devnum");
} }
}), },
_ => {} _ => {}
} }
} }
}, },
error: |evlh, token, _, err| { error: |evlh, udev, _, err| {
evlh.state() udev.handler.error(evlh, err)
.with_value(token, |state, udev| udev.handler.error(state, err))
}, },
} }
} }
@ -366,8 +360,8 @@ pub trait UdevHandler<H: DrmHandler<SessionFdDrmDevice> + 'static> {
/// ///
/// ## Panics /// ## Panics
/// Panics if you try to borrow the token of the belonging `UdevBackend` using this `StateProxy`. /// Panics if you try to borrow the token of the belonging `UdevBackend` using this `StateProxy`.
fn device_added<'a, S: Into<StateProxy<'a>>>( fn device_added(
&mut self, state: S, device: &mut DrmDevice<SessionFdDrmDevice> &mut self, evlh: &mut EventLoopHandle, device: &mut DrmDevice<SessionFdDrmDevice>
) -> Option<H>; ) -> Option<H>;
/// Called when an open device is changed. /// Called when an open device is changed.
/// ///
@ -376,8 +370,8 @@ pub trait UdevHandler<H: DrmHandler<SessionFdDrmDevice> + 'static> {
/// ///
/// ## Panics /// ## Panics
/// Panics if you try to borrow the token of the belonging `UdevBackend` using this `StateProxy`. /// Panics if you try to borrow the token of the belonging `UdevBackend` using this `StateProxy`.
fn device_changed<'a, S: Into<StateProxy<'a>>>( fn device_changed(
&mut self, state: S, device: &StateToken<DrmDevice<SessionFdDrmDevice>> &mut self, evlh: &mut EventLoopHandle, device: &mut DrmDevice<SessionFdDrmDevice>
); );
/// Called when a device was removed. /// Called when a device was removed.
/// ///
@ -386,14 +380,14 @@ pub trait UdevHandler<H: DrmHandler<SessionFdDrmDevice> + 'static> {
/// ///
/// ## Panics /// ## Panics
/// Panics if you try to borrow the token of the belonging `UdevBackend` using this `StateProxy`. /// Panics if you try to borrow the token of the belonging `UdevBackend` using this `StateProxy`.
fn device_removed<'a, S: Into<StateProxy<'a>>>( fn device_removed(
&mut self, state: S, device: &StateToken<DrmDevice<SessionFdDrmDevice>> &mut self, evlh: &mut EventLoopHandle, device: &mut DrmDevice<SessionFdDrmDevice>
); );
/// Called when the udev context has encountered and error. /// Called when the udev context has encountered and error.
/// ///
/// ## Panics /// ## Panics
/// Panics if you try to borrow the token of the belonging `UdevBackend` using this `StateProxy`. /// Panics if you try to borrow the token of the belonging `UdevBackend` using this `StateProxy`.
fn error<'a, S: Into<StateProxy<'a>>>(&mut self, state: S, error: IoError); fn error(&mut self, evlh: &mut EventLoopHandle, error: IoError);
} }
/// Returns the path of the primary gpu device if any /// Returns the path of the primary gpu device if any