backend: migrate drm & udev

This commit is contained in:
Victor Berger 2018-04-18 09:38:35 +02:00
parent f9dbabce56
commit 7f6af94733
11 changed files with 270 additions and 200 deletions

View File

@ -37,8 +37,11 @@ pub(crate) struct DrmBackendInternal<A: Device + 'static> {
impl<A: Device + 'static> DrmBackend<A> {
pub(crate) fn new(
context: Rc<EGLContext<Gbm<framebuffer::Info>, GbmDevice<A>>>, crtc: crtc::Handle, mode: Mode,
connectors: Vec<connector::Handle>, log: ::slog::Logger,
context: Rc<EGLContext<Gbm<framebuffer::Info>, GbmDevice<A>>>,
crtc: crtc::Handle,
mode: Mode,
connectors: Vec<connector::Handle>,
log: ::slog::Logger,
) -> Result<Self> {
// logger already initialized by the DrmDevice
info!(log, "Initializing DrmBackend");
@ -351,7 +354,8 @@ impl<A: Device + 'static> DrmBackendInternal<A> {
}
pub(crate) fn page_flip(
&self, fb: Option<&framebuffer::Info>
&self,
fb: Option<&framebuffer::Info>,
) -> ::std::result::Result<(), SwapBuffersError> {
trace!(self.logger, "Queueing Page flip");
@ -421,7 +425,9 @@ impl<A: Device + 'static> GraphicsBackend for DrmBackend<A> {
}
fn set_cursor_representation(
&self, buffer: &ImageBuffer<Rgba<u8>, Vec<u8>>, hotspot: (u32, u32)
&self,
buffer: &ImageBuffer<Rgba<u8>, Vec<u8>>,
hotspot: (u32, u32),
) -> Result<()> {
let (w, h) = buffer.dimensions();
debug!(self.backend.logger, "Importing cursor");

View File

@ -233,8 +233,9 @@ use std::rc::{Rc, Weak};
use std::sync::{Arc, Once, ONCE_INIT};
use std::sync::atomic::{AtomicBool, Ordering};
use std::time::Duration;
use wayland_server::{Display, EventLoopHandle};
use wayland_server::sources::{FdEventSource, FdEventSourceImpl, FdInterest};
use wayland_server::{Display, LoopToken};
use wayland_server::commons::{downcast_impl, Implementation};
use wayland_server::sources::{FdEvent, FdInterest, Source};
mod backend;
pub mod error;
@ -378,7 +379,10 @@ impl<A: ControlDevice + 'static> DrmDevice<A> {
/// Errors if initialization fails or the mode is not available on all given
/// connectors.
pub fn create_backend<I>(
&mut self, crtc: crtc::Handle, mode: Mode, connectors: I
&mut self,
crtc: crtc::Handle,
mode: Mode,
connectors: I,
) -> Result<DrmBackend<A>>
where
I: Into<Vec<connector::Handle>>,
@ -532,44 +536,66 @@ impl<A: ControlDevice + 'static> Drop for DrmDevice<A> {
pub trait DrmHandler<A: ControlDevice + 'static> {
/// The `DrmBackend` of crtc has finished swapping buffers and new frame can now
/// (and should be immediately) be rendered.
fn ready(
&mut self, evlh: &mut EventLoopHandle, device: &mut DrmDevice<A>, crtc: crtc::Handle, frame: u32,
duration: Duration,
);
fn ready(&mut self, device: &mut DrmDevice<A>, crtc: crtc::Handle, frame: u32, duration: Duration);
/// The `DrmDevice` has thrown an error.
///
/// The related backends are most likely *not* usable anymore and
/// the whole stack has to be recreated..
fn error(&mut self, evlh: &mut EventLoopHandle, device: &mut DrmDevice<A>, error: DrmError);
fn error(&mut self, device: &mut DrmDevice<A>, error: DrmError);
}
/// Bind a `DrmDevice` to an `EventLoop`,
///
/// This will cause it to recieve events and feed them into an `DrmHandler`
pub fn drm_device_bind<A, H>(
evlh: &mut EventLoopHandle, device: DrmDevice<A>, handler: H
) -> ::std::result::Result<FdEventSource<(DrmDevice<A>, H)>, (IoError, (DrmDevice<A>, H))>
token: &LoopToken,
device: DrmDevice<A>,
handler: H,
) -> ::std::result::Result<(Source<FdEvent>, Rc<RefCell<DrmDevice<A>>>), (IoError, (DrmDevice<A>, H))>
where
A: ControlDevice + 'static,
H: DrmHandler<A> + 'static,
{
let fd = device.as_raw_fd();
evlh.add_fd_event_source(
let device = Rc::new(RefCell::new(device));
match token.add_fd_event_source(
fd,
fd_event_source_implementation(),
(device, handler),
FdInterest::READ,
)
DrmFdImpl {
device: device.clone(),
handler,
},
) {
Ok(source) => Ok((source, device)),
Err((
ioerror,
DrmFdImpl {
device: device2,
handler,
},
)) => {
// make the Rc unique again
::std::mem::drop(device2);
let device = Rc::try_unwrap(device).unwrap_or_else(|_| unreachable!());
Err((ioerror, (device.into_inner(), handler)))
}
}
}
fn fd_event_source_implementation<A, H>() -> FdEventSourceImpl<(DrmDevice<A>, H)>
struct DrmFdImpl<A: ControlDevice + 'static, H> {
device: Rc<RefCell<DrmDevice<A>>>,
handler: H,
}
impl<A, H> Implementation<(), FdEvent> for DrmFdImpl<A, H>
where
A: ControlDevice + 'static,
H: DrmHandler<A> + 'static,
{
FdEventSourceImpl {
ready: |evlh, &mut (ref mut device, ref mut handler), _, _| {
match crtc::receive_events(device) {
fn receive(&mut self, event: FdEvent, (): ()) {
let mut device = self.device.borrow_mut();
match event {
FdEvent::Ready { .. } => match crtc::receive_events(&mut *device) {
Ok(events) => for event in events {
if let crtc::Event::PageFlip(event) = event {
if device.active.load(Ordering::SeqCst) {
@ -584,20 +610,21 @@ where
backend.unlock_buffer();
trace!(device.logger, "Handling event for backend {:?}", event.crtc);
// and then call the user to render the next frame
handler.ready(evlh, device, event.crtc, event.frame, event.duration);
self.handler
.ready(&mut device, event.crtc, event.frame, event.duration);
} else {
device.backends.borrow_mut().remove(&event.crtc);
}
}
}
},
Err(err) => handler.error(evlh, device, err),
};
},
error: |evlh, &mut (ref mut device, ref mut handler), _, error| {
warn!(device.logger, "DrmDevice errored: {}", error);
handler.error(evlh, device, error.into());
},
Err(err) => self.handler.error(&mut device, err),
},
FdEvent::Error { error, .. } => {
warn!(device.logger, "DrmDevice errored: {}", error);
self.handler.error(&mut device, error.into());
}
}
}
}
@ -629,7 +656,7 @@ impl<A: ControlDevice + 'static> AsSessionObserver<DrmDeviceObserver<A>> for Drm
#[cfg(feature = "backend_session")]
impl<A: ControlDevice + 'static> SessionObserver for DrmDeviceObserver<A> {
fn pause(&mut self, _evlh: &mut EventLoopHandle, devnum: Option<(u32, u32)>) {
fn pause(&mut self, devnum: Option<(u32, u32)>) {
if let Some((major, minor)) = devnum {
if major as u64 != stat::major(self.device_id) || minor as u64 != stat::minor(self.device_id) {
return;
@ -665,7 +692,7 @@ impl<A: ControlDevice + 'static> SessionObserver for DrmDeviceObserver<A> {
}
}
fn activate(&mut self, _evlh: &mut EventLoopHandle, devnum: Option<(u32, u32, Option<RawFd>)>) {
fn activate(&mut self, devnum: Option<(u32, u32, Option<RawFd>)>) {
if let Some((major, minor, fd)) = devnum {
if major as u64 != stat::major(self.device_id) || minor as u64 != stat::minor(self.device_id) {
return;

View File

@ -50,7 +50,10 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> DerefMut for EGLContext<B,
impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
/// Create a new `EGLContext` from a given `NativeDisplay`
pub fn new<L>(
native: N, attributes: GlAttributes, reqs: PixelFormatRequirements, logger: L
native: N,
attributes: GlAttributes,
reqs: PixelFormatRequirements,
logger: L,
) -> Result<EGLContext<B, N>>
where
L: Into<Option<::slog::Logger>>,
@ -82,7 +85,9 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
}
unsafe fn new_internal(
ptr: ffi::NativeDisplayType, mut attributes: GlAttributes, reqs: PixelFormatRequirements,
ptr: ffi::NativeDisplayType,
mut attributes: GlAttributes,
reqs: PixelFormatRequirements,
log: ::slog::Logger,
) -> Result<
(

View File

@ -42,7 +42,8 @@ pub mod egl {
#[allow(non_snake_case, unused_variables, dead_code)]
#[inline]
pub unsafe fn BindWaylandDisplayWL(
dpy: types::EGLDisplay, display: *mut __gl_imports::raw::c_void
dpy: types::EGLDisplay,
display: *mut __gl_imports::raw::c_void,
) -> types::EGLBoolean {
__gl_imports::mem::transmute::<
_,
@ -53,7 +54,8 @@ pub mod egl {
#[allow(non_snake_case, unused_variables, dead_code)]
#[inline]
pub unsafe fn UnbindWaylandDisplayWL(
dpy: types::EGLDisplay, display: *mut __gl_imports::raw::c_void
dpy: types::EGLDisplay,
display: *mut __gl_imports::raw::c_void,
) -> types::EGLBoolean {
__gl_imports::mem::transmute::<
_,
@ -64,7 +66,9 @@ pub mod egl {
#[allow(non_snake_case, unused_variables, dead_code)]
#[inline]
pub unsafe fn QueryWaylandBufferWL(
dpy: types::EGLDisplay, buffer: *mut __gl_imports::raw::c_void, attribute: types::EGLint,
dpy: types::EGLDisplay,
buffer: *mut __gl_imports::raw::c_void,
attribute: types::EGLint,
value: *mut types::EGLint,
) -> types::EGLBoolean {
__gl_imports::mem::transmute::<

View File

@ -31,7 +31,9 @@ pub trait Backend {
/// The returned `EGLDisplay` needs to be a valid ptr for egl,
/// but there is no way to test that.
unsafe fn get_display<F: Fn(&str) -> bool>(
display: ffi::NativeDisplayType, has_dp_extension: F, log: ::slog::Logger
display: ffi::NativeDisplayType,
has_dp_extension: F,
log: ::slog::Logger,
) -> ffi::egl::types::EGLDisplay;
}
@ -43,7 +45,9 @@ impl Backend for Wayland {
type Surface = wegl::WlEglSurface;
unsafe fn get_display<F>(
display: ffi::NativeDisplayType, has_dp_extension: F, log: ::slog::Logger
display: ffi::NativeDisplayType,
has_dp_extension: F,
log: ::slog::Logger,
) -> ffi::egl::types::EGLDisplay
where
F: Fn(&str) -> bool,
@ -87,7 +91,9 @@ impl Backend for X11 {
type Surface = XlibWindow;
unsafe fn get_display<F>(
display: ffi::NativeDisplayType, has_dp_extension: F, log: ::slog::Logger
display: ffi::NativeDisplayType,
has_dp_extension: F,
log: ::slog::Logger,
) -> ffi::egl::types::EGLDisplay
where
F: Fn(&str) -> bool,
@ -114,7 +120,9 @@ impl<T: 'static> Backend for Gbm<T> {
type Surface = GbmSurface<T>;
unsafe fn get_display<F>(
display: ffi::NativeDisplayType, has_dp_extension: F, log: ::slog::Logger
display: ffi::NativeDisplayType,
has_dp_extension: F,
log: ::slog::Logger,
) -> ffi::egl::types::EGLDisplay
where
F: Fn(&str) -> bool,

View File

@ -30,7 +30,8 @@ impl<N: native::NativeSurface> DerefMut for EGLSurface<N> {
impl<N: native::NativeSurface> EGLSurface<N> {
pub(crate) fn new<B: native::Backend<Surface = N>, D: native::NativeDisplay<B>>(
context: &EGLContext<B, D>, native: N
context: &EGLContext<B, D>,
native: N,
) -> Result<EGLSurface<N>> {
let surface = unsafe {
ffi::egl::CreateWindowSurface(

View File

@ -192,7 +192,9 @@ impl EGLImages {
///
/// The given `tex_id` needs to be a valid GL texture otherwise undefined behavior might occur.
pub unsafe fn bind_to_texture(
&self, plane: usize, tex_id: c_uint
&self,
plane: usize,
tex_id: c_uint,
) -> ::std::result::Result<(), TextureCreationError> {
if self.display.upgrade().is_some() {
let mut old_tex_id: i32 = 0;
@ -255,7 +257,8 @@ pub struct EGLDisplay(Weak<ffi::egl::types::EGLDisplay>, *mut wl_display);
impl EGLDisplay {
fn new<B: native::Backend, N: native::NativeDisplay<B>>(
context: &EGLContext<B, N>, display: *mut wl_display
context: &EGLContext<B, N>,
display: *mut wl_display,
) -> EGLDisplay {
EGLDisplay(Rc::downgrade(&context.display), display)
}
@ -266,7 +269,8 @@ impl EGLDisplay {
/// a `BufferAccessError::NotManaged(WlBuffer)` is returned with the original buffer
/// to render it another way.
pub fn egl_buffer_contents(
&self, buffer: Resource<WlBuffer>
&self,
buffer: Resource<WlBuffer>,
) -> ::std::result::Result<EGLImages, BufferAccessError> {
if let Some(display) = self.0.upgrade() {
let mut format: i32 = 0;

View File

@ -30,7 +30,9 @@ pub trait GraphicsBackend {
/// from raw image buffers over a fixed list of possible cursor types to simply the
/// void type () to represent no possible customization of the cursor itself.
fn set_cursor_representation(
&self, cursor: &Self::CursorFormat, hotspot: (u32, u32)
&self,
cursor: &Self::CursorFormat,
hotspot: (u32, u32),
) -> Result<(), Self::Error>;
}

View File

@ -19,11 +19,11 @@ pub mod graphics;
//#[cfg(feature = "backend_winit")]
//pub mod winit;
//#[cfg(feature = "backend_drm")]
//pub mod drm;
#[cfg(feature = "backend_drm")]
pub mod drm;
//#[cfg(feature = "backend_libinput")]
//pub mod libinput;
#[cfg(feature = "backend_session")]
pub mod session;
//#[cfg(feature = "backend_udev")]
//pub mod udev;
#[cfg(feature = "backend_udev")]
pub mod udev;

View File

@ -451,11 +451,7 @@ pub fn logind_session_bind(
let mut interest = FdInterest::empty();
interest.set(FdInterest::READ, watch.readable());
interest.set(FdInterest::WRITE, watch.writable());
token.add_fd_event_source(
watch.fd(),
interest,
notifier.clone(),
)
token.add_fd_event_source(watch.fd(), interest, notifier.clone())
})
.collect::<::std::result::Result<Vec<Source<FdEvent>>, (IoError, _)>>()
.map_err(|(err, _)| {

View File

@ -24,8 +24,9 @@ use std::os::unix::io::{AsRawFd, RawFd};
use std::path::{Path, PathBuf};
use std::rc::{Rc, Weak};
use udev::{Context, Enumerator, Event, EventType, MonitorBuilder, MonitorSocket, Result as UdevResult};
use wayland_server::EventLoopHandle;
use wayland_server::sources::{EventSource, FdEventSource, FdEventSourceImpl, FdInterest};
use wayland_server::LoopToken;
use wayland_server::commons::Implementation;
use wayland_server::sources::{FdEvent, FdInterest, Source};
/// Udev's `DrmDevice` type based on the underlying session
pub struct SessionFdDrmDevice(RawFd);
@ -48,11 +49,13 @@ pub struct UdevBackend<
S: Session + 'static,
T: UdevHandler<H> + 'static,
> {
devices: Rc<RefCell<HashMap<dev_t, FdEventSource<(DrmDevice<SessionFdDrmDevice>, H)>>>>,
_handler: ::std::marker::PhantomData<H>,
devices: Rc<RefCell<HashMap<dev_t, (Source<FdEvent>, Rc<RefCell<DrmDevice<SessionFdDrmDevice>>>)>>>,
monitor: MonitorSocket,
session: S,
handler: T,
logger: ::slog::Logger,
token: LoopToken,
}
impl<H: DrmHandler<SessionFdDrmDevice> + 'static, S: Session + 'static, T: UdevHandler<H> + 'static>
@ -67,7 +70,11 @@ impl<H: DrmHandler<SessionFdDrmDevice> + 'static, S: Session + 'static, T: UdevH
/// `handler` - User-provided handler to respond to any detected changes
/// `logger` - slog Logger to be used by the backend and its `DrmDevices`.
pub fn new<'a, L>(
mut evlh: &mut EventLoopHandle, context: &Context, mut session: S, mut handler: T, logger: L
token: LoopToken,
context: &Context,
mut session: S,
mut handler: T,
logger: L,
) -> Result<UdevBackend<H, S, T>>
where
L: Into<Option<::slog::Logger>>,
@ -81,7 +88,7 @@ impl<H: DrmHandler<SessionFdDrmDevice> + 'static, S: Session + 'static, T: UdevH
.flat_map(|path| {
match DrmDevice::new(
{
match session.open(&path, fcntl::O_RDWR | fcntl::O_CLOEXEC | fcntl::O_NOCTTY | fcntl::O_NONBLOCK) {
match session.open(&path, fcntl::OFlag::O_RDWR | fcntl::OFlag::O_CLOEXEC | fcntl::OFlag::O_NOCTTY | fcntl::OFlag::O_NONBLOCK) {
Ok(fd) => SessionFdDrmDevice(fd),
Err(err) => {
warn!(logger, "Unable to open drm device {:?}, Error: {:?}. Skipping", path, err);
@ -94,13 +101,13 @@ impl<H: DrmHandler<SessionFdDrmDevice> + 'static, S: Session + 'static, T: UdevH
Ok(mut device) => {
let devnum = device.device_id();
let fd = device.as_raw_fd();
match handler.device_added(evlh, &mut device) {
match handler.device_added(&mut device) {
Some(drm_handler) => {
match drm_device_bind(&mut evlh, device, drm_handler) {
Ok(event_source) => Some((devnum, event_source)),
match drm_device_bind(&token, device, drm_handler) {
Ok((event_source, device)) => Some((devnum, (event_source, device))),
Err((err, (mut device, _))) => {
warn!(logger, "Failed to bind device. Error: {:?}.", err);
handler.device_removed(evlh, &mut device);
handler.device_removed(&mut device);
drop(device);
if let Err(err) = session.close(fd) {
warn!(logger, "Failed to close dropped device. Error: {:?}. Ignoring", err);
@ -124,7 +131,7 @@ impl<H: DrmHandler<SessionFdDrmDevice> + 'static, S: Session + 'static, T: UdevH
}
}
})
.collect::<HashMap<dev_t, FdEventSource<(DrmDevice<SessionFdDrmDevice>, H)>>>();
.collect::<HashMap<dev_t, _>>();
let mut builder = MonitorBuilder::new(context).chain_err(|| ErrorKind::FailedToInitMonitor)?;
builder
@ -135,20 +142,25 @@ impl<H: DrmHandler<SessionFdDrmDevice> + 'static, S: Session + 'static, T: UdevH
.chain_err(|| ErrorKind::FailedToInitMonitor)?;
Ok(UdevBackend {
_handler: ::std::marker::PhantomData,
devices: Rc::new(RefCell::new(devices)),
monitor,
session,
handler,
logger,
token,
})
}
/// Closes the udev backend and frees all remaining open devices.
pub fn close(&mut self, evlh: &mut EventLoopHandle) {
pub fn close(&mut self) {
let mut devices = self.devices.borrow_mut();
for (_, event_source) in devices.drain() {
let (mut device, _) = event_source.remove();
self.handler.device_removed(evlh, &mut device);
for (_, (event_source, device)) in devices.drain() {
event_source.remove();
let mut device = Rc::try_unwrap(device)
.unwrap_or_else(|_| unreachable!())
.into_inner();
self.handler.device_removed(&mut device);
let fd = device.as_raw_fd();
drop(device);
if let Err(err) = self.session.close(fd) {
@ -163,8 +175,8 @@ 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)>>>>,
pub struct UdevBackendObserver {
devices: Weak<RefCell<HashMap<dev_t, (Source<FdEvent>, Rc<RefCell<DrmDevice<SessionFdDrmDevice>>>)>>>,
logger: ::slog::Logger,
}
@ -172,9 +184,9 @@ impl<
H: DrmHandler<SessionFdDrmDevice> + 'static,
S: Session + 'static,
T: UdevHandler<H> + 'static,
> AsSessionObserver<UdevBackendObserver<H>> for UdevBackend<H, S, T>
> AsSessionObserver<UdevBackendObserver> for UdevBackend<H, S, T>
{
fn observer(&mut self) -> UdevBackendObserver<H> {
fn observer(&mut self) -> UdevBackendObserver {
UdevBackendObserver {
devices: Rc::downgrade(&self.devices),
logger: self.logger.clone(),
@ -182,25 +194,21 @@ impl<
}
}
impl<H: DrmHandler<SessionFdDrmDevice> + 'static> SessionObserver for UdevBackendObserver<H> {
fn pause<'a>(&mut self, evlh: &mut EventLoopHandle, devnum: Option<(u32, u32)>) {
impl SessionObserver for UdevBackendObserver {
fn pause<'a>(&mut self, 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);
})
for &mut (_, ref device) in devices.borrow_mut().values_mut() {
info!(self.logger, "changed successful");
device.borrow_mut().observer().pause(devnum);
}
}
}
fn activate<'a>(&mut self, evlh: &mut EventLoopHandle, devnum: Option<(u32, u32, Option<RawFd>)>) {
fn activate<'a>(&mut self, 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);
})
for &mut (_, ref device) in devices.borrow_mut().values_mut() {
info!(self.logger, "changed successful");
device.borrow_mut().observer().activate(devnum);
}
}
}
@ -210,143 +218,154 @@ impl<H: DrmHandler<SessionFdDrmDevice> + 'static> SessionObserver for UdevBacken
///
/// Allows the backend to recieve kernel events and thus to drive the `UdevHandler`.
/// No runtime functionality can be provided without using this function.
pub fn udev_backend_bind<S, H, T>(
evlh: &mut EventLoopHandle, udev: UdevBackend<H, S, T>
) -> ::std::result::Result<FdEventSource<UdevBackend<H, S, T>>, (IoError, UdevBackend<H, S, T>)>
pub fn udev_backend_bind<H, S, T>(
token: &LoopToken,
udev: UdevBackend<H, S, T>,
) -> ::std::result::Result<Source<FdEvent>, (IoError, UdevBackend<H, S, T>)>
where
H: DrmHandler<SessionFdDrmDevice> + 'static,
T: UdevHandler<H> + 'static,
S: Session + 'static,
{
let fd = udev.monitor.as_raw_fd();
evlh.add_fd_event_source(fd, fd_event_source_implementation(), udev, FdInterest::READ)
token.add_fd_event_source(fd, FdInterest::READ, udev)
}
fn fd_event_source_implementation<S, H, T>() -> FdEventSourceImpl<UdevBackend<H, S, T>>
impl<H, S, T> Implementation<(), FdEvent> for UdevBackend<H, S, T>
where
H: DrmHandler<SessionFdDrmDevice> + 'static,
T: UdevHandler<H> + 'static,
S: Session + 'static,
{
FdEventSourceImpl {
ready: |mut evlh, udev, _, _| {
let events = udev.monitor.clone().collect::<Vec<Event>>();
for event in events {
match event.event_type() {
// New device
EventType::Add => {
info!(udev.logger, "Device Added");
if let (Some(path), Some(devnum)) = (event.devnode(), event.devnum()) {
let mut device = {
match DrmDevice::new(
{
let logger = udev.logger.clone();
match udev.session.open(
path,
fcntl::O_RDWR | fcntl::O_CLOEXEC | fcntl::O_NOCTTY
| fcntl::O_NONBLOCK,
) {
Ok(fd) => SessionFdDrmDevice(fd),
Err(err) => {
fn receive(&mut self, event: FdEvent, (): ()) {
match event {
FdEvent::Ready { .. } => {
let events = self.monitor.clone().collect::<Vec<Event>>();
for event in events {
match event.event_type() {
// New device
EventType::Add => {
info!(self.logger, "Device Added");
if let (Some(path), Some(devnum)) = (event.devnode(), event.devnum()) {
let mut device = {
match DrmDevice::new(
{
let logger = self.logger.clone();
match self.session.open(
path,
fcntl::OFlag::O_RDWR | fcntl::OFlag::O_CLOEXEC
| fcntl::OFlag::O_NOCTTY
| fcntl::OFlag::O_NONBLOCK,
) {
Ok(fd) => SessionFdDrmDevice(fd),
Err(err) => {
warn!(
logger,
"Unable to open drm device {:?}, Error: {:?}. Skipping",
path,
err
);
continue;
}
}
},
self.logger.clone(),
) {
Ok(dev) => dev,
Err(err) => {
warn!(
self.logger,
"Failed to initialize device {:?}. Error: {}. Skipping",
path,
err
);
continue;
}
}
};
let fd = device.as_raw_fd();
match self.handler.device_added(&mut device) {
Some(drm_handler) => {
match drm_device_bind(&self.token, device, drm_handler) {
Ok(fd_event_source) => {
self.devices.borrow_mut().insert(devnum, fd_event_source);
}
Err((err, (mut device, _))) => {
warn!(
logger,
"Unable to open drm device {:?}, Error: {:?}. Skipping",
path,
err
self.logger,
"Failed to bind device. Error: {:?}.", err
);
continue;
self.handler.device_removed(&mut device);
drop(device);
if let Err(err) = self.session.close(fd) {
warn!(
self.logger,
"Failed to close dropped device. Error: {:?}. Ignoring", err
);
};
}
}
},
udev.logger.clone(),
) {
Ok(dev) => dev,
Err(err) => {
warn!(
udev.logger,
"Failed to initialize device {:?}. Error: {}. Skipping",
path,
err
);
continue;
}
}
};
let fd = device.as_raw_fd();
match udev.handler.device_added(evlh, &mut device) {
Some(drm_handler) => match drm_device_bind(&mut evlh, device, drm_handler) {
Ok(fd_event_source) => {
udev.devices.borrow_mut().insert(devnum, fd_event_source);
}
Err((err, (mut device, _))) => {
warn!(udev.logger, "Failed to bind device. Error: {:?}.", err);
udev.handler.device_removed(evlh, &mut device);
None => {
self.handler.device_removed(&mut device);
drop(device);
if let Err(err) = udev.session.close(fd) {
if let Err(err) = self.session.close(fd) {
warn!(
udev.logger,
"Failed to close dropped device. Error: {:?}. Ignoring", err
self.logger,
"Failed to close unused device. Error: {:?}", 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
EventType::Remove => {
info!(udev.logger, "Device Remove");
if let Some(devnum) = event.devnum() {
if let Some(fd_event_source) = udev.devices.borrow_mut().remove(&devnum) {
let (mut device, _) = fd_event_source.remove();
udev.handler.device_removed(evlh, &mut device);
let fd = device.as_raw_fd();
drop(device);
if let Err(err) = udev.session.close(fd) {
warn!(
udev.logger,
"Failed to close device {:?}. Error: {:?}. Ignoring",
event.sysname(),
err
);
};
}
}
}
// New connector
EventType::Change => {
info!(udev.logger, "Device Changed");
if let Some(devnum) = event.devnum() {
info!(udev.logger, "Devnum: {:b}", devnum);
if let Some(fd_event_source) = udev.devices.borrow_mut().get_mut(&devnum) {
let handler = &mut udev.handler;
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 {
info!(udev.logger, "changed, but device not tracked by backend");
};
} else {
info!(udev.logger, "changed, but no devnum");
// Device removed
EventType::Remove => {
info!(self.logger, "Device Remove");
if let Some(devnum) = event.devnum() {
if let Some((fd_event_source, device)) =
self.devices.borrow_mut().remove(&devnum)
{
fd_event_source.remove();
let mut device = Rc::try_unwrap(device)
.unwrap_or_else(|_| unreachable!())
.into_inner();
self.handler.device_removed(&mut device);
let fd = device.as_raw_fd();
drop(device);
if let Err(err) = self.session.close(fd) {
warn!(
self.logger,
"Failed to close device {:?}. Error: {:?}. Ignoring",
event.sysname(),
err
);
};
}
}
}
// New connector
EventType::Change => {
info!(self.logger, "Device Changed");
if let Some(devnum) = event.devnum() {
info!(self.logger, "Devnum: {:b}", devnum);
if let Some(&(_, ref device)) = self.devices.borrow_mut().get(&devnum) {
let handler = &mut self.handler;
let logger = &self.logger;
handler.device_changed(&mut device.borrow_mut());
} else {
info!(self.logger, "changed, but device not tracked by backend");
};
} else {
info!(self.logger, "changed, but no devnum");
}
}
_ => {}
}
_ => {}
}
}
},
error: |evlh, udev, _, err| udev.handler.error(evlh, err),
FdEvent::Error { error, .. } => self.handler.error(error),
}
}
}
@ -358,9 +377,7 @@ pub trait UdevHandler<H: DrmHandler<SessionFdDrmDevice> + 'static> {
///
/// ## Panics
/// Panics if you try to borrow the token of the belonging `UdevBackend` using this `StateProxy`.
fn device_added(
&mut self, evlh: &mut EventLoopHandle, device: &mut DrmDevice<SessionFdDrmDevice>
) -> Option<H>;
fn device_added(&mut self, device: &mut DrmDevice<SessionFdDrmDevice>) -> Option<H>;
/// Called when an open device is changed.
///
/// This usually indicates that some connectors did become available or were unplugged. The handler
@ -368,7 +385,7 @@ pub trait UdevHandler<H: DrmHandler<SessionFdDrmDevice> + 'static> {
///
/// ## Panics
/// Panics if you try to borrow the token of the belonging `UdevBackend` using this `StateProxy`.
fn device_changed(&mut self, evlh: &mut EventLoopHandle, device: &mut DrmDevice<SessionFdDrmDevice>);
fn device_changed(&mut self, device: &mut DrmDevice<SessionFdDrmDevice>);
/// Called when a device was removed.
///
/// The device will not accept any operations anymore and its file descriptor will be closed once
@ -376,12 +393,12 @@ pub trait UdevHandler<H: DrmHandler<SessionFdDrmDevice> + 'static> {
///
/// ## Panics
/// Panics if you try to borrow the token of the belonging `UdevBackend` using this `StateProxy`.
fn device_removed(&mut self, evlh: &mut EventLoopHandle, device: &mut DrmDevice<SessionFdDrmDevice>);
fn device_removed(&mut self, device: &mut DrmDevice<SessionFdDrmDevice>);
/// Called when the udev context has encountered and error.
///
/// ## Panics
/// Panics if you try to borrow the token of the belonging `UdevBackend` using this `StateProxy`.
fn error(&mut self, evlh: &mut EventLoopHandle, error: IoError);
fn error(&mut self, error: IoError);
}
/// Returns the path of the primary gpu device if any