#[cfg(feature = "backend_session_logind")]
use super::logind::{self, logind_session_bind, BoundLogindSession, LogindSession, LogindSessionNotifier};
use super::{
direct::{self, direct_session_bind, BoundDirectSession, DirectSession, DirectSessionNotifier},
AsErrno, Session, SessionNotifier, SessionObserver,
};
use nix::fcntl::OFlag;
use std::{cell::RefCell, io::Error as IoError, os::unix::io::RawFd, path::Path, rc::Rc};
use wayland_server::calloop::LoopHandle;
#[derive(Clone)]
pub enum AutoSession {
#[cfg(feature = "backend_session_logind")]
Logind(LogindSession),
Direct(Rc<RefCell<DirectSession>>),
}
pub enum AutoSessionNotifier {
#[cfg(feature = "backend_session_logind")]
Logind(LogindSessionNotifier),
Direct(DirectSessionNotifier),
}
pub enum BoundAutoSession {
#[cfg(feature = "backend_session_logind")]
Logind(BoundLogindSession),
Direct(BoundDirectSession),
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct AutoId(AutoIdInternal);
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
enum AutoIdInternal {
#[cfg(feature = "backend_session_logind")]
Logind(logind::Id),
Direct(direct::Id),
}
impl AutoSession {
#[cfg(feature = "backend_session_logind")]
pub fn new<L>(logger: L) -> Option<(AutoSession, AutoSessionNotifier)>
where
L: Into<Option<::slog::Logger>>,
{
let logger = crate::slog_or_stdlog(logger)
.new(o!("smithay_module" => "backend_session_auto", "session_type" => "auto"));
info!(logger, "Trying to create logind session");
match LogindSession::new(logger.clone()) {
Ok((session, notifier)) => Some((
AutoSession::Logind(session),
AutoSessionNotifier::Logind(notifier),
)),
Err(err) => {
warn!(logger, "Failed to create logind session: {}", err);
info!(logger, "Falling back to create tty session");
match DirectSession::new(None, logger.clone()) {
Ok((session, notifier)) => Some((
AutoSession::Direct(Rc::new(RefCell::new(session))),
AutoSessionNotifier::Direct(notifier),
)),
Err(err) => {
warn!(logger, "Failed to create direct session: {}", err);
error!(logger, "Could not create any session, possibilities exhausted");
None
}
}
}
}
}
#[cfg(not(feature = "backend_session_logind"))]
pub fn new<L>(logger: L) -> Option<(AutoSession, AutoSessionNotifier)>
where
L: Into<Option<::slog::Logger>>,
{
let logger = crate::slog_or_stdlog(logger)
.new(o!("smithay_module" => "backend_session_auto", "session_type" => "auto"));
info!(logger, "Trying to create tty session");
match DirectSession::new(None, logger.clone()) {
Ok((session, notifier)) => Some((
AutoSession::Direct(Rc::new(RefCell::new(session))),
AutoSessionNotifier::Direct(notifier),
)),
Err(err) => {
warn!(logger, "Failed to create direct session: {}", err);
error!(logger, "Could not create any session, possibilities exhausted");
None
}
}
}
}
pub fn auto_session_bind<Data: 'static>(
notifier: AutoSessionNotifier,
handle: &LoopHandle<Data>,
) -> ::std::result::Result<BoundAutoSession, (IoError, AutoSessionNotifier)> {
Ok(match notifier {
#[cfg(feature = "backend_session_logind")]
AutoSessionNotifier::Logind(logind) => BoundAutoSession::Logind(
logind_session_bind(logind, handle).map_err(|(e, n)| (e, AutoSessionNotifier::Logind(n)))?,
),
AutoSessionNotifier::Direct(direct) => BoundAutoSession::Direct(
direct_session_bind(direct, handle).map_err(|(e, n)| (e, AutoSessionNotifier::Direct(n)))?,
),
})
}
impl Session for AutoSession {
type Error = Error;
fn open(&mut self, path: &Path, flags: OFlag) -> Result<RawFd> {
match *self {
#[cfg(feature = "backend_session_logind")]
AutoSession::Logind(ref mut logind) => logind.open(path, flags).map_err(|e| e.into()),
AutoSession::Direct(ref mut direct) => direct.open(path, flags).map_err(|e| e.into()),
}
}
fn close(&mut self, fd: RawFd) -> Result<()> {
match *self {
#[cfg(feature = "backend_session_logind")]
AutoSession::Logind(ref mut logind) => logind.close(fd).map_err(|e| e.into()),
AutoSession::Direct(ref mut direct) => direct.close(fd).map_err(|e| e.into()),
}
}
fn change_vt(&mut self, vt: i32) -> Result<()> {
match *self {
#[cfg(feature = "backend_session_logind")]
AutoSession::Logind(ref mut logind) => logind.change_vt(vt).map_err(|e| e.into()),
AutoSession::Direct(ref mut direct) => direct.change_vt(vt).map_err(|e| e.into()),
}
}
fn is_active(&self) -> bool {
match *self {
#[cfg(feature = "backend_session_logind")]
AutoSession::Logind(ref logind) => logind.is_active(),
AutoSession::Direct(ref direct) => direct.is_active(),
}
}
fn seat(&self) -> String {
match *self {
#[cfg(feature = "backend_session_logind")]
AutoSession::Logind(ref logind) => logind.seat(),
AutoSession::Direct(ref direct) => direct.seat(),
}
}
}
impl SessionNotifier for AutoSessionNotifier {
type Id = AutoId;
fn register<S: SessionObserver + 'static>(&mut self, signal: S) -> Self::Id {
match *self {
#[cfg(feature = "backend_session_logind")]
AutoSessionNotifier::Logind(ref mut logind) => {
AutoId(AutoIdInternal::Logind(logind.register(signal)))
}
AutoSessionNotifier::Direct(ref mut direct) => {
AutoId(AutoIdInternal::Direct(direct.register(signal)))
}
}
}
fn unregister(&mut self, signal: Self::Id) {
#[allow(unreachable_patterns)]
match (self, signal) {
#[cfg(feature = "backend_session_logind")]
(&mut AutoSessionNotifier::Logind(ref mut logind), AutoId(AutoIdInternal::Logind(signal))) => {
logind.unregister(signal)
}
(&mut AutoSessionNotifier::Direct(ref mut direct), AutoId(AutoIdInternal::Direct(signal))) => {
direct.unregister(signal)
}
_ => unreachable!(),
}
}
}
impl BoundAutoSession {
pub fn unbind(self) -> AutoSessionNotifier {
match self {
#[cfg(feature = "backend_session_logind")]
BoundAutoSession::Logind(logind) => AutoSessionNotifier::Logind(logind.unbind()),
BoundAutoSession::Direct(direct) => AutoSessionNotifier::Direct(direct.unbind()),
}
}
}
pub mod errors {
#[cfg(feature = "backend_session_logind")]
use super::logind::errors as logind;
error_chain! {
links {
Logind(logind::Error, logind::ErrorKind) #[cfg(feature = "backend_session_logind")] #[doc = "Underlying logind session error"];
}
foreign_links {
Direct(::nix::Error) #[doc = "Underlying direct tty session error"];
}
}
}
use self::errors::*;
impl AsErrno for Error {
fn as_errno(&self) -> Option<i32> {
None
}
}