Add documentation

This commit is contained in:
Drakulix 2017-11-29 20:00:16 +01:00
parent 0350dca972
commit 13be5b1634
7 changed files with 237 additions and 45 deletions

View File

@ -375,6 +375,7 @@ impl DrmBackend {
Ok(()) Ok(())
} }
/// Returns the crtc id used by this backend
pub fn crtc(&self) -> crtc::Handle { pub fn crtc(&self) -> crtc::Handle {
self.crtc self.crtc
} }

View File

@ -457,14 +457,20 @@ impl<B: From<DrmBackend> + Borrow<DrmBackend> + 'static> DrmDevice<B> {
Ok(self.backends.get(&crtc).unwrap()) Ok(self.backends.get(&crtc).unwrap())
} }
/// Get the current backend for a given crtc if any
pub fn backend_for_crtc(&self, crtc: &crtc::Handle) -> Option<&StateToken<B>> { pub fn backend_for_crtc(&self, crtc: &crtc::Handle) -> Option<&StateToken<B>> {
self.backends.get(crtc) self.backends.get(crtc)
} }
/// Get all belonging backends
pub fn current_backends(&self) -> Vec<&StateToken<B>> { pub fn current_backends(&self) -> Vec<&StateToken<B>> {
self.backends.values().collect() self.backends.values().collect()
} }
/// Destroy the backend using a given crtc if any
///
/// ## Panics
/// Panics if the backend is already borrowed from the state
pub fn destroy_backend<'a, S>(&mut self, state: S, crtc: &crtc::Handle) pub fn destroy_backend<'a, S>(&mut self, state: S, crtc: &crtc::Handle)
where where
S: Into<StateProxy<'a>> S: Into<StateProxy<'a>>
@ -474,6 +480,11 @@ impl<B: From<DrmBackend> + Borrow<DrmBackend> + 'static> DrmDevice<B> {
} }
} }
/// Close the device
///
/// ## Warning
/// Never call this function if the device is managed by another backend e.g. the `UdevBackend`.
/// Only use this function for manually initialized devices.
pub fn close(self) -> NixResult<()> { pub fn close(self) -> NixResult<()> {
let fd = self.as_raw_fd(); let fd = self.as_raw_fd();
mem::drop(self); mem::drop(self);
@ -517,12 +528,20 @@ pub trait DrmHandler<B: Borrow<DrmBackend> + 'static> {
/// ///
/// The `id` argument is the `Id` of the `DrmBackend` that finished rendering, /// The `id` argument is the `Id` of the `DrmBackend` that finished rendering,
/// check using `DrmBackend::is`. /// check using `DrmBackend::is`.
///
/// ## Panics
/// The device is already borrowed from the given `state`. Borrowing it again will panic
/// and is not necessary as it is already provided via the `device` parameter.
fn ready<'a, S: Into<StateProxy<'a>>>(&mut self, state: S, device: &mut DrmDevice<B>, backend: &StateToken<B>, fn ready<'a, S: Into<StateProxy<'a>>>(&mut self, state: S, device: &mut DrmDevice<B>, backend: &StateToken<B>,
crtc: crtc::Handle, frame: u32, duration: Duration); 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..
///
/// ## Panics
/// The device is already borrowed from the given `state`. Borrowing it again will panic
/// and is not necessary as it is already provided via the `device` parameter.
fn error<'a, S: Into<StateProxy<'a>>>(&mut self, state: S, device: &mut DrmDevice<B>, error: DrmError); fn error<'a, S: Into<StateProxy<'a>>>(&mut self, state: S, device: &mut DrmDevice<B>, error: DrmError);
} }
@ -610,6 +629,5 @@ impl<B: Borrow<DrmBackend> + 'static> SessionObserver for StateToken<DrmDevice<B
} }
} }
}) })
} }
} }

View File

@ -566,6 +566,8 @@ impl SessionObserver for libinput::Libinput {
} }
} }
/// Wrapper for types implementing the `Session` trait to provide
/// a `LibinputInterface` implementation.
pub struct LibinputSessionInterface<S: Session>(S); pub struct LibinputSessionInterface<S: Session>(S);
impl<S: Session> From<S> for LibinputSessionInterface<S> { impl<S: Session> From<S> for LibinputSessionInterface<S> {
@ -585,6 +587,10 @@ impl<S: Session> libinput::LibinputInterface for LibinputSessionInterface<S> {
} }
} }
/// Binds a `LibinputInputBackend` to a given `EventLoop`.
///
/// Automatically feeds the backend with incoming events without any manual calls to
/// `dispatch_new_events`. Should be used to achieve the smallest possible latency.
pub fn libinput_bind(backend: LibinputInputBackend, evlh: &mut EventLoopHandle) pub fn libinput_bind(backend: LibinputInputBackend, evlh: &mut EventLoopHandle)
-> IoResult<FdEventSource<LibinputInputBackend>> -> IoResult<FdEventSource<LibinputInputBackend>>
{ {

View File

@ -1,3 +1,51 @@
//!
//! Implementation of the `Session` trait through the legacy vt kernel interface.
//!
//! This requires write permissions for the given tty device and any devices opened through this
//! interface. This means it will almost certainly require root permissions and not allow to run
//! the compositor as an unpriviledged user. Use this session type *only* as a fallback or for testing,
//! if anything better is available.
//!
//! ## How to use it
//!
//! ### Initialization
//!
//! To initialize the session you may pass the path to any tty device, that shall be used.
//! If no path is given the tty used to start this compositor (if any) will be used.
//! A new session and its notifier will be returned.
//!
//! ```rust,no_run
//! extern crate smithay;
//!
//! use smithay::backend::session::direct::DirectSession;
//!
//! # fn main() {
//! let (session, mut notifier) = DirectSession::new(None, None).unwrap();
//! # }
//! ```
//!
//! ### Usage of the session
//!
//! The session may be used to open devices manually through the `Session` interface
//! or be passed to other object that need to open devices themselves.
//!
//! Examples for those are e.g. the `LibinputInputBackend` (its context might be initialized through a
//! `Session` via the `LibinputSessionInterface`) or the `UdevBackend`.
//!
//! In case you want to pass the same `Session` to multiple objects, `Session` is implement for
//! every `Rc<RefCell<Session>>` or `Arc<Mutex<Session>>`.
//!
//! ### Usage of the session notifier
//!
//! The notifier might be used to pause device access, when the session gets paused (e.g. by
//! switching the tty via `DirectSession::change_vt`) and to automatically enable it again,
//! when the session becomes active again.
//!
//! It is crutial to avoid errors during that state. Examples for object that might be registered
//! for notifications are the `Libinput` context, the `UdevBackend` or a `DrmDevice` (handled
//! automatically by the `UdevBackend`, if not done manually).
//! ```
use std::io::Result as IoResult; use std::io::Result as IoResult;
use std::path::Path; use std::path::Path;
use std::os::unix::io::RawFd; use std::os::unix::io::RawFd;
@ -17,6 +65,7 @@ use libudev::Context;
use super::{AsErrno, Session, SessionNotifier, SessionObserver}; use super::{AsErrno, Session, SessionNotifier, SessionObserver};
#[allow(dead_code)]
mod tty { mod tty {
ioctl!(bad read kd_get_mode with 0x4B3B; i16); ioctl!(bad read kd_get_mode with 0x4B3B; i16);
ioctl!(bad write_int kd_set_mode with 0x4B3A); ioctl!(bad write_int kd_set_mode with 0x4B3A);
@ -59,60 +108,17 @@ mod tty {
} }
} }
// on freebsd and dragonfly
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
const DRM_MAJOR: u64 = 145;
// on netbsd
#[cfg(target_os = "netbsd")]
const DRM_MAJOR: u64 = 34;
// on openbsd (32 & 64 bit)
#[cfg(all(target_os = "openbsd", target_pointer_width = "32"))]
const DRM_MAJOR: u64 = 88;
#[cfg(all(target_os = "openbsd", target_pointer_width = "64"))]
const DRM_MAJOR: u64 = 87;
// on linux/android
#[cfg(any(target_os = "linux", target_os = "android"))]
const DRM_MAJOR: u64 = 226;
#[cfg(any(target_os = "linux", target_os = "android"))] #[cfg(any(target_os = "linux", target_os = "android"))]
const TTY_MAJOR: u64 = 4; const TTY_MAJOR: u64 = 4;
#[cfg(not(any(target_os = "linux", target_os = "android")))] #[cfg(not(any(target_os = "linux", target_os = "android")))]
const TTY_MAJOR: u64 = 0; const TTY_MAJOR: u64 = 0;
#[cfg(not(feature = "backend_session_udev"))]
fn is_drm_device(dev: dev_t, _path: &Path) -> bool {
major(dev) == DRM_MAJOR
}
#[cfg(not(feature = "backend_session_udev"))] #[cfg(not(feature = "backend_session_udev"))]
fn is_tty_device(dev: dev_t, _path: Option<&Path>) -> bool { fn is_tty_device(dev: dev_t, _path: Option<&Path>) -> bool {
major(dev) == TTY_MAJOR major(dev) == TTY_MAJOR
} }
#[cfg(feature = "backend_session_udev")]
fn is_drm_device(dev: dev_t, path: &Path) -> bool {
let udev = match Context::new() {
Ok(context) => context,
Err(_) => return major(dev) == DRM_MAJOR,
};
let device = match udev.device_from_syspath(path) {
Ok(device) => device,
Err(_) => return major(dev) == DRM_MAJOR,
};
if let Some(subsystem) = device.subsystem() {
subsystem == "drm"
} else {
major(dev) == DRM_MAJOR
}
}
#[cfg(feature = "backend_session_udev")] #[cfg(feature = "backend_session_udev")]
fn is_tty_device(dev: dev_t, path: Option<&Path>) -> bool { fn is_tty_device(dev: dev_t, path: Option<&Path>) -> bool {
match path { match path {
@ -138,6 +144,7 @@ fn is_tty_device(dev: dev_t, path: Option<&Path>) -> bool {
} }
} }
/// `Session` via the virtual terminal direct kernel interface
pub struct DirectSession { pub struct DirectSession {
tty: RawFd, tty: RawFd,
active: Arc<AtomicBool>, active: Arc<AtomicBool>,
@ -146,6 +153,7 @@ pub struct DirectSession {
logger: ::slog::Logger, logger: ::slog::Logger,
} }
/// `SessionNotifier` via the virtual terminal direct kernel interface
pub struct DirectSessionNotifier { pub struct DirectSessionNotifier {
tty: RawFd, tty: RawFd,
active: Arc<AtomicBool>, active: Arc<AtomicBool>,
@ -155,6 +163,9 @@ pub struct DirectSessionNotifier {
} }
impl DirectSession { impl DirectSession {
/// Tries to creates a new session via the legacy virtual terminal interface.
///
/// If you do not provide a tty device path, it will try to open the currently active tty if any.
pub fn new<L>(tty: Option<&Path>, logger: L) -> Result<(DirectSession, DirectSessionNotifier)> pub fn new<L>(tty: Option<&Path>, logger: L) -> Result<(DirectSession, DirectSessionNotifier)>
where where
L: Into<Option<::slog::Logger>> L: Into<Option<::slog::Logger>>
@ -244,6 +255,11 @@ impl DirectSession {
Ok((vt_num, old_keyboard_mode, signal)) Ok((vt_num, old_keyboard_mode, signal))
} }
/// Get the number of the virtual terminal used by this session
pub fn vt(&self) -> i32 {
self.vt
}
} }
impl Session for DirectSession { impl Session for DirectSession {
@ -323,6 +339,11 @@ impl SessionNotifier for DirectSessionNotifier {
} }
} }
/// Bind a `DirectSessionNotifier` to an `EventLoop`.
///
/// Allows the `DirectSessionNotifier` to listen for the incoming signals signalling the session state.
/// If you don't use this function `DirectSessionNotifier` will not correctly tell you the current
/// session state.
pub fn direct_session_bind<L>(notifier: DirectSessionNotifier, evlh: &mut EventLoopHandle, _logger: L) pub fn direct_session_bind<L>(notifier: DirectSessionNotifier, evlh: &mut EventLoopHandle, _logger: L)
-> IoResult<SignalEventSource<DirectSessionNotifier>> -> IoResult<SignalEventSource<DirectSessionNotifier>>
where where
@ -332,6 +353,7 @@ where
evlh.add_signal_event_source(|evlh, notifier, _| { evlh.add_signal_event_source(|evlh, notifier, _| {
if notifier.is_active() { if notifier.is_active() {
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 {signal.pause(&mut evlh.state().as_proxy()); } if let &mut Some(ref mut signal) = signal {signal.pause(&mut evlh.state().as_proxy()); }
} }
@ -339,7 +361,9 @@ where
unsafe { unsafe {
tty::vt_rel_disp(notifier.tty, 1).expect("Unable to release tty lock"); tty::vt_rel_disp(notifier.tty, 1).expect("Unable to release tty lock");
} }
debug!(notifier.logger, "Session is now inactive");
} else { } else {
debug!(notifier.logger, "Session will become active again");
unsafe { unsafe {
tty::vt_rel_disp(notifier.tty, tty::VT_ACKACQ).expect("Unable to acquire tty lock"); tty::vt_rel_disp(notifier.tty, tty::VT_ACKACQ).expect("Unable to acquire tty lock");
} }
@ -347,6 +371,7 @@ where
if let &mut Some(ref mut signal) = signal { signal.activate(&mut evlh.state().as_proxy()); } if let &mut Some(ref mut signal) = signal { signal.activate(&mut evlh.state().as_proxy()); }
} }
notifier.active.store(true, Ordering::SeqCst); notifier.active.store(true, Ordering::SeqCst);
info!(notifier.logger, "Session is now active again");
} }
}, notifier, signal) }, notifier, signal)
} }

View File

@ -0,0 +1,27 @@
use dbus::{BusType, Connection as DbusConnection};
use systemd::login as logind;
pub struct LogindSession {
dbus: DbusConnection,
}
impl Session for LogindSession {
}
impl LogindSession {
pub fn new() -> Result<LogindSession> {
let session = logind::get_session(None)?;
let vt = logind::get_vt(&session)?;
let seat = logind::get_seat(&session)?;
let dbus = DbusConnection::get_private(BusType::System)?;
}
}
error_chain! {
errors {
}
}

View File

@ -1,3 +1,15 @@
//!
//! Abstraction of different session apis.
//!
//! Sessions provide a way for multiple graphical systems to run in parallel by providing
//! mechanisms to switch between and handle device access and permissions for every running
//! instance.
//!
//! They are crutial to allow unpriviledged processes to use graphical or input devices.
//!
//! The following mechanisms are currently provided:
//! - direct - legacy tty / virtual terminal kernel api
//!
use std::path::Path; use std::path::Path;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use std::rc::Rc; use std::rc::Rc;
@ -6,28 +18,62 @@ use std::os::unix::io::RawFd;
use nix::fcntl::OFlag; use nix::fcntl::OFlag;
use wayland_server::StateProxy; use wayland_server::StateProxy;
/// General session interface.
///
/// Provides a way to open and close devices and change the active vt.
pub trait Session { pub trait Session {
/// Error type of the implementation
type Error: AsErrno; type Error: AsErrno;
/// Opens a device at the given `path` with the given flags.
///
/// Returns a raw file descriptor
fn open(&mut self, path: &Path, flags: OFlag) -> Result<RawFd, Self::Error>; fn open(&mut self, path: &Path, flags: OFlag) -> Result<RawFd, Self::Error>;
/// Close a previously opened file descriptor
fn close(&mut self, fd: RawFd) -> Result<(), Self::Error>; fn close(&mut self, fd: RawFd) -> Result<(), Self::Error>;
/// Change the currently active virtual terminal
fn change_vt(&mut self, vt: i32) -> Result<(), Self::Error>; fn change_vt(&mut self, vt: i32) -> Result<(), Self::Error>;
/// Check if this session is currently active
fn is_active(&self) -> bool; fn is_active(&self) -> bool;
/// Which seat this session is on
fn seat(&self) -> String; fn seat(&self) -> String;
} }
/// Interface for registering for notifications for a given session.
///
/// Part of the session api which allows to get notified, when the given session
/// gets paused or becomes active again. Any object implementing the `SessionObserver` trait
/// may be registered.
pub trait SessionNotifier { pub trait SessionNotifier {
/// Registers a given `SessionObserver`.
///
/// Returns an id of the inserted observer, can be used to remove it again.
fn register<S: SessionObserver + 'static>(&mut self, signal: S) -> usize; fn register<S: SessionObserver + 'static>(&mut self, signal: S) -> usize;
/// Removes an observer by its given id from `SessionNotifier::register`.
fn unregister(&mut self, signal: usize); fn unregister(&mut self, signal: usize);
/// Check if this session is currently active
fn is_active(&self) -> bool; fn is_active(&self) -> bool;
/// Which seat this session is on
fn seat(&self) -> &str; fn seat(&self) -> &str;
} }
/// Trait describing the ability to be notified when the session pauses or becomes active again.
///
/// It might be impossible to interact with devices while the session is disabled.
/// This interface provides callbacks for when that happens.
pub trait SessionObserver { pub trait SessionObserver {
/// Session is about to be paused.
///
/// In case the implementor is a `StateToken` the state of the `EventLoop`
/// is provided via a `StateProxy`.
fn pause<'a>(&mut self, state: &mut StateProxy<'a>); fn pause<'a>(&mut self, state: &mut StateProxy<'a>);
/// Session got active again
///
/// In case the implementor is a `StateToken` the state of the `EventLoop`
/// is provided via a `StateProxy`.
fn activate<'a>(&mut self, state: &mut StateProxy<'a>); fn activate<'a>(&mut self, state: &mut StateProxy<'a>);
} }
@ -91,7 +137,9 @@ impl<S: Session> Session for Arc<Mutex<S>> {
} }
} }
/// Allows errors to be described by an error number
pub trait AsErrno: ::std::fmt::Debug { pub trait AsErrno: ::std::fmt::Debug {
/// Returns the error number representing this error if any
fn as_errno(&self) -> Option<i32>; fn as_errno(&self) -> Option<i32>;
} }

View File

@ -1,3 +1,14 @@
//!
//! Provides `udev` related functionality for automated device scanning.
//!
//! This module mainly provides the `UdevBackend`, which constantly monitors available drm devices
//! and notifies a user supplied `UdevHandler` of any changes.
//!
//! Additionally this contains some utility functions related to scanning.
//!
//! See also `examples/udev.rs` for pure hardware backed example of a compositor utilizing this
//! backend.
use libudev::{Context, MonitorBuilder, MonitorSocket, Event, EventType, Enumerator, Result as UdevResult}; use libudev::{Context, MonitorBuilder, MonitorSocket, Event, EventType, Enumerator, Result as UdevResult};
use nix::fcntl; use nix::fcntl;
use nix::sys::stat::{dev_t, fstat}; use nix::sys::stat::{dev_t, fstat};
@ -14,6 +25,11 @@ use wayland_server::sources::{FdEventSource, FdEventSourceImpl, FdInterest};
use ::backend::drm::{DrmDevice, DrmBackend, DrmHandler, drm_device_bind}; use ::backend::drm::{DrmDevice, DrmBackend, DrmHandler, drm_device_bind};
use ::backend::session::{Session, SessionObserver}; use ::backend::session::{Session, SessionObserver};
/// Graphical backend that monitors available drm devices.
///
/// Provides a way to automatically initialize a `DrmDevice` for available gpus and notifies the
/// given handler of any changes. Can be used to provide hot-plug functionality for gpus and
/// attached monitors.
pub struct UdevBackend<B: Borrow<DrmBackend> + 'static, H: DrmHandler<B> + 'static, S: Session + 'static, T: UdevHandler<B, H> + 'static> { pub struct UdevBackend<B: Borrow<DrmBackend> + 'static, H: DrmHandler<B> + 'static, S: Session + 'static, T: UdevHandler<B, H> + 'static> {
devices: HashMap<dev_t, (StateToken<DrmDevice<B>>, FdEventSource<(StateToken<DrmDevice<B>>, H)>)>, devices: HashMap<dev_t, (StateToken<DrmDevice<B>>, FdEventSource<(StateToken<DrmDevice<B>>, H)>)>,
monitor: MonitorSocket, monitor: MonitorSocket,
@ -23,6 +39,14 @@ pub struct UdevBackend<B: Borrow<DrmBackend> + 'static, H: DrmHandler<B> + 'stat
} }
impl<B: From<DrmBackend> + Borrow<DrmBackend> + 'static, H: DrmHandler<B> + 'static, S: Session + 'static, T: UdevHandler<B, H> + 'static> UdevBackend<B, H, S, T> { impl<B: From<DrmBackend> + Borrow<DrmBackend> + 'static, H: DrmHandler<B> + 'static, S: Session + 'static, T: UdevHandler<B, H> + 'static> UdevBackend<B, H, S, T> {
/// Creates a new `UdevBackend` and adds it to the given `EventLoop`'s state.
///
/// ## Arguments
/// `evlh` - An event loop to use for binding `DrmDevices`
/// `context` - An initialized udev context
/// `session` - A session used to open and close devices as they become available
/// `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, pub fn new<'a, L>(mut evlh: &mut EventLoopHandle,
context: &Context, context: &Context,
mut session: S, mut session: S,
@ -113,6 +137,14 @@ impl<B: From<DrmBackend> + Borrow<DrmBackend> + 'static, H: DrmHandler<B> + 'sta
})) }))
} }
/// Closes the udev backend and frees all remaining open devices.
///
/// Needs to be called after the `FdEventSource` was removed and the backend was removed from
/// the `EventLoop`'s `State`.
///
/// ## Panics
/// 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) { pub fn close<'a, ST: Into<StateProxy<'a>>>(mut self, state: ST) {
let mut state = state.into(); let mut state = state.into();
for (_, (mut device, event_source)) in self.devices.drain() { for (_, (mut device, event_source)) in self.devices.drain() {
@ -147,6 +179,10 @@ impl<B: Borrow<DrmBackend> + 'static, H: DrmHandler<B> + 'static, S: Session + '
} }
} }
/// Binds a `UdevBackend` to a given `EventLoop`.
///
/// 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<B, S, H, T>(evlh: &mut EventLoopHandle, udev: StateToken<UdevBackend<B, H, S, T>>) pub fn udev_backend_bind<B, S, H, T>(evlh: &mut EventLoopHandle, udev: StateToken<UdevBackend<B, H, S, T>>)
-> IoResult<FdEventSource<StateToken<UdevBackend<B, H, S, T>>>> -> IoResult<FdEventSource<StateToken<UdevBackend<B, H, S, T>>>>
where where
@ -275,13 +311,41 @@ where
} }
} }
/// Handler for the `UdevBackend`, allows to open, close and update drm devices as they change during runtime.
pub trait UdevHandler<B: Borrow<DrmBackend> + 'static, H: DrmHandler<B> + 'static> { pub trait UdevHandler<B: Borrow<DrmBackend> + 'static, H: DrmHandler<B> + 'static> {
/// Called on initialization for every known device and when a new device is detected.
///
/// Returning a `DrmHandler` will initialize the device, returning `None` will ignore the device.
///
/// ## Panics
/// Panics if you try to borrow the token of the belonging `UdevBackend` using this `StateProxy`.
fn device_added<'a, S: Into<StateProxy<'a>>>(&mut self, state: S, device: &mut DrmDevice<B>) -> Option<H>; fn device_added<'a, S: Into<StateProxy<'a>>>(&mut self, state: S, device: &mut DrmDevice<B>) -> Option<H>;
/// Called when an open device is changed.
///
/// This usually indicates that some connectors did become available or were unplugged. The handler
/// should scan again for connected monitors and mode switch accordingly.
///
/// ## Panics
/// Panics if you try to borrow the token of the belonging `UdevBackend` using this `StateProxy`.
fn device_changed<'a, S: Into<StateProxy<'a>>>(&mut self, state: S, device: &StateToken<DrmDevice<B>>); fn device_changed<'a, S: Into<StateProxy<'a>>>(&mut self, state: S, device: &StateToken<DrmDevice<B>>);
/// Called when a device was removed.
///
/// The device will not accept any operations anymore and its file descriptor will be closed once
/// this function returns, any open references/tokens to this device need to be released.
///
/// ## Panics
/// Panics if you try to borrow the token of the belonging `UdevBackend` using this `StateProxy`.
fn device_removed<'a, S: Into<StateProxy<'a>>>(&mut self, state: S, device: &StateToken<DrmDevice<B>>); fn device_removed<'a, S: Into<StateProxy<'a>>>(&mut self, state: S, device: &StateToken<DrmDevice<B>>);
/// 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<'a, S: Into<StateProxy<'a>>>(&mut self, state: S, error: IoError); fn error<'a, S: Into<StateProxy<'a>>>(&mut self, state: S, error: IoError);
} }
/// Returns the path of the primary gpu device if any
///
/// Might be used for filtering in `UdevHandler::device_added` or for manual `DrmDevice` initialization
pub fn primary_gpu<S: AsRef<str>>(context: &Context, seat: S) -> UdevResult<Option<PathBuf>> { pub fn primary_gpu<S: AsRef<str>>(context: &Context, seat: S) -> UdevResult<Option<PathBuf>> {
let mut enumerator = Enumerator::new(context)?; let mut enumerator = Enumerator::new(context)?;
enumerator.match_subsystem("drm")?; enumerator.match_subsystem("drm")?;
@ -304,6 +368,9 @@ pub fn primary_gpu<S: AsRef<str>>(context: &Context, seat: S) -> UdevResult<Opti
Ok(result.and_then(|device| device.devnode().map(PathBuf::from))) Ok(result.and_then(|device| device.devnode().map(PathBuf::from)))
} }
/// Returns the paths of all available gpu devices
///
/// Might be used for manual `DrmDevice` initialization
pub fn all_gpus<S: AsRef<str>>(context: &Context, seat: S) -> UdevResult<Vec<PathBuf>> { pub fn all_gpus<S: AsRef<str>>(context: &Context, seat: S) -> UdevResult<Vec<PathBuf>> {
let mut enumerator = Enumerator::new(context)?; let mut enumerator = Enumerator::new(context)?;
enumerator.match_subsystem("drm")?; enumerator.match_subsystem("drm")?;