Merge pull request #64 from Smithay/feature/udev_handler_evlh
Introduce SessionObserver
This commit is contained in:
commit
6c1d310a23
|
@ -7,8 +7,8 @@ description = "Smithay is a library for writing wayland compositors."
|
||||||
repository = "https://github.com/Smithay/smithay"
|
repository = "https://github.com/Smithay/smithay"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wayland-server = "0.12.5"
|
wayland-server = "0.14.0"
|
||||||
wayland-sys = "0.12.5"
|
wayland-sys = "0.14.0"
|
||||||
nix = "0.9.0"
|
nix = "0.9.0"
|
||||||
xkbcommon = "0.2.1"
|
xkbcommon = "0.2.1"
|
||||||
tempfile = "2.1.5"
|
tempfile = "2.1.5"
|
||||||
|
@ -24,7 +24,7 @@ input = { version = "0.4.0", optional = true }
|
||||||
udev = { version = "0.2.0", optional = true }
|
udev = { version = "0.2.0", optional = true }
|
||||||
dbus = { version = "0.6.1", optional = true }
|
dbus = { version = "0.6.1", optional = true }
|
||||||
systemd = { version = "^0.2.0", optional = true }
|
systemd = { version = "^0.2.0", optional = true }
|
||||||
wayland-protocols = { version = "0.12.5", features = ["unstable_protocols", "server"] }
|
wayland-protocols = { version = "0.14.0", features = ["unstable_protocols", "server"] }
|
||||||
image = "0.17.0"
|
image = "0.17.0"
|
||||||
error-chain = "0.11.0"
|
error-chain = "0.11.0"
|
||||||
lazy_static = "1.0.0"
|
lazy_static = "1.0.0"
|
||||||
|
|
|
@ -34,6 +34,7 @@ use std::os::unix::io::AsRawFd;
|
||||||
use std::os::unix::io::RawFd;
|
use std::os::unix::io::RawFd;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
use wayland_server::EventLoopHandle;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Card(File);
|
pub struct Card(File);
|
||||||
|
@ -137,17 +138,17 @@ 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(),
|
||||||
drawer: renderer,
|
drawer: renderer,
|
||||||
logger: log,
|
logger: log,
|
||||||
},
|
},
|
||||||
).unwrap();
|
).map_err(|(err, _)| err)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
event_loop.dispatch(Some(16)).unwrap();
|
event_loop.dispatch(Some(16)).unwrap();
|
||||||
|
@ -166,7 +167,8 @@ pub struct DrmHandlerImpl {
|
||||||
|
|
||||||
impl DrmHandler<Card> for DrmHandlerImpl {
|
impl DrmHandler<Card> for DrmHandlerImpl {
|
||||||
fn ready(
|
fn ready(
|
||||||
&mut self, _device: &mut DrmDevice<Card>, _crtc: crtc::Handle, _frame: u32, _duration: Duration
|
&mut self, _evlh: &mut EventLoopHandle, _device: &mut DrmDevice<Card>, _crtc: crtc::Handle,
|
||||||
|
_frame: u32, _duration: Duration,
|
||||||
) {
|
) {
|
||||||
let mut frame = self.drawer.draw();
|
let mut frame = self.drawer.draw();
|
||||||
frame.clear_color(0.8, 0.8, 0.9, 1.0);
|
frame.clear_color(0.8, 0.8, 0.9, 1.0);
|
||||||
|
@ -246,7 +248,7 @@ impl DrmHandler<Card> for DrmHandlerImpl {
|
||||||
frame.finish().unwrap();
|
frame.finish().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn error(&mut self, _device: &mut DrmDevice<Card>, error: DrmError) {
|
fn error(&mut self, _evlh: &mut EventLoopHandle, _device: &mut DrmDevice<Card>, error: DrmError) {
|
||||||
panic!("{:?}", error);
|
panic!("{:?}", error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,8 +54,9 @@ 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::protocol::{wl_output, wl_pointer};
|
use wayland_server::protocol::{wl_output, wl_pointer};
|
||||||
|
use wayland_server::sources::EventSource;
|
||||||
use xkbcommon::xkb::keysyms as xkb;
|
use xkbcommon::xkb::keysyms as xkb;
|
||||||
|
|
||||||
struct LibinputInputHandler {
|
struct LibinputInputHandler {
|
||||||
|
@ -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(
|
||||||
|
@ -356,10 +357,16 @@ fn main() {
|
||||||
running: running.clone(),
|
running: running.clone(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
let libinput_event_source = libinput_bind(libinput_backend, &mut event_loop).unwrap();
|
let libinput_event_source = libinput_bind(libinput_backend, &mut event_loop)
|
||||||
|
.map_err(|(err, _)| err)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let session_event_source = auto_session_bind(notifier, &mut event_loop).unwrap();
|
let session_event_source = auto_session_bind(notifier, &mut event_loop)
|
||||||
let udev_event_source = udev_backend_bind(&mut event_loop, udev_token).unwrap();
|
.map_err(|(err, _)| err)
|
||||||
|
.unwrap();
|
||||||
|
let udev_event_source = udev_backend_bind(&mut event_loop, udev_backend)
|
||||||
|
.map_err(|(err, _)| err)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
while running.load(Ordering::SeqCst) {
|
while running.load(Ordering::SeqCst) {
|
||||||
if let Err(_) = event_loop.dispatch(Some(16)) {
|
if let Err(_) = event_loop.dispatch(Some(16)) {
|
||||||
|
@ -378,9 +385,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 +461,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 +481,13 @@ impl UdevHandler<DrmHandlerImpl> for UdevHandlerImpl {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn device_changed<'a, S: Into<StateProxy<'a>>>(
|
fn device_changed(&mut self, _evlh: &mut EventLoopHandle, device: &mut DrmDevice<SessionFdDrmDevice>) {
|
||||||
&mut self, state: S, device: &StateToken<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, _evlh: &mut EventLoopHandle, device: &mut DrmDevice<SessionFdDrmDevice>) {
|
||||||
&mut self, state: S, device: &StateToken<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 +497,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -514,8 +512,8 @@ pub struct DrmHandlerImpl {
|
||||||
|
|
||||||
impl DrmHandler<SessionFdDrmDevice> for DrmHandlerImpl {
|
impl DrmHandler<SessionFdDrmDevice> for DrmHandlerImpl {
|
||||||
fn ready(
|
fn ready(
|
||||||
&mut self, _device: &mut DrmDevice<SessionFdDrmDevice>, crtc: crtc::Handle, _frame: u32,
|
&mut self, _evlh: &mut EventLoopHandle, _device: &mut DrmDevice<SessionFdDrmDevice>,
|
||||||
_duration: Duration,
|
crtc: crtc::Handle, _frame: u32, _duration: Duration,
|
||||||
) {
|
) {
|
||||||
if let Some(drawer) = self.backends.borrow().get(&crtc) {
|
if let Some(drawer) = self.backends.borrow().get(&crtc) {
|
||||||
{
|
{
|
||||||
|
@ -605,7 +603,9 @@ impl DrmHandler<SessionFdDrmDevice> for DrmHandlerImpl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn error(&mut self, _device: &mut DrmDevice<SessionFdDrmDevice>, error: DrmError) {
|
fn error(
|
||||||
|
&mut self, _evlh: &mut EventLoopHandle, _device: &mut DrmDevice<SessionFdDrmDevice>, error: DrmError
|
||||||
|
) {
|
||||||
error!(self.logger, "{:?}", error);
|
error!(self.logger, "{:?}", error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
@ -140,6 +139,7 @@
|
||||||
//! # use std::time::Duration;
|
//! # use std::time::Duration;
|
||||||
//! use smithay::backend::drm::{DrmDevice, DrmBackend, DrmHandler, drm_device_bind};
|
//! use smithay::backend::drm::{DrmDevice, DrmBackend, DrmHandler, drm_device_bind};
|
||||||
//! use smithay::backend::graphics::egl::EGLGraphicsBackend;
|
//! use smithay::backend::graphics::egl::EGLGraphicsBackend;
|
||||||
|
//! use wayland_server::EventLoopHandle;
|
||||||
//! #
|
//! #
|
||||||
//! # #[derive(Debug)]
|
//! # #[derive(Debug)]
|
||||||
//! # pub struct Card(File);
|
//! # pub struct Card(File);
|
||||||
|
@ -181,6 +181,7 @@
|
||||||
//! impl DrmHandler<Card> for MyDrmHandler {
|
//! impl DrmHandler<Card> for MyDrmHandler {
|
||||||
//! fn ready(
|
//! fn ready(
|
||||||
//! &mut self,
|
//! &mut self,
|
||||||
|
//! _evlh: &mut EventLoopHandle,
|
||||||
//! _device: &mut DrmDevice<Card>,
|
//! _device: &mut DrmDevice<Card>,
|
||||||
//! _crtc: CrtcHandle,
|
//! _crtc: CrtcHandle,
|
||||||
//! _frame: u32,
|
//! _frame: u32,
|
||||||
|
@ -191,6 +192,7 @@
|
||||||
//! }
|
//! }
|
||||||
//! fn error(
|
//! fn error(
|
||||||
//! &mut self,
|
//! &mut self,
|
||||||
|
//! _evlh: &mut EventLoopHandle,
|
||||||
//! device: &mut DrmDevice<Card>,
|
//! device: &mut DrmDevice<Card>,
|
||||||
//! error: DrmError)
|
//! error: DrmError)
|
||||||
//! {
|
//! {
|
||||||
|
@ -201,8 +203,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)).map_err(|(err, _)| err).unwrap();
|
||||||
//! let _source = drm_device_bind(&mut event_loop, device_token, MyDrmHandler(backend)).unwrap();
|
|
||||||
//!
|
//!
|
||||||
//! event_loop.run().unwrap();
|
//! event_loop.run().unwrap();
|
||||||
//! # }
|
//! # }
|
||||||
|
@ -213,7 +214,7 @@ use backend::graphics::egl::error::Result as EGLResult;
|
||||||
use backend::graphics::egl::native::Gbm;
|
use backend::graphics::egl::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 +223,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::Error as IoError;
|
||||||
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 +250,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 +317,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 +383,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 +442,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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -531,25 +532,28 @@ impl<A: ControlDevice + 'static> Drop for DrmDevice<A> {
|
||||||
pub trait DrmHandler<A: ControlDevice + 'static> {
|
pub trait DrmHandler<A: ControlDevice + 'static> {
|
||||||
/// The `DrmBackend` of crtc has finished swapping buffers and new frame can now
|
/// The `DrmBackend` of crtc has finished swapping buffers and new frame can now
|
||||||
/// (and should be immediately) be rendered.
|
/// (and should be immediately) be rendered.
|
||||||
fn ready(&mut self, device: &mut DrmDevice<A>, crtc: crtc::Handle, frame: u32, duration: Duration);
|
fn ready(
|
||||||
|
&mut self, evlh: &mut EventLoopHandle, device: &mut DrmDevice<A>, crtc: crtc::Handle, frame: u32,
|
||||||
|
duration: Duration,
|
||||||
|
);
|
||||||
/// The `DrmDevice` has thrown an error.
|
/// The `DrmDevice` has thrown an error.
|
||||||
///
|
///
|
||||||
/// The related backends are most likely *not* usable anymore and
|
/// The related backends are most likely *not* usable anymore and
|
||||||
/// the whole stack has to be recreated..
|
/// the whole stack has to be recreated..
|
||||||
fn error(&mut self, device: &mut DrmDevice<A>, error: DrmError);
|
fn error(&mut self, evlh: &mut EventLoopHandle, device: &mut DrmDevice<A>, error: DrmError);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bind a `DrmDevice` to an `EventLoop`,
|
/// Bind a `DrmDevice` to an `EventLoop`,
|
||||||
///
|
///
|
||||||
/// 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)>>
|
) -> ::std::result::Result<FdEventSource<(DrmDevice<A>, H)>, (IoError, (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 +562,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,91 +582,120 @@ 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(evlh, 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(evlh, 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(evlh, 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>>>>>,
|
||||||
|
old_state: HashMap<crtc::Handle, (crtc::Info, Vec<connector::Handle>)>,
|
||||||
|
active: Arc<AtomicBool>,
|
||||||
|
priviledged: bool,
|
||||||
|
logger: ::slog::Logger,
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "backend_session")]
|
#[cfg(feature = "backend_session")]
|
||||||
impl<A: ControlDevice + 'static> SessionObserver for StateToken<DrmDevice<A>> {
|
impl<A: ControlDevice + 'static> AsSessionObserver<DrmDeviceObserver<A>> for DrmDevice<A> {
|
||||||
fn pause<'a>(&mut self, state: &mut StateProxy<'a>, devnum: Option<(u32, u32)>) {
|
fn observer(&mut self) -> DrmDeviceObserver<A> {
|
||||||
let device = state.get_mut(self);
|
DrmDeviceObserver {
|
||||||
|
context: Rc::downgrade(&self.context),
|
||||||
|
device_id: self.device_id.clone(),
|
||||||
|
backends: self.backends.clone(),
|
||||||
|
old_state: self.old_state.clone(),
|
||||||
|
active: self.active.clone(),
|
||||||
|
priviledged: self.priviledged,
|
||||||
|
logger: self.logger.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "backend_session")]
|
||||||
|
impl<A: ControlDevice + 'static> SessionObserver for DrmDeviceObserver<A> {
|
||||||
|
fn pause(&mut self, _evlh: &mut EventLoopHandle, devnum: Option<(u32, u32)>) {
|
||||||
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() {
|
if let Some(device) = self.context.upgrade() {
|
||||||
if let Err(err) = crtc::set(
|
for (handle, &(ref info, ref connectors)) in self.old_state.iter() {
|
||||||
&*device.context,
|
if let Err(err) = crtc::set(
|
||||||
*handle,
|
&*device,
|
||||||
info.fb(),
|
*handle,
|
||||||
connectors,
|
info.fb(),
|
||||||
info.position(),
|
connectors,
|
||||||
info.mode(),
|
info.position(),
|
||||||
) {
|
info.mode(),
|
||||||
error!(
|
) {
|
||||||
device.logger,
|
error!(
|
||||||
"Failed to reset crtc ({:?}). Error: {}", handle, err
|
self.logger,
|
||||||
);
|
"Failed to reset crtc ({:?}). Error: {}", handle, err
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
device.active = false;
|
self.active.store(false, Ordering::SeqCst);
|
||||||
if device.priviledged {
|
if self.priviledged {
|
||||||
if let Err(err) = device.drop_master() {
|
if let Some(device) = self.context.upgrade() {
|
||||||
error!(
|
if let Err(err) = device.drop_master() {
|
||||||
device.logger,
|
error!(
|
||||||
"Failed to drop drm master state. Error: {}", err
|
self.logger,
|
||||||
);
|
"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");
|
||||||
nix::unistd::dup2(device.as_raw_fd(), fd)
|
if let Some(device) = self.context.upgrade() {
|
||||||
.expect("Failed to replace file descriptor of drm device");
|
nix::unistd::dup2(device.as_raw_fd(), fd)
|
||||||
|
.expect("Failed to replace file descriptor of drm device");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
device.active = true;
|
self.active.store(true, Ordering::SeqCst);
|
||||||
if device.priviledged {
|
if self.priviledged {
|
||||||
if let Err(err) = device.set_master() {
|
if let Some(device) = self.context.upgrade() {
|
||||||
crit!(
|
if let Err(err) = device.set_master() {
|
||||||
device.logger,
|
crit!(
|
||||||
"Failed to acquire drm master again. Error: {}",
|
self.logger,
|
||||||
err
|
"Failed to acquire drm master again. Error: {}",
|
||||||
);
|
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 +711,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 +720,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,11 +7,11 @@ use input as libinput;
|
||||||
use input::event;
|
use input::event;
|
||||||
use std::collections::hash_map::{DefaultHasher, Entry, HashMap};
|
use std::collections::hash_map::{DefaultHasher, Entry, HashMap};
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::io::{Error as IoError, Result as IoResult};
|
use std::io::Error as IoError;
|
||||||
use std::os::unix::io::RawFd;
|
use std::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");
|
||||||
|
@ -635,7 +635,7 @@ impl<S: Session> libinput::LibinputInterface for LibinputSessionInterface<S> {
|
||||||
/// `dispatch_new_events`. Should be used to achieve the smallest possible latency.
|
/// `dispatch_new_events`. Should be used to achieve the smallest possible latency.
|
||||||
pub fn libinput_bind(
|
pub fn libinput_bind(
|
||||||
backend: LibinputInputBackend, evlh: &mut EventLoopHandle
|
backend: LibinputInputBackend, evlh: &mut EventLoopHandle
|
||||||
) -> IoResult<FdEventSource<LibinputInputBackend>> {
|
) -> ::std::result::Result<FdEventSource<LibinputInputBackend>, (IoError, LibinputInputBackend)> {
|
||||||
let fd = unsafe { backend.context.fd() };
|
let fd = unsafe { backend.context.fd() };
|
||||||
evlh.add_fd_event_source(
|
evlh.add_fd_event_source(
|
||||||
fd,
|
fd,
|
||||||
|
|
|
@ -29,18 +29,18 @@
|
||||||
//! 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, AsSessionObserver, Session, SessionNotifier, SessionObserver};
|
||||||
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};
|
||||||
use nix::fcntl::OFlag;
|
use nix::fcntl::OFlag;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::io::Result as IoResult;
|
use std::io::Error as IoError;
|
||||||
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;
|
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)]
|
||||||
|
@ -154,11 +154,13 @@ impl AutoSession {
|
||||||
/// session state and call it's `SessionObservers`.
|
/// session state and call it's `SessionObservers`.
|
||||||
pub fn auto_session_bind(
|
pub fn auto_session_bind(
|
||||||
notifier: AutoSessionNotifier, evlh: &mut EventLoopHandle
|
notifier: AutoSessionNotifier, evlh: &mut EventLoopHandle
|
||||||
) -> IoResult<BoundAutoSession> {
|
) -> ::std::result::Result<BoundAutoSession, (IoError, AutoSessionNotifier)> {
|
||||||
Ok(match notifier {
|
Ok(match notifier {
|
||||||
#[cfg(feature = "backend_session_logind")]
|
#[cfg(feature = "backend_session_logind")]
|
||||||
AutoSessionNotifier::Logind(logind) => BoundAutoSession::Logind(logind_session_bind(logind, evlh)?),
|
AutoSessionNotifier::Logind(logind) => BoundAutoSession::Logind(logind_session_bind(logind, evlh)
|
||||||
AutoSessionNotifier::Direct(direct) => BoundAutoSession::Direct(direct_session_bind(direct, evlh)?),
|
.map_err(|(error, notifier)| (error, AutoSessionNotifier::Logind(notifier)))?),
|
||||||
|
AutoSessionNotifier::Direct(direct) => BoundAutoSession::Direct(direct_session_bind(direct, evlh)
|
||||||
|
.map_err(|(error, notifier)| (error, AutoSessionNotifier::Direct(notifier)))?),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,7 +209,9 @@ impl Session for AutoSession {
|
||||||
impl SessionNotifier for AutoSessionNotifier {
|
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) => {
|
||||||
|
|
|
@ -30,20 +30,20 @@
|
||||||
//! 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, AsSessionObserver, Session, SessionNotifier, SessionObserver};
|
||||||
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;
|
||||||
use nix::sys::stat::{fstat, major, minor, stat};
|
use nix::sys::stat::{fstat, major, minor, stat};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::io::Result as IoResult;
|
use std::io::Error as IoError;
|
||||||
use std::os::unix::io::RawFd;
|
use std::os::unix::io::RawFd;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::rc::{Rc, Weak};
|
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) {
|
||||||
|
@ -430,8 +432,10 @@ pub struct BoundLogindSession {
|
||||||
/// session state and call it's `SessionObservers`.
|
/// session state and call it's `SessionObservers`.
|
||||||
pub fn logind_session_bind(
|
pub fn logind_session_bind(
|
||||||
notifier: LogindSessionNotifier, evlh: &mut EventLoopHandle
|
notifier: LogindSessionNotifier, evlh: &mut EventLoopHandle
|
||||||
) -> IoResult<BoundLogindSession> {
|
) -> ::std::result::Result<BoundLogindSession, (IoError, LogindSessionNotifier)> {
|
||||||
let watches = notifier.internal.conn.borrow().watch_fds();
|
let watches = notifier.internal.conn.borrow().watch_fds();
|
||||||
|
|
||||||
|
let internal_for_error = notifier.internal.clone();
|
||||||
let sources = watches
|
let sources = watches
|
||||||
.clone()
|
.clone()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -446,7 +450,15 @@ pub fn logind_session_bind(
|
||||||
interest,
|
interest,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect::<IoResult<Vec<FdEventSource<Rc<LogindSessionImpl>>>>>()?;
|
.collect::<::std::result::Result<Vec<FdEventSource<Rc<LogindSessionImpl>>>, (IoError, _)>>()
|
||||||
|
.map_err(|(err, _)| {
|
||||||
|
(
|
||||||
|
err,
|
||||||
|
LogindSessionNotifier {
|
||||||
|
internal: internal_for_error,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
Ok(BoundLogindSession {
|
Ok(BoundLogindSession {
|
||||||
notifier,
|
notifier,
|
||||||
|
|
|
@ -45,14 +45,14 @@
|
||||||
//! 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, AsSessionObserver, Session, SessionNotifier, SessionObserver};
|
||||||
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;
|
||||||
use nix::sys::signal::{self, Signal};
|
use nix::sys::signal::{self, Signal};
|
||||||
use nix::sys::stat::{dev_t, fstat, major, minor, Mode};
|
use nix::sys::stat::{dev_t, fstat, major, minor, Mode};
|
||||||
use nix::unistd::{close, dup};
|
use nix::unistd::{close, dup};
|
||||||
use std::io::Result as IoResult;
|
use std::io::Error as IoError;
|
||||||
use std::os::unix::io::RawFd;
|
use std::os::unix::io::RawFd;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
@ -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>>(
|
||||||
self.signals.push(Some(Box::new(signal)));
|
&mut self, signal: &mut A
|
||||||
|
) -> Self::Id {
|
||||||
|
self.signals.push(Some(Box::new(signal.observer())));
|
||||||
Id(self.signals.len() - 1)
|
Id(self.signals.len() - 1)
|
||||||
}
|
}
|
||||||
fn unregister(&mut self, signal: Id) {
|
fn unregister(&mut self, signal: Id) {
|
||||||
|
@ -367,7 +369,7 @@ impl SessionNotifier for DirectSessionNotifier {
|
||||||
/// session state and call it's `SessionObservers`.
|
/// session state and call it's `SessionObservers`.
|
||||||
pub fn direct_session_bind(
|
pub fn direct_session_bind(
|
||||||
notifier: DirectSessionNotifier, evlh: &mut EventLoopHandle
|
notifier: DirectSessionNotifier, evlh: &mut EventLoopHandle
|
||||||
) -> IoResult<SignalEventSource<DirectSessionNotifier>> {
|
) -> ::std::result::Result<SignalEventSource<DirectSessionNotifier>, (IoError, DirectSessionNotifier)> {
|
||||||
let signal = notifier.signal;
|
let signal = notifier.signal;
|
||||||
|
|
||||||
evlh.add_signal_event_source(
|
evlh.add_signal_event_source(
|
||||||
|
@ -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);
|
||||||
|
|
|
@ -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,8 @@ 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 +64,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 +85,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 () {
|
||||||
|
|
|
@ -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::{AsSessionObserver, Session, SessionObserver};
|
||||||
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;
|
||||||
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>>,
|
||||||
{
|
{
|
||||||
|
@ -96,21 +92,21 @@ impl<H: DrmHandler<SessionFdDrmDevice> + 'static, S: Session + 'static, T: UdevH
|
||||||
) {
|
) {
|
||||||
// Call the handler, which might add it to the runloop
|
// Call the handler, which might add it to the runloop
|
||||||
Ok(mut device) => {
|
Ok(mut device) => {
|
||||||
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) {
|
let fd = device.as_raw_fd();
|
||||||
|
match handler.device_added(evlh, &mut device) {
|
||||||
Some(drm_handler) => {
|
Some(drm_handler) => {
|
||||||
let token = evlh.state().insert(device);
|
match drm_device_bind(&mut evlh, device, drm_handler) {
|
||||||
if let Ok(event_source) = drm_device_bind(&mut evlh, token.clone(), drm_handler) {
|
Ok(event_source) => Some((devnum, event_source)),
|
||||||
Some((devnum, (token, event_source)))
|
Err((err, (mut device, _))) => {
|
||||||
} else {
|
warn!(logger, "Failed to bind device. Error: {:?}.", err);
|
||||||
handler.device_removed(evlh.state(), &token);
|
handler.device_removed(evlh, &mut device);
|
||||||
let device = evlh.state().remove(token);
|
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);
|
};
|
||||||
};
|
None
|
||||||
None
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
|
@ -128,7 +124,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 +134,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 +162,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 pause<'a>(&mut self, state: &mut StateProxy<'a>, devnum: Option<(u32, u32)>) {
|
fn observer(&mut self) -> UdevBackendObserver<H> {
|
||||||
state.with_value(self, |state, udev| {
|
UdevBackendObserver {
|
||||||
for &mut (ref mut device, _) in udev.devices.values_mut() {
|
devices: Rc::downgrade(&self.devices),
|
||||||
device.pause(state, devnum);
|
logger: self.logger.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<H: DrmHandler<SessionFdDrmDevice> + 'static> SessionObserver for UdevBackendObserver<H> {
|
||||||
|
fn pause<'a>(&mut self, evlh: &mut EventLoopHandle, devnum: Option<(u32, u32)>) {
|
||||||
|
if let Some(devices) = self.devices.upgrade() {
|
||||||
|
for fd_event_source in devices.borrow_mut().values_mut() {
|
||||||
|
fd_event_source.with_idata(evlh, |&mut (ref mut device, _), evlh| {
|
||||||
|
info!(self.logger, "changed successful");
|
||||||
|
device.observer().pause(evlh, devnum);
|
||||||
|
})
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn activate<'a>(&mut self, state: &mut StateProxy<'a>, devnum: Option<(u32, u32, Option<RawFd>)>) {
|
fn activate<'a>(&mut self, evlh: &mut EventLoopHandle, devnum: Option<(u32, u32, Option<RawFd>)>) {
|
||||||
state.with_value(self, |state, udev| {
|
if let Some(devices) = self.devices.upgrade() {
|
||||||
for &mut (ref mut device, _) in udev.devices.values_mut() {
|
for fd_event_source in devices.borrow_mut().values_mut() {
|
||||||
device.activate(state, devnum);
|
fd_event_source.with_idata(evlh, |&mut (ref mut device, _), evlh| {
|
||||||
|
info!(self.logger, "changed successful");
|
||||||
|
device.observer().activate(evlh, devnum);
|
||||||
|
})
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,41 +211,37 @@ impl<
|
||||||
/// Allows the backend to recieve kernel events and thus to drive the `UdevHandler`.
|
/// 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>>>>
|
) -> ::std::result::Result<FdEventSource<UdevBackend<H, S, T>>, (IoError, 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 +258,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,57 +273,43 @@ 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) => match drm_device_bind(&mut evlh, device, drm_handler) {
|
||||||
}) {
|
Ok(fd_event_source) => {
|
||||||
Some(drm_handler) => {
|
udev.devices.borrow_mut().insert(devnum, fd_event_source);
|
||||||
let dev_token = evlh.state().insert(device);
|
|
||||||
if let Ok(fd_event_source) =
|
|
||||||
drm_device_bind(&mut evlh, dev_token.clone(), drm_handler)
|
|
||||||
{
|
|
||||||
evlh.state()
|
|
||||||
.get_mut(token)
|
|
||||||
.devices
|
|
||||||
.insert(devnum, (dev_token, fd_event_source));
|
|
||||||
} else {
|
|
||||||
evlh.state().with_value(token, |state, udev| {
|
|
||||||
let mut state: StateProxy = state.into();
|
|
||||||
udev.handler.device_removed(&mut state, &dev_token);
|
|
||||||
let device = state.remove(dev_token);
|
|
||||||
drop(device);
|
|
||||||
if let Err(err) = udev.session.close(fd) {
|
|
||||||
warn!(
|
|
||||||
udev.logger,
|
|
||||||
"Failed to close dropped device. Error: {:?}. Ignoring",
|
|
||||||
err
|
|
||||||
);
|
|
||||||
};
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
Err((err, (mut device, _))) => {
|
||||||
None => {
|
warn!(udev.logger, "Failed to bind device. Error: {:?}.", err);
|
||||||
drop(device);
|
udev.handler.device_removed(evlh, &mut device);
|
||||||
evlh.state().with_value(token, |_state, udev| {
|
drop(device);
|
||||||
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 dropped device. Error: {:?}. Ignoring", err
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
})
|
}
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
udev.handler.device_removed(evlh, &mut device);
|
||||||
|
drop(device);
|
||||||
|
if let Err(err) = udev.session.close(fd) {
|
||||||
|
warn!(
|
||||||
|
udev.logger,
|
||||||
|
"Failed to close unused device. Error: {:?}", err
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Device removed
|
// 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,30 +322,31 @@ 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| udev.handler.error(evlh, err),
|
||||||
evlh.state()
|
|
||||||
.with_value(token, |state, udev| udev.handler.error(state, err))
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -366,8 +358,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,9 +368,7 @@ 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, evlh: &mut EventLoopHandle, device: &mut DrmDevice<SessionFdDrmDevice>);
|
||||||
&mut self, state: S, device: &StateToken<DrmDevice<SessionFdDrmDevice>>
|
|
||||||
);
|
|
||||||
/// Called when a device was removed.
|
/// Called when a device was removed.
|
||||||
///
|
///
|
||||||
/// The device will not accept any operations anymore and its file descriptor will be closed once
|
/// The device will not accept any operations anymore and its file descriptor will be closed once
|
||||||
|
@ -386,14 +376,12 @@ 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, evlh: &mut EventLoopHandle, device: &mut DrmDevice<SessionFdDrmDevice>);
|
||||||
&mut self, state: S, device: &StateToken<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
|
||||||
|
|
Loading…
Reference in New Issue