<NME> mod.rs
<BEF> //! 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 crucial to allow unprivileged processes to use graphical or input
//! devices.
//!
//! The functions of the provided interfaces lies in two main components: the ability to
//! open privileged devices, and be notified about when the session is paused and resumed
//! (for example when the user switches to an other TTY, or is the computer goes to sleep).
//!
//! ## General use
//!
//! Session handling in Smithay is done through a pair of types that each session provider implements.
//!
//! The first is a handle implementing the [`Session`] trait, which allows you to request the opening
//! of devices, a VT change, or information about the session state.
//!
//! The second is a notifier which informs you when the session is enabled or disabled by the system.
//! This notifier takes the form of a [`calloop`] event source, but it does not generates any event
//! directly. Instead, it gives you a [`Signaler`](crate::utils::signaling::Signaler) that you can
//! pass around to other backend modules that need to be notified of the new session state, to stop
//! accessing the devices while the session is disabled. Notable examples are the
//! [`libinput`](super::libinput) and [`drm`](super::drm) backends.
//!
//! ## Available providers
//!
//! This module provides session implementations based on different providers:
//!
//! - Through [libseat](https://sr.ht/~kennylevinsen/seatd/), gated by the `backend_session_libseat`
//!   cargo feature
//! - Through logind or elogind, gated by the `backend_session_logind` and `backend_session_elogind`
//!   cargo features (which are incompatible with each other)
//! - Through the direct kernel VT interface. This last option is intended as a fallback, as this is
//!   a legacy API.
//!
//! In general, you'll want to use the [`auto`] wrapper, that automatically discovers which
//! provider is available and selects the "best" one (in the order of the previous list). See the
//! module-level documentation of each provider for its precise usage.

use nix::fcntl::OFlag;
    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 {
    /// Id type of registered observers
    type Id: PartialEq + Eq;

    /// 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) -> Self::Id;
    /// Removes an observer by its given id from [`SessionNotifier::register`].
    fn unregister(&mut self, signal: Self::Id);
}

/// Trait describing the ability to return a [`SessionObserver`] related to Self.
///
/// The returned [`SessionObserver`] is responsible to handle the [`pause`](SessionObserver::pause)
/// and [`activate`](SessionObserver::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.
///
/// It might be impossible to interact with devices while the session is disabled.
/// This interface provides callbacks for when that happens.
pub trait SessionObserver {
    /// Session/Device is about to be paused.
    ///
    /// If only a specific device shall be closed a device number in the form of
    /// (major, minor) is provided. All observers not using the specified device should
    /// ignore the signal in that case.
    fn pause(&mut self, device: Option<(u32, u32)>);
    /// Session/Device got active again
    ///
    /// If only a specific device shall be activated again a device number in the form of
    /// `(major, major, Option<RawFd>)` is provided. Optionally the session may decide to replace
    /// the currently open file descriptor of the device with a new one. In that case the old one
    /// should not be used anymore and be closed. All observers not using the specified device should
    /// ignore the signal in that case.
    fn activate(&mut self, device: Option<(u32, u32, Option<RawFd>)>);
}

impl Session for () {
    ///
    /// All devices should be considered as paused
    PauseSession,
    /// A given device has been paused
    PauseDevice {
        /// Major number identifying the device
        major: u32,
        /// Minor number identifying the device
        minor: u32,
    },
    /// The whole session has been activated
    ActivateSession,
    /// A given device has been activated
    ActivateDevice {
        /// Major number identifying the device
        major: u32,
        /// Minor number identifying the device
        minor: u32,
        /// New file descriptor for accessing the device
        ///
        /// If it is not `None`, you should use this FD in place of the
        /// previous one for accessing this device. In case the old FD
        /// is different from the new one, the old one should be closed.
        new_fd: Option<RawFd>,
    },
}

impl Session for () {
    type Error = ();

    fn open(&mut self, _path: &Path, _flags: OFlag) -> Result<RawFd, Self::Error> {
        Err(())
    }
    fn close(&mut self, _fd: RawFd) -> Result<(), Self::Error> {
        Err(())
    }

    fn change_vt(&mut self, _vt: i32) -> Result<(), Self::Error> {
        Err(())
    }

    fn is_active(&self) -> bool {
        false
    }
    fn seat(&self) -> String {
        String::from("seat0")
    }
}

impl<S: Session> Session for Rc<RefCell<S>> {
    type Error = S::Error;

    fn open(&mut self, path: &Path, flags: OFlag) -> Result<RawFd, Self::Error> {
        self.borrow_mut().open(path, flags)
    }

    fn close(&mut self, fd: RawFd) -> Result<(), Self::Error> {
        self.borrow_mut().close(fd)
    }

    fn change_vt(&mut self, vt: i32) -> Result<(), Self::Error> {
        self.borrow_mut().change_vt(vt)
    }

    fn is_active(&self) -> bool {
        self.borrow().is_active()
    }

    fn seat(&self) -> String {
        self.borrow().seat()
    }
}

impl<S: Session> Session for Arc<Mutex<S>> {
    type Error = S::Error;

    fn open(&mut self, path: &Path, flags: OFlag) -> Result<RawFd, Self::Error> {
        self.lock().unwrap().open(path, flags)
    }

    fn close(&mut self, fd: RawFd) -> Result<(), Self::Error> {
        self.lock().unwrap().close(fd)
mod dbus;
pub mod direct;
pub use self::dbus::*;
mod multi;
pub use self::multi::*;
        self.lock().unwrap().change_vt(vt)
    }

    fn is_active(&self) -> bool {
        self.lock().unwrap().is_active()
    }

    fn seat(&self) -> String {
        self.lock().unwrap().seat()
    }
}

/// Allows errors to be described by an error number
pub trait AsErrno: ::std::fmt::Debug {
    /// Returns the error number representing this error if any
    fn as_errno(&self) -> Option<i32>;
}

impl AsErrno for () {
    fn as_errno(&self) -> Option<i32> {
        None
    }
}

pub mod auto;
pub mod direct;
#[cfg(feature = "backend_session_libseat")]
pub mod libseat;

#[cfg(feature = "backend_session_logind")]
mod dbus;
#[cfg(feature = "backend_session_logind")]
pub use self::dbus::*;

<MSG> backend.session: Migrate to using Signaler

Change the session backend to rely on Signaler to propagate its
signals. Also introduce the Linkable trait to allow generic composition
of objects needing to listen for signals.

<DFF> @@ -42,57 +42,39 @@ pub trait Session {
     fn seat(&self) -> String;
 }
 
-/// Interface for registering for notifications for a given session.
+/// Signals that can be generated by a session
 ///
-/// Part of the session API which allows to get notified, when the given session
-/// gets paused or becomes active again. Any object implementing the [`SessionObserver`]
-/// trait may be registered.
-pub trait SessionNotifier {
-    /// Id type of registered observers
-    type Id: PartialEq + Eq;
-
-    /// Registers a given [`SessionObserver`].
+/// Objects that need to be notifier about activation and deactivation
+/// of devices need to be linked to the `Signaler` of the session providing
+/// these signals.
+#[derive(Copy, Clone, Debug)]
+pub enum Signal {
+    /// The whole session has been paused
     ///
-    /// 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;
-    /// Removes an observer by its given id from [`SessionNotifier::register`].
-    fn unregister(&mut self, signal: Self::Id);
-}
-
-/// Trait describing the ability to return a [`SessionObserver`] related to Self.
-///
-/// The returned [`SessionObserver`] is responsible to handle the [`pause`](SessionObserver::pause)
-/// and [`activate`](SessionObserver::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.
-///
-/// It might be impossible to interact with devices while the session is disabled.
-/// This interface provides callbacks for when that happens.
-pub trait SessionObserver {
-    /// Session/Device is about to be paused.
-    ///
-    /// If only a specific device shall be closed a device number in the form of
-    /// (major, minor) is provided. All observers not using the specified device should
-    /// ignore the signal in that case.
-    fn pause(&mut self, device: Option<(u32, u32)>);
-    /// Session/Device got active again
-    ///
-    /// If only a specific device shall be activated again a device number in the form of
-    /// `(major, major, Option<RawFd>)` is provided. Optionally the session may decide to replace
-    /// the currently open file descriptor of the device with a new one. In that case the old one
-    /// should not be used anymore and be closed. All observers not using the specified device should
-    /// ignore the signal in that case.
-    fn activate(&mut self, device: Option<(u32, u32, Option<RawFd>)>);
+    /// All devices should be considered as paused
+    PauseSession,
+    /// A given device has been paused
+    PauseDevice {
+        /// Major number identifying the device
+        major: u32,
+        /// Minor number identifying the device
+        minor: u32,
+    },
+    /// The whole session has been activated
+    ActivateSession,
+    /// A given device has been activated
+    ActivateDevice {
+        /// Major number identifying the device
+        major: u32,
+        /// Minor number identifying the device
+        minor: u32,
+        /// New file descriptor for accessing the device
+        ///
+        /// If it is not `None`, you should use this FD in place of the
+        /// previous one for accessing this device. In case the old FD
+        /// is different from the new one, the old one should be closed.
+        new_fd: Option<RawFd>,
+    },
 }
 
 impl Session for () {
@@ -181,5 +163,3 @@ pub mod auto;
 mod dbus;
 pub mod direct;
 pub use self::dbus::*;
-mod multi;
-pub use self::multi::*;

backend.session: Migrate to using Signaler