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::io::{Result as IoResult};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::cell::RefCell;
|
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::logind::{self, LogindSession, LogindSessionNotifier, BoundLogindSession, logind_session_bind};
|
||||||
use super::direct::{self, DirectSession, DirectSessionNotifier, direct_session_bind};
|
use super::direct::{self, DirectSession, DirectSessionNotifier, direct_session_bind};
|
||||||
|
|
||||||
|
/// `Session` using the best available inteface
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum AutoSession {
|
pub enum AutoSession {
|
||||||
|
/// Logind session
|
||||||
#[cfg(feature = "backend_session_logind")]
|
#[cfg(feature = "backend_session_logind")]
|
||||||
Logind(LogindSession),
|
Logind(LogindSession),
|
||||||
|
/// Direct / tty session
|
||||||
Direct(Rc<RefCell<DirectSession>>),
|
Direct(Rc<RefCell<DirectSession>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// `SessionNotifier` using the best available inteface
|
||||||
pub enum AutoSessionNotifier {
|
pub enum AutoSessionNotifier {
|
||||||
|
/// Logind session nofifier
|
||||||
#[cfg(feature = "backend_session_logind")]
|
#[cfg(feature = "backend_session_logind")]
|
||||||
Logind(LogindSessionNotifier),
|
Logind(LogindSessionNotifier),
|
||||||
|
/// Direct / tty session notifier
|
||||||
Direct(DirectSessionNotifier),
|
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 {
|
pub enum BoundAutoSession {
|
||||||
|
/// Bound logind session
|
||||||
#[cfg(feature = "backend_session_logind")]
|
#[cfg(feature = "backend_session_logind")]
|
||||||
Logind(BoundLogindSession),
|
Logind(BoundLogindSession),
|
||||||
|
/// Bound direct / tty session
|
||||||
Direct(SignalEventSource<DirectSessionNotifier>),
|
Direct(SignalEventSource<DirectSessionNotifier>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Id's used by the `AutoSessionNotifier` internally.
|
||||||
#[derive(PartialEq, Eq)]
|
#[derive(PartialEq, Eq)]
|
||||||
pub struct AutoId(AutoIdInternal);
|
pub struct AutoId(AutoIdInternal);
|
||||||
#[derive(PartialEq, Eq)]
|
#[derive(PartialEq, Eq)]
|
||||||
|
@ -41,6 +86,7 @@ enum AutoIdInternal {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AutoSession {
|
impl AutoSession {
|
||||||
|
/// Tries to create a new session via the best available interface.
|
||||||
#[cfg(feature = "backend_session_logind")]
|
#[cfg(feature = "backend_session_logind")]
|
||||||
pub fn new<L>(logger: L) -> Option<(AutoSession, AutoSessionNotifier)>
|
pub fn new<L>(logger: L) -> Option<(AutoSession, AutoSessionNotifier)>
|
||||||
where L: Into<Option<::slog::Logger>>
|
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> {
|
pub fn auto_session_bind(notifier: AutoSessionNotifier, evlh: &mut EventLoopHandle) -> IoResult<BoundAutoSession> {
|
||||||
Ok(match notifier {
|
Ok(match notifier {
|
||||||
#[cfg(feature = "backend_session_logind")]
|
#[cfg(feature = "backend_session_logind")]
|
||||||
|
@ -171,10 +222,11 @@ impl SessionNotifier for AutoSessionNotifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BoundAutoSession {
|
impl BoundAutoSession {
|
||||||
pub fn remove(self) -> AutoSessionNotifier {
|
/// Unbind the session from the `EventLoop` again
|
||||||
|
pub fn unbind(self) -> AutoSessionNotifier {
|
||||||
match self {
|
match self {
|
||||||
#[cfg(feature = "backend_session_logind")]
|
#[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()),
|
BoundAutoSession::Direct(source) => AutoSessionNotifier::Direct(source.remove()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -182,11 +234,11 @@ impl BoundAutoSession {
|
||||||
|
|
||||||
error_chain! {
|
error_chain! {
|
||||||
links {
|
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 {
|
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 ::backend::session::{AsErrno, Session, SessionNotifier, SessionObserver};
|
||||||
use nix::fcntl::OFlag;
|
use nix::fcntl::OFlag;
|
||||||
use nix::sys::stat::{stat, fstat, major, minor};
|
use nix::sys::stat::{stat, fstat, major, minor};
|
||||||
|
@ -21,17 +53,20 @@ struct LogindSessionImpl {
|
||||||
logger: ::slog::Logger,
|
logger: ::slog::Logger,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// `Session` via the logind dbus interface
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct LogindSession {
|
pub struct LogindSession {
|
||||||
internal: Weak<LogindSessionImpl>,
|
internal: Weak<LogindSessionImpl>,
|
||||||
seat: String,
|
seat: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// `SessionNotifier` via the logind dbus interface
|
||||||
pub struct LogindSessionNotifier {
|
pub struct LogindSessionNotifier {
|
||||||
internal: Rc<LogindSessionImpl>
|
internal: Rc<LogindSessionImpl>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LogindSession {
|
impl LogindSession {
|
||||||
|
/// Tries to create a new session via the logind dbus interface.
|
||||||
pub fn new<L>(logger: L) -> Result<(LogindSession, LogindSessionNotifier)>
|
pub fn new<L>(logger: L) -> Result<(LogindSession, LogindSessionNotifier)>
|
||||||
where
|
where
|
||||||
L: Into<Option<::slog::Logger>>
|
L: Into<Option<::slog::Logger>>
|
||||||
|
@ -39,17 +74,14 @@ impl LogindSession {
|
||||||
let logger = ::slog_or_stdlog(logger)
|
let logger = ::slog_or_stdlog(logger)
|
||||||
.new(o!("smithay_module" => "backend_session", "session_type" => "logind"));
|
.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 session_id = login::get_session(None).chain_err(|| ErrorKind::FailedToGetSession)?;
|
||||||
let seat = login::get_seat(session_id.clone()).chain_err(|| ErrorKind::FailedToGetSeat)?;
|
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();
|
let vt = login::get_vt(session_id.clone()).ok();
|
||||||
|
|
||||||
|
// Create dbus connection
|
||||||
let conn = Connection::get_private(BusType::System).chain_err(|| ErrorKind::FailedDbusConnection)?;
|
let conn = Connection::get_private(BusType::System).chain_err(|| ErrorKind::FailedDbusConnection)?;
|
||||||
|
// and get the session path
|
||||||
let session_path = LogindSessionImpl::blocking_call(
|
let session_path = LogindSessionImpl::blocking_call(
|
||||||
&conn,
|
&conn,
|
||||||
"org.freedesktop.login1",
|
"org.freedesktop.login1",
|
||||||
|
@ -60,6 +92,7 @@ impl LogindSession {
|
||||||
)?.get1::<DbusPath<'static>>()
|
)?.get1::<DbusPath<'static>>()
|
||||||
.chain_err(|| ErrorKind::UnexpectedMethodReturn)?;
|
.chain_err(|| ErrorKind::UnexpectedMethodReturn)?;
|
||||||
|
|
||||||
|
// Match all signals that we want to receive and handle
|
||||||
let match1 = String::from("type='signal',\
|
let match1 = String::from("type='signal',\
|
||||||
sender='org.freedesktop.login1',\
|
sender='org.freedesktop.login1',\
|
||||||
interface='org.freedesktop.login1.Manager',\
|
interface='org.freedesktop.login1.Manager',\
|
||||||
|
@ -85,6 +118,7 @@ impl LogindSession {
|
||||||
path='{}'", &session_path);
|
path='{}'", &session_path);
|
||||||
conn.add_match(&match4).chain_err(|| ErrorKind::DbusMatchFailed(match4))?;
|
conn.add_match(&match4).chain_err(|| ErrorKind::DbusMatchFailed(match4))?;
|
||||||
|
|
||||||
|
// Activate (switch to) the session and take control
|
||||||
LogindSessionImpl::blocking_call(
|
LogindSessionImpl::blocking_call(
|
||||||
&conn,
|
&conn,
|
||||||
"org.freedesktop.login1",
|
"org.freedesktop.login1",
|
||||||
|
@ -93,7 +127,6 @@ impl LogindSession {
|
||||||
"Activate",
|
"Activate",
|
||||||
None,
|
None,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
LogindSessionImpl::blocking_call(
|
LogindSessionImpl::blocking_call(
|
||||||
&conn,
|
&conn,
|
||||||
"org.freedesktop.login1",
|
"org.freedesktop.login1",
|
||||||
|
@ -128,6 +161,7 @@ impl LogindSession {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LogindSessionNotifier {
|
impl LogindSessionNotifier {
|
||||||
|
/// Creates a new session object beloging to this notifier.
|
||||||
pub fn session(&self) -> LogindSession {
|
pub fn session(&self) -> LogindSession {
|
||||||
LogindSession {
|
LogindSession {
|
||||||
internal: Rc::downgrade(&self.internal),
|
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 {
|
pub struct BoundLogindSession {
|
||||||
notifier: LogindSessionNotifier,
|
notifier: LogindSessionNotifier,
|
||||||
watches: Vec<Watch>,
|
_watches: Vec<Watch>,
|
||||||
sources: Vec<FdEventSource<Rc<LogindSessionImpl>>>,
|
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(
|
pub fn logind_session_bind(
|
||||||
notifier: LogindSessionNotifier, evlh: &mut EventLoopHandle
|
notifier: LogindSessionNotifier, evlh: &mut EventLoopHandle
|
||||||
) -> IoResult<BoundLogindSession>
|
) -> IoResult<BoundLogindSession>
|
||||||
|
@ -382,13 +426,14 @@ pub fn logind_session_bind(
|
||||||
|
|
||||||
Ok(BoundLogindSession {
|
Ok(BoundLogindSession {
|
||||||
notifier,
|
notifier,
|
||||||
watches,
|
_watches: watches,
|
||||||
sources,
|
sources,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BoundLogindSession {
|
impl BoundLogindSession {
|
||||||
pub fn close(self) -> LogindSessionNotifier {
|
/// Unbind the logind session from the `EventLoop`
|
||||||
|
pub fn unbind(self) -> LogindSessionNotifier {
|
||||||
for source in self.sources {
|
for source in self.sources {
|
||||||
source.remove();
|
source.remove();
|
||||||
}
|
}
|
||||||
|
@ -399,6 +444,7 @@ impl BoundLogindSession {
|
||||||
impl Drop for LogindSessionNotifier {
|
impl Drop for LogindSessionNotifier {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
info!(self.internal.logger, "Closing logind session");
|
info!(self.internal.logger, "Closing logind session");
|
||||||
|
// Release control again and drop everything closing the connection
|
||||||
let _ = LogindSessionImpl::blocking_call(
|
let _ = LogindSessionImpl::blocking_call(
|
||||||
&*self.internal.conn.borrow(),
|
&*self.internal.conn.borrow(),
|
||||||
"org.freedesktop.login1",
|
"org.freedesktop.login1",
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
//! ### Usage of the session
|
//! ### Usage of the session
|
||||||
//!
|
//!
|
||||||
//! The session may be used to open devices manually through the `Session` interface
|
//! 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
|
//! Examples for those are e.g. the `LibinputInputBackend` (its context might be initialized through a
|
||||||
//! `Session` via the `LibinputSessionInterface`) or the `UdevBackend`.
|
//! `Session` via the `LibinputSessionInterface`) or the `UdevBackend`.
|
||||||
|
@ -160,7 +160,7 @@ pub struct DirectSessionNotifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DirectSession {
|
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.
|
/// 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)>
|
||||||
|
@ -362,9 +362,9 @@ impl SessionNotifier for DirectSessionNotifier {
|
||||||
|
|
||||||
/// Bind a `DirectSessionNotifier` to an `EventLoop`.
|
/// 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
|
/// 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(
|
pub fn direct_session_bind(
|
||||||
notifier: DirectSessionNotifier, evlh: &mut EventLoopHandle
|
notifier: DirectSessionNotifier, evlh: &mut EventLoopHandle
|
||||||
) -> IoResult<SignalEventSource<DirectSessionNotifier>> {
|
) -> IoResult<SignalEventSource<DirectSessionNotifier>> {
|
||||||
|
|
Loading…
Reference in New Issue