Add documentation for logind/auto session
This commit is contained in:
parent
4501ca5fe1
commit
20e10612b9
|
@ -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<RefCell<DirectSession>>),
|
||||
}
|
||||
|
||||
/// `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<DirectSessionNotifier>),
|
||||
}
|
||||
|
||||
/// 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<L>(logger: L) -> Option<(AutoSession, AutoSessionNotifier)>
|
||||
where L: Into<Option<::slog::Logger>>
|
||||
|
@ -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<BoundAutoSession> {
|
||||
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"];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<LogindSessionImpl>,
|
||||
seat: String,
|
||||
}
|
||||
|
||||
/// `SessionNotifier` via the logind dbus interface
|
||||
pub struct LogindSessionNotifier {
|
||||
internal: Rc<LogindSessionImpl>
|
||||
}
|
||||
|
||||
impl LogindSession {
|
||||
/// Tries to create a new session via the logind dbus interface.
|
||||
pub fn new<L>(logger: L) -> Result<(LogindSession, LogindSessionNotifier)>
|
||||
where
|
||||
L: Into<Option<::slog::Logger>>
|
||||
|
@ -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::<DbusPath<'static>>()
|
||||
.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<Watch>,
|
||||
_watches: Vec<Watch>,
|
||||
sources: Vec<FdEventSource<Rc<LogindSessionImpl>>>,
|
||||
}
|
||||
|
||||
/// 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<BoundLogindSession>
|
||||
|
@ -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",
|
||||
|
|
|
@ -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<L>(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<SignalEventSource<DirectSessionNotifier>> {
|
||||
|
|
Loading…
Reference in New Issue