#[cfg(feature = "backend_session_libseat")]
use super::libseat::{LibSeatSession, LibSeatSessionNotifier};
#[cfg(feature = "backend_session_logind")]
use super::logind::{self, LogindSession, LogindSessionNotifier};
use super::{
direct::{self, DirectSession, DirectSessionNotifier},
AsErrno, Session, Signal as SessionSignal,
};
use crate::utils::signaling::Signaler;
use nix::fcntl::OFlag;
use std::{cell::RefCell, io, os::unix::io::RawFd, path::Path, rc::Rc};
use calloop::{EventSource, Poll, PostAction, Readiness, Token, TokenFactory};
use slog::{error, info, o, warn};
#[derive(Debug, Clone)]
pub enum AutoSession {
#[cfg(feature = "backend_session_logind")]
Logind(LogindSession),
Direct(Rc<RefCell<DirectSession>>),
#[cfg(feature = "backend_session_libseat")]
LibSeat(LibSeatSession),
}
#[derive(Debug)]
pub enum AutoSessionNotifier {
#[cfg(feature = "backend_session_logind")]
Logind(LogindSessionNotifier),
Direct(DirectSessionNotifier),
#[cfg(feature = "backend_session_libseat")]
LibSeat(LibSeatSessionNotifier),
}
impl AutoSession {
pub fn new<L>(logger: L) -> Option<(AutoSession, AutoSessionNotifier)>
where
L: Into<Option<::slog::Logger>>,
{
let logger = crate::slog_or_fallback(logger)
.new(o!("smithay_module" => "backend_session_auto", "session_type" => "auto"));
#[cfg(feature = "backend_session_libseat")]
{
info!(logger, "Trying to create libseat session");
match LibSeatSession::new(logger.clone()) {
Ok((sesstion, notifier)) => {
return Some((
AutoSession::LibSeat(sesstion),
AutoSessionNotifier::LibSeat(notifier),
))
}
Err(err) => {
warn!(logger, "Failed to create libseat session: {}", err);
}
}
}
#[cfg(feature = "backend_session_logind")]
{
info!(logger, "Trying to create logind session");
match LogindSession::new(logger.clone()) {
Ok((session, notifier)) => {
return Some((
AutoSession::Logind(session),
AutoSessionNotifier::Logind(notifier),
))
}
Err(err) => {
warn!(logger, "Failed to create logind session: {}", err);
}
}
}
info!(logger, "Trying to create tty session");
match DirectSession::new(None, logger.clone()) {
Ok((session, notifier)) => {
return 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
}
}
impl Session for AutoSession {
type Error = Error;
fn open(&mut self, path: &Path, flags: OFlag) -> Result<RawFd, Error> {
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()),
#[cfg(feature = "backend_session_libseat")]
AutoSession::LibSeat(ref mut logind) => logind.open(path, flags).map_err(|e| e.into()),
}
}
fn close(&mut self, fd: RawFd) -> Result<(), Error> {
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()),
#[cfg(feature = "backend_session_libseat")]
AutoSession::LibSeat(ref mut direct) => direct.close(fd).map_err(|e| e.into()),
}
}
fn change_vt(&mut self, vt: i32) -> Result<(), Error> {
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()),
#[cfg(feature = "backend_session_libseat")]
AutoSession::LibSeat(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(),
#[cfg(feature = "backend_session_libseat")]
AutoSession::LibSeat(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(),
#[cfg(feature = "backend_session_libseat")]
AutoSession::LibSeat(ref direct) => direct.seat(),
}
}
}
impl AutoSessionNotifier {
pub fn signaler(&self) -> Signaler<SessionSignal> {
match *self {
#[cfg(feature = "backend_session_logind")]
AutoSessionNotifier::Logind(ref logind) => logind.signaler(),
AutoSessionNotifier::Direct(ref direct) => direct.signaler(),
#[cfg(feature = "backend_session_libseat")]
AutoSessionNotifier::LibSeat(ref direct) => direct.signaler(),
}
}
}
impl EventSource for AutoSessionNotifier {
type Event = ();
type Metadata = ();
type Ret = ();
fn process_events<F>(&mut self, readiness: Readiness, token: Token, callback: F) -> io::Result<PostAction>
where
F: FnMut((), &mut ()),
{
match self {
#[cfg(feature = "backend_session_logind")]
AutoSessionNotifier::Logind(s) => s.process_events(readiness, token, callback),
AutoSessionNotifier::Direct(s) => s.process_events(readiness, token, callback),
#[cfg(feature = "backend_session_libseat")]
AutoSessionNotifier::LibSeat(s) => s.process_events(readiness, token, callback),
}
}
fn register(&mut self, poll: &mut Poll, factory: &mut TokenFactory) -> io::Result<()> {
match self {
#[cfg(feature = "backend_session_logind")]
AutoSessionNotifier::Logind(s) => EventSource::register(s, poll, factory),
AutoSessionNotifier::Direct(s) => EventSource::register(s, poll, factory),
#[cfg(feature = "backend_session_libseat")]
AutoSessionNotifier::LibSeat(s) => EventSource::register(s, poll, factory),
}
}
fn reregister(&mut self, poll: &mut Poll, factory: &mut TokenFactory) -> io::Result<()> {
match self {
#[cfg(feature = "backend_session_logind")]
AutoSessionNotifier::Logind(s) => EventSource::reregister(s, poll, factory),
AutoSessionNotifier::Direct(s) => EventSource::reregister(s, poll, factory),
#[cfg(feature = "backend_session_libseat")]
AutoSessionNotifier::LibSeat(s) => EventSource::reregister(s, poll, factory),
}
}
fn unregister(&mut self, poll: &mut Poll) -> io::Result<()> {
match self {
#[cfg(feature = "backend_session_logind")]
AutoSessionNotifier::Logind(s) => EventSource::unregister(s, poll),
AutoSessionNotifier::Direct(s) => EventSource::unregister(s, poll),
#[cfg(feature = "backend_session_libseat")]
AutoSessionNotifier::LibSeat(s) => EventSource::unregister(s, poll),
}
}
}
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[cfg(feature = "backend_session_logind")]
#[error("Logind session error: {0}")]
Logind(#[from] logind::Error),
#[error("Direct session error: {0}")]
Direct(#[from] direct::Error),
#[cfg(feature = "backend_session_libseat")]
#[error("LibSeat session error: {0}")]
LibSeat(#[from] super::libseat::Error),
#[error("Nix error: {0}")]
Nix(#[from] nix::Error),
}
impl AsErrno for Error {
fn as_errno(&self) -> Option<i32> {
None
}
}