From 20e10612b9efa3994c45c113546682c381c50ba8 Mon Sep 17 00:00:00 2001 From: Drakulix Date: Sat, 27 Jan 2018 13:38:21 +0100 Subject: [PATCH] Add documentation for logind/auto session --- src/backend/session/auto.rs | 60 +++++++++++++++++++++++++-- src/backend/session/dbus/logind.rs | 66 +++++++++++++++++++++++++----- src/backend/session/direct.rs | 8 ++-- 3 files changed, 116 insertions(+), 18 deletions(-) diff --git a/src/backend/session/auto.rs b/src/backend/session/auto.rs index 3540952..b9bac5b 100644 --- a/src/backend/session/auto.rs +++ b/src/backend/session/auto.rs @@ -1,3 +1,34 @@ +//! +//! Implementation of the `Session` trait through various implementations +//! automatically choosing the best available interface. +//! +//! ## How to use it +//! +//! ### Initialization +//! +//! To initialize a session just call `AutoSession::new`. A new session will be opened, if the +//! any available interface is successful and will be closed once the `AutoSessionNotifier` is dropped. +//! +//! ### Usage of the session +//! +//! The session may be used to open devices manually through the `Session` interface +//! or be passed to other objects that need it to open devices themselves. +//! The `AutoSession` is clonable and may be passed to multiple devices easily. +//! +//! Examples for those are e.g. the `LibinputInputBackend` (its context might be initialized through a +//! `Session` via the `LibinputSessionInterface`) or the `UdevBackend`. +//! +//! ### 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 `AutoSession::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::rc::Rc; use std::cell::RefCell; @@ -12,25 +43,39 @@ use super::{Session, SessionNotifier, SessionObserver, AsErrno}; use super::logind::{self, LogindSession, LogindSessionNotifier, BoundLogindSession, logind_session_bind}; use super::direct::{self, DirectSession, DirectSessionNotifier, direct_session_bind}; +/// `Session` using the best available inteface #[derive(Clone)] pub enum AutoSession { + /// Logind session #[cfg(feature = "backend_session_logind")] Logind(LogindSession), + /// Direct / tty session Direct(Rc>), } +/// `SessionNotifier` using the best available inteface pub enum AutoSessionNotifier { + /// Logind session nofifier #[cfg(feature = "backend_session_logind")] Logind(LogindSessionNotifier), + /// Direct / tty session notifier Direct(DirectSessionNotifier), } +/// Bound session that is driven by the `wayland_server::EventLoop`. +/// +/// See `auto_session_bind` for details. +/// +/// Dropping this object will close the session just like the `AutoSessionNotifier`. pub enum BoundAutoSession { + /// Bound logind session #[cfg(feature = "backend_session_logind")] Logind(BoundLogindSession), + /// Bound direct / tty session Direct(SignalEventSource), } +/// Id's used by the `AutoSessionNotifier` internally. #[derive(PartialEq, Eq)] pub struct AutoId(AutoIdInternal); #[derive(PartialEq, Eq)] @@ -41,6 +86,7 @@ enum AutoIdInternal { } impl AutoSession { + /// Tries to create a new session via the best available interface. #[cfg(feature = "backend_session_logind")] pub fn new(logger: L) -> Option<(AutoSession, AutoSessionNotifier)> where L: Into> @@ -85,6 +131,11 @@ impl AutoSession { } } +/// Bind an `AutoSessionNotifier` to an `EventLoop`. +/// +/// Allows the `AutoSessionNotifier` to listen for incoming signals signalling the session state. +/// If you don't use this function `AutoSessionNotifier` will not correctly tell you the +/// session state and call it's `SessionObservers`. pub fn auto_session_bind(notifier: AutoSessionNotifier, evlh: &mut EventLoopHandle) -> IoResult { Ok(match notifier { #[cfg(feature = "backend_session_logind")] @@ -171,10 +222,11 @@ impl SessionNotifier for AutoSessionNotifier { } impl BoundAutoSession { - pub fn remove(self) -> AutoSessionNotifier { + /// Unbind the session from the `EventLoop` again + pub fn unbind(self) -> AutoSessionNotifier { match self { #[cfg(feature = "backend_session_logind")] - BoundAutoSession::Logind(logind) => AutoSessionNotifier::Logind(logind.close()), + BoundAutoSession::Logind(logind) => AutoSessionNotifier::Logind(logind.unbind()), BoundAutoSession::Direct(source) => AutoSessionNotifier::Direct(source.remove()), } } @@ -182,11 +234,11 @@ impl BoundAutoSession { error_chain! { links { - Logind(logind::Error, logind::ErrorKind) #[cfg(feature = "backend_session_logind")]; + Logind(logind::Error, logind::ErrorKind) #[cfg(feature = "backend_session_logind")] #[doc = "Underlying logind session error"]; } foreign_links { - Direct(::nix::Error); + Direct(::nix::Error) #[doc = "Underlying direct tty session error"]; } } diff --git a/src/backend/session/dbus/logind.rs b/src/backend/session/dbus/logind.rs index 17ce24c..4aa415f 100644 --- a/src/backend/session/dbus/logind.rs +++ b/src/backend/session/dbus/logind.rs @@ -1,3 +1,35 @@ +//! +//! Implementation of the `Session` trait through the logind dbus interface. +//! +//! This requires systemd and dbus to be available and started on the system. +//! +//! ## How to use it +//! +//! ### Initialization +//! +//! To initialize a session just call `LogindSession::new`. A new session will be opened, if the +//! call is successful and will be closed once the `LogindSessionNotifier` is dropped. +//! +//! ### Usage of the session +//! +//! The session may be used to open devices manually through the `Session` interface +//! or be passed to other objects that need it to open devices themselves. +//! The `LogindSession` is clonable and may be passed to multiple devices easily. +//! +//! Examples for those are e.g. the `LibinputInputBackend` (its context might be initialized through a +//! `Session` via the `LibinputSessionInterface`) or the `UdevBackend`. +//! +//! ### 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 `LogindSession::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 ::backend::session::{AsErrno, Session, SessionNotifier, SessionObserver}; use nix::fcntl::OFlag; use nix::sys::stat::{stat, fstat, major, minor}; @@ -21,17 +53,20 @@ struct LogindSessionImpl { logger: ::slog::Logger, } +/// `Session` via the logind dbus interface #[derive(Clone)] pub struct LogindSession { internal: Weak, seat: String, } +/// `SessionNotifier` via the logind dbus interface pub struct LogindSessionNotifier { internal: Rc } impl LogindSession { + /// Tries to create a new session via the logind dbus interface. pub fn new(logger: L) -> Result<(LogindSession, LogindSessionNotifier)> where L: Into> @@ -39,17 +74,14 @@ impl LogindSession { let logger = ::slog_or_stdlog(logger) .new(o!("smithay_module" => "backend_session", "session_type" => "logind")); + // Acquire session_id, seat and vt (if any) via libsystemd let session_id = login::get_session(None).chain_err(|| ErrorKind::FailedToGetSession)?; let seat = login::get_seat(session_id.clone()).chain_err(|| ErrorKind::FailedToGetSeat)?; - /*let vt = if seat == "seat0" { - Some(login::get_vt(session_id.clone()).chain_err(|| ErrorKind::FailedToGetVT)?) - } else { - None - };*/ let vt = login::get_vt(session_id.clone()).ok(); + // Create dbus connection let conn = Connection::get_private(BusType::System).chain_err(|| ErrorKind::FailedDbusConnection)?; - + // and get the session path let session_path = LogindSessionImpl::blocking_call( &conn, "org.freedesktop.login1", @@ -60,6 +92,7 @@ impl LogindSession { )?.get1::>() .chain_err(|| ErrorKind::UnexpectedMethodReturn)?; + // Match all signals that we want to receive and handle let match1 = String::from("type='signal',\ sender='org.freedesktop.login1',\ interface='org.freedesktop.login1.Manager',\ @@ -85,6 +118,7 @@ impl LogindSession { path='{}'", &session_path); conn.add_match(&match4).chain_err(|| ErrorKind::DbusMatchFailed(match4))?; + // Activate (switch to) the session and take control LogindSessionImpl::blocking_call( &conn, "org.freedesktop.login1", @@ -93,7 +127,6 @@ impl LogindSession { "Activate", None, )?; - LogindSessionImpl::blocking_call( &conn, "org.freedesktop.login1", @@ -128,6 +161,7 @@ impl LogindSession { } impl LogindSessionNotifier { + /// Creates a new session object beloging to this notifier. pub fn session(&self) -> LogindSession { LogindSession { internal: Rc::downgrade(&self.internal), @@ -357,12 +391,22 @@ impl SessionNotifier for LogindSessionNotifier { } } +/// Bound logind session that is driven by the `wayland_server::EventLoop`. +/// +/// See `logind_session_bind` for details. +/// +/// Dropping this object will close the logind session just like the `LogindSessionNotifier`. pub struct BoundLogindSession { notifier: LogindSessionNotifier, - watches: Vec, + _watches: Vec, sources: Vec>>, } +/// Bind a `LogindSessionNotifier` to an `EventLoop`. +/// +/// Allows the `LogindSessionNotifier` to listen for incoming signals signalling the session state. +/// If you don't use this function `LogindSessionNotifier` will not correctly tell you the logind +/// session state and call it's `SessionObservers`. pub fn logind_session_bind( notifier: LogindSessionNotifier, evlh: &mut EventLoopHandle ) -> IoResult @@ -382,13 +426,14 @@ pub fn logind_session_bind( Ok(BoundLogindSession { notifier, - watches, + _watches: watches, sources, }) } impl BoundLogindSession { - pub fn close(self) -> LogindSessionNotifier { + /// Unbind the logind session from the `EventLoop` + pub fn unbind(self) -> LogindSessionNotifier { for source in self.sources { source.remove(); } @@ -399,6 +444,7 @@ impl BoundLogindSession { impl Drop for LogindSessionNotifier { fn drop(&mut self) { info!(self.internal.logger, "Closing logind session"); + // Release control again and drop everything closing the connection let _ = LogindSessionImpl::blocking_call( &*self.internal.conn.borrow(), "org.freedesktop.login1", diff --git a/src/backend/session/direct.rs b/src/backend/session/direct.rs index 3a61b71..e8c8e27 100644 --- a/src/backend/session/direct.rs +++ b/src/backend/session/direct.rs @@ -27,7 +27,7 @@ //! ### 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. +//! or be passed to other objects that need it 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`. @@ -160,7 +160,7 @@ pub struct DirectSessionNotifier { } impl DirectSession { - /// Tries to creates a new session via the legacy virtual terminal interface. + /// Tries to create 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(tty: Option<&Path>, logger: L) -> Result<(DirectSession, DirectSessionNotifier)> @@ -362,9 +362,9 @@ impl SessionNotifier for DirectSessionNotifier { /// Bind a `DirectSessionNotifier` to an `EventLoop`. /// -/// Allows the `DirectSessionNotifier` to listen for the incoming signals signalling the session state. +/// Allows the `DirectSessionNotifier` to listen for incoming signals signalling the session state. /// If you don't use this function `DirectSessionNotifier` will not correctly tell you the current -/// session state. +/// session state and call it's `SessionObservers`. pub fn direct_session_bind( notifier: DirectSessionNotifier, evlh: &mut EventLoopHandle ) -> IoResult> {