Add logind session

This commit is contained in:
Drakulix 2018-01-24 00:10:00 +01:00
parent 4971278a25
commit b16c62b19f
9 changed files with 566 additions and 22 deletions

View File

@ -22,6 +22,8 @@ gbm = { version = "^0.4.0", optional = true, default-features = false, features
glium = { version = "0.19.0", optional = true, default-features = false } glium = { version = "0.19.0", optional = true, default-features = false }
input = { version = "0.4.0", optional = true } input = { version = "0.4.0", optional = true }
udev = { version = "0.2.0", optional = true } udev = { version = "0.2.0", optional = true }
dbus = { version = "0.6.1", optional = true }
systemd = { git = "https://github.com/Drakulix/rust-systemd", branch = "feature/login_functions", optional = true }
wayland-protocols = { version = "0.12.5", features = ["unstable_protocols", "server"] } wayland-protocols = { version = "0.12.5", features = ["unstable_protocols", "server"] }
image = "0.17.0" image = "0.17.0"
error-chain = "0.11.0" error-chain = "0.11.0"
@ -37,11 +39,12 @@ rand = "0.3"
ctrlc = { version = "3.0", features = ["termination"] } ctrlc = { version = "3.0", features = ["termination"] }
[features] [features]
default = ["backend_winit", "backend_drm", "backend_libinput", "backend_udev", "renderer_glium"] default = ["backend_winit", "backend_drm", "backend_libinput", "backend_udev", "renderer_glium", "backend_session_logind"]
backend_winit = ["winit", "wayland-server/dlopen", "wayland-client/dlopen"] backend_winit = ["winit", "wayland-server/dlopen", "wayland-client/dlopen"]
backend_drm = ["drm", "gbm"] backend_drm = ["drm", "gbm"]
backend_libinput = ["input"] backend_libinput = ["input"]
backend_session = [] backend_session = []
backend_session_udev = ["udev", "backend_session"] backend_session_udev = ["udev", "backend_session"]
backend_session_logind = ["dbus", "systemd", "backend_session"]
backend_udev = ["udev", "backend_drm", "backend_session_udev"] backend_udev = ["udev", "backend_drm", "backend_session_udev"]
renderer_glium = ["glium"] renderer_glium = ["glium"]

View File

@ -221,7 +221,7 @@ use drm::control::framebuffer;
use drm::result::Error as DrmError; use drm::result::Error as DrmError;
use gbm::Device as GbmDevice; use gbm::Device as GbmDevice;
use nix; use nix;
use nix::sys::stat::{dev_t, fstat}; use nix::sys::stat::{self, dev_t, fstat};
use std::collections::HashMap; use std::collections::HashMap;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::io::Result as IoResult; use std::io::Result as IoResult;
@ -597,8 +597,14 @@ where
#[cfg(feature = "backend_session")] #[cfg(feature = "backend_session")]
impl<A: ControlDevice + 'static> SessionObserver for StateToken<DrmDevice<A>> { impl<A: ControlDevice + 'static> SessionObserver for StateToken<DrmDevice<A>> {
fn pause<'a>(&mut self, state: &mut StateProxy<'a>) { fn pause<'a>(&mut self, state: &mut StateProxy<'a>, devnum: Option<(u32, u32)>) {
let device = state.get_mut(self); let device = state.get_mut(self);
if let Some((major, minor)) = devnum {
if major as u64 != stat::major(device.device_id) ||
minor as u64 != stat::minor(device.device_id) {
return;
}
}
device.active = false; device.active = false;
if let Err(err) = device.drop_master() { if let Err(err) = device.drop_master() {
error!( error!(
@ -608,8 +614,17 @@ impl<A: ControlDevice + 'static> SessionObserver for StateToken<DrmDevice<A>> {
} }
} }
fn activate<'a>(&mut self, state: &mut StateProxy<'a>) { fn activate<'a>(&mut self, state: &mut StateProxy<'a>, devnum: Option<(u32, u32, Option<RawFd>)>) {
let device = state.get_mut(self); let device = state.get_mut(self);
if let Some((major, minor, fd)) = devnum {
if major as u64 != stat::major(device.device_id) ||
minor as u64 != stat::minor(device.device_id)
{
return;
} else if let Some(fd) = fd {
nix::unistd::dup2(device.as_raw_fd(), fd).expect("Failed to replace file descriptor of drm device");
}
}
device.active = true; device.active = true;
if let Err(err) = device.set_master() { if let Err(err) = device.set_master() {
crit!( crit!(

View File

@ -14,6 +14,12 @@ use std::rc::Rc;
use wayland_server::{EventLoopHandle, StateProxy}; use wayland_server::{EventLoopHandle, StateProxy};
use wayland_server::sources::{FdEventSource, FdEventSourceImpl, FdInterest}; use wayland_server::sources::{FdEventSource, FdEventSourceImpl, FdInterest};
// No idea if this is the same across unix platforms
// Lets make this linux exclusive for now, once someone tries to build it for
// any BSD-like system, they can verify if this is right and make a PR to change this.
#[cfg(any(target_os = "linux", target_os = "android"))]
const INPUT_MAJOR: u32 = 13;
/// Libinput based `InputBackend`. /// Libinput based `InputBackend`.
/// ///
/// Tracks input of all devices given manually or via a udev seat to a provided libinput /// Tracks input of all devices given manually or via a udev seat to a provided libinput
@ -568,12 +574,19 @@ impl From<event::pointer::ButtonState> for backend::MouseButtonState {
#[cfg(feature = "backend_session")] #[cfg(feature = "backend_session")]
impl SessionObserver for libinput::Libinput { impl SessionObserver for libinput::Libinput {
fn pause<'a>(&mut self, _state: &mut StateProxy<'a>) { fn pause<'a>(&mut self, _state: &mut StateProxy<'a>, device: Option<(u32, u32)>) {
if let Some((major, _)) = device {
if major != INPUT_MAJOR {
return;
}
}
// lets hope multiple suspends are okay in case of logind?
self.suspend() self.suspend()
} }
fn activate<'a>(&mut self, _state: &mut StateProxy<'a>) { fn activate<'a>(&mut self, _state: &mut StateProxy<'a>, _device: Option<(u32, u32, Option<RawFd>)>) {
// TODO Is this the best way to handle this failure? // libinput closes the devices on suspend, so we should not get any INPUT_MAJOR calls
// also lets hope multiple resumes are okay in case of logind
self.resume().expect("Unable to resume libinput context"); self.resume().expect("Unable to resume libinput context");
} }
} }

View File

@ -0,0 +1,502 @@
use ::backend::session::{AsErrno, Session, SessionNotifier, SessionObserver};
use nix::fcntl::OFlag;
use nix::sys::stat::{stat, fstat, major, minor};
use std::cell::RefCell;
use std::io::Result as IoResult;
use std::os::unix::io::RawFd;
use std::rc::{Rc, Weak};
use std::path::Path;
use std::sync::atomic::{AtomicBool, Ordering};
use systemd::login;
use dbus::{BusType, Connection, ConnectionItems, ConnectionItem, Message, BusName, Interface, Member, Path as DbusPath, OwnedFd, MessageItem, Watch, WatchEvent};
use wayland_server::EventLoopHandle;
use wayland_server::sources::{FdEventSource, FdEventSourceImpl, FdInterest};
struct LogindSessionImpl {
conn: RefCell<Connection>,
session_path: DbusPath<'static>,
active: AtomicBool,
signals: RefCell<Vec<Option<Box<SessionObserver>>>>,
seat: String,
logger: ::slog::Logger,
}
#[derive(Clone)]
pub struct LogindSession {
internal: Weak<LogindSessionImpl>,
seat: String,
}
pub struct LogindSessionNotifier {
internal: Rc<LogindSessionImpl>
}
impl LogindSession {
pub fn new<L>(logger: L) -> Result<(LogindSession, LogindSessionNotifier)>
where
L: Into<Option<::slog::Logger>>
{
let logger = ::slog_or_stdlog(logger)
.new(o!("smithay_module" => "backend_session", "session_type" => "logind"));
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();
let conn = Connection::get_private(BusType::System).chain_err(|| ErrorKind::FailedDbusConnection)?;
let session_path = LogindSessionImpl::blocking_call(
&conn,
"org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
"GetSession",
Some(vec![session_id.clone().into()])
)?.get1::<DbusPath<'static>>()
.chain_err(|| ErrorKind::UnexpectedMethodReturn)?;
let match1 = String::from("type='signal',\
sender='org.freedesktop.login1',\
interface='org.freedesktop.login1.Manager',\
member='SessionRemoved',\
path='/org/freedesktop/login1'");
conn.add_match(&match1).chain_err(|| ErrorKind::DbusMatchFailed(match1))?;
let match2 = format!("type='signal',\
sender='org.freedesktop.login1',\
interface='org.freedesktop.login1.Session',\
member='PauseDevice',\
path='{}'", &session_path);
conn.add_match(&match2).chain_err(|| ErrorKind::DbusMatchFailed(match2))?;
let match3 = format!("type='signal',\
sender='org.freedesktop.login1',\
interface='org.freedesktop.login1.Session',\
member='ResumeDevice',\
path='{}'", &session_path);
conn.add_match(&match3).chain_err(|| ErrorKind::DbusMatchFailed(match3))?;
let match4 = format!("type='signal',\
sender='org.freedesktop.login1',\
interface='org.freedesktop.DBus.Properties',\
member='PropertiesChanged',\
path='{}'", &session_path);
conn.add_match(&match4).chain_err(|| ErrorKind::DbusMatchFailed(match4))?;
LogindSessionImpl::blocking_call(
&conn,
"org.freedesktop.login1",
session_path.clone(),
"org.freedesktop.login1.Session",
"Activate",
None,
)?;
LogindSessionImpl::blocking_call(
&conn,
"org.freedesktop.login1",
session_path.clone(),
"org.freedesktop.login1.Session",
"TakeControl",
Some(vec![false.into()]),
)?;
let signals = RefCell::new(Vec::new());
let conn = RefCell::new(conn);
let internal = Rc::new(LogindSessionImpl {
conn,
session_path,
active: AtomicBool::new(true),
signals,
seat: seat.clone(),
logger: logger.new(o!("id" => session_id, "seat" => seat.clone(), "vt" => format!("{:?}", &vt))),
});
Ok((
LogindSession {
internal: Rc::downgrade(&internal),
seat,
},
LogindSessionNotifier {
internal,
}
))
}
}
impl LogindSessionNotifier {
pub fn session(&self) -> LogindSession {
LogindSession {
internal: Rc::downgrade(&self.internal),
seat: self.internal.seat.clone(),
}
}
}
impl LogindSessionImpl {
fn blocking_call<'d, 'p, 'i, 'm, D, P, I, M>
(
conn: &Connection,
destination: D,
path: P,
interface: I,
method: M,
arguments: Option<Vec<MessageItem>>
) -> Result<Message>
where
D: Into<BusName<'d>>,
P: Into<DbusPath<'p>>,
I: Into<Interface<'i>>,
M: Into<Member<'m>>,
{
let destination = destination.into().into_static();
let path = path.into().into_static();
let interface = interface.into().into_static();
let method = method.into().into_static();
let mut message = Message::method_call(&destination, &path, &interface, &method);
if let Some(arguments) = arguments {
message.append_items(&arguments)
};
let mut message = conn.send_with_reply_and_block(message, 1000)
.chain_err(|| ErrorKind::FailedToSendDbusCall(
destination.clone(),
path.clone(),
interface.clone(),
method.clone()
))?;
match message.as_result() {
Ok(_) => Ok(message),
Err(err) => Err(Error::with_chain(err, ErrorKind::DbusCallFailed(
destination.clone(),
path.clone(),
interface.clone(),
method.clone()
)))
}
}
fn handle_signals(&self, evlh: &mut EventLoopHandle, signals: ConnectionItems) -> Result<()> {
for item in signals {
let message = if let ConnectionItem::Signal(ref s) = item {
s
} else {
continue
};
if &*message.interface().unwrap() == "org.freedesktop.login1.Manager"
&& &*message.member().unwrap() == "SessionRemoved"
{
error!(self.logger, "Session got closed by logind");
//Ok... now what?
//This session will never live again, but the user maybe has other sessions open
//So lets just put it to sleep.. forever
for signal in &mut *self.signals.borrow_mut() {
if let &mut Some(ref mut signal) = signal {
signal.pause(&mut evlh.state().as_proxy(), None);
}
}
self.active.store(false, Ordering::SeqCst);
warn!(self.logger, "Session is now considered inactive");
} else if &*message.interface().unwrap() == "org.freedesktop.login1.Session" {
if &*message.member().unwrap() == "PauseDevice" {
let (major, minor, pause_type) = message.get3::<u32, u32, String>();
let major = major.chain_err(|| ErrorKind::UnexpectedMethodReturn)?;
let minor = minor.chain_err(|| ErrorKind::UnexpectedMethodReturn)?;
let pause_type = pause_type.chain_err(|| ErrorKind::UnexpectedMethodReturn)?;
debug!(self.logger, "Request of type \"{}\" to close device ({},{})", pause_type, major, minor);
for signal in &mut *self.signals.borrow_mut() {
if let &mut Some(ref mut signal) = signal {
signal.pause(&mut evlh.state().as_proxy(), Some((major, minor)));
}
}
// the other possible types are "force" or "gone" (unplugged),
// both expect no acknoledgement (note even this is not *really* necessary,
// logind would just timeout and send a "force" event. There is no way to
// keep the device.)
if &*pause_type == "pause" {
LogindSessionImpl::blocking_call(
&*self.conn.borrow(),
"org.freedesktop.login1",
self.session_path.clone(),
"org.freedesktop.login1.Session",
"PauseDeviceComplete",
Some(vec![major.into(), minor.into()])
)?;
}
} else if &*message.member().unwrap() == "ResumeDevice" {
let (major, minor, fd) = message.get3::<u32, u32, OwnedFd>();
let major = major.chain_err(|| ErrorKind::UnexpectedMethodReturn)?;
let minor = minor.chain_err(|| ErrorKind::UnexpectedMethodReturn)?;
let fd = fd.chain_err(|| ErrorKind::UnexpectedMethodReturn)?.into_fd();
debug!(self.logger, "Reactivating device ({},{})", major, minor);
for signal in &mut *self.signals.borrow_mut() {
if let &mut Some(ref mut signal) = signal {
signal.activate(&mut evlh.state().as_proxy(), Some((major, minor, Some(fd))));
}
}
}
} else if &*message.interface().unwrap() == "org.freedesktop.DBus.Properties"
&& &*message.member().unwrap() == "PropertiesChanged"
{
use dbus::arg::{Array, Dict, Iter, Variant, Get};
let (_, changed, _) = message.get3::<String, Dict<String, Variant<Iter>, Iter>, Array<String, Iter>>();
let mut changed = changed.chain_err(|| ErrorKind::UnexpectedMethodReturn)?;
if let Some((_, mut value)) = changed.find(|&(ref key, _)| &*key == "Active") {
if let Some(active) = Get::get(&mut value.0) {
self.active.store(active, Ordering::SeqCst);
}
}
}
}
Ok(())
}
}
impl Session for LogindSession {
type Error = Error;
fn open(&mut self, path: &Path, _flags: OFlag) -> Result<RawFd> {
if let Some(session) = self.internal.upgrade() {
let stat = stat(path).chain_err(|| ErrorKind::FailedToStatDevice)?;
// TODO handle paused
let (fd, _paused) = LogindSessionImpl::blocking_call(
&*session.conn.borrow(),
"org.freedesktop.login1",
session.session_path.clone(),
"org.freedesktop.login1.Session",
"TakeDevice",
Some(vec![
(major(stat.st_rdev) as u32).into(),
(minor(stat.st_rdev) as u32).into(),
])
)?.get2::<OwnedFd, bool>();
let fd = fd.chain_err(|| ErrorKind::UnexpectedMethodReturn)?.into_fd();
Ok(fd)
} else {
bail!(ErrorKind::SessionLost)
}
}
fn close(&mut self, fd: RawFd) -> Result<()> {
if let Some(session) = self.internal.upgrade() {
let stat = fstat(fd).chain_err(|| ErrorKind::FailedToStatDevice)?;
LogindSessionImpl::blocking_call(
&*session.conn.borrow(),
"org.freedesktop.login1",
session.session_path.clone(),
"org.freedesktop.login1.Session",
"ReleaseDevice",
Some(vec![
(major(stat.st_rdev) as u32).into(),
(minor(stat.st_rdev) as u32).into(),
])
).map(|_| ())
} else {
bail!(ErrorKind::SessionLost)
}
}
fn is_active(&self) -> bool {
if let Some(internal) = self.internal.upgrade() {
internal.active.load(Ordering::SeqCst)
} else {
false
}
}
fn seat(&self) -> String {
self.seat.clone()
}
fn change_vt(&mut self, vt_num: i32) -> Result<()> {
if let Some(session) = self.internal.upgrade() {
LogindSessionImpl::blocking_call(
&*session.conn.borrow_mut(),
"org.freedesktop.login1",
"/org/freedesktop/login1/seat/self",
"org.freedesktop.login1.Seat",
"SwitchTo",
Some(vec![
(vt_num as u32).into(),
])
).map(|_| ())
} else {
bail!(ErrorKind::SessionLost)
}
}
}
/// Ids of registered `SessionObserver`s of the `LogindSessionNotifier`
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct Id(usize);
impl SessionNotifier for LogindSessionNotifier {
type Id = Id;
fn register<S: SessionObserver + 'static>(&mut self, signal: S) -> Id {
self.internal.signals.borrow_mut().push(Some(Box::new(signal)));
Id(self.internal.signals.borrow().len() - 1)
}
fn unregister(&mut self, signal: Id) {
self.internal.signals.borrow_mut()[signal.0] = None;
}
fn is_active(&self) -> bool {
self.internal.active.load(Ordering::SeqCst)
}
fn seat(&self) -> &str {
&self.internal.seat
}
}
pub struct BoundLogindSession {
notifier: LogindSessionNotifier,
watches: Vec<Watch>,
sources: Vec<FdEventSource<Rc<LogindSessionImpl>>>,
}
pub fn logind_session_bind(
notifier: LogindSessionNotifier, evlh: &mut EventLoopHandle
) -> IoResult<BoundLogindSession>
{
let watches = notifier.internal.conn.borrow().watch_fds();
let sources = watches.clone().into_iter().map(|watch| {
let mut interest = FdInterest::empty();
interest.set(FdInterest::READ, watch.readable());
interest.set(FdInterest::WRITE, watch.writable());
evlh.add_fd_event_source(
watch.fd(),
fd_event_source_implementation(),
notifier.internal.clone(),
interest
)
}).collect::<IoResult<Vec<FdEventSource<Rc<LogindSessionImpl>>>>>()?;
Ok(BoundLogindSession {
notifier,
watches,
sources,
})
}
impl BoundLogindSession {
pub fn close(self) -> LogindSessionNotifier {
for source in self.sources {
source.remove();
}
self.notifier
}
}
impl Drop for LogindSessionNotifier {
fn drop(&mut self) {
info!(self.internal.logger, "Closing logind session");
let _ = LogindSessionImpl::blocking_call(
&*self.internal.conn.borrow(),
"org.freedesktop.login1",
self.internal.session_path.clone(),
"org.freedesktop.login1.Session",
"ReleaseControl",
None,
);
}
}
fn fd_event_source_implementation() -> FdEventSourceImpl<Rc<LogindSessionImpl>> {
FdEventSourceImpl {
ready: |evlh, session, fd, interest| {
let conn = session.conn.borrow();
let items = conn.watch_handle(fd, match interest {
x if x.contains(FdInterest::READ) && x.contains(FdInterest::WRITE) =>
WatchEvent::Readable as u32 | WatchEvent::Writable as u32,
x if x.contains(FdInterest::READ) => WatchEvent::Readable as u32,
x if x.contains(FdInterest::WRITE) => WatchEvent::Writable as u32,
_ => return,
});
if let Err(err) = session.handle_signals(evlh, items) {
error!(session.logger, "Error handling dbus signals: {}", err);
}
},
error: |evlh, session, fd, error| {
warn!(session.logger, "Error on dbus connection: {:?}", error);
// handle the remaining messages, they might contain the SessionRemoved event
// in case the server did close the connection.
let conn = session.conn.borrow();
let items = conn.watch_handle(fd, WatchEvent::Error as u32);
if let Err(err) = session.handle_signals(evlh, items) {
error!(session.logger, "Error handling dbus signals: {}", err);
}
},
}
}
error_chain! {
errors {
#[doc = "Failed to connect to dbus system socket"]
FailedDbusConnection {
description("Failed to connect to dbus system socket"),
}
#[doc = "Failed to get session from logind"]
FailedToGetSession {
description("Failed to get session from logind")
}
#[doc = "Failed to get seat from logind"]
FailedToGetSeat {
description("Failed to get seat from logind")
}
#[doc = "Failed to get vt from logind"]
FailedToGetVT {
description("Failed to get vt from logind")
}
#[doc = "Failed to call dbus method"]
FailedToSendDbusCall(bus: BusName<'static>, path: DbusPath<'static>, interface: Interface<'static>, member: Member<'static>) {
description("Failed to call dbus method")
display("Failed to call dbus method for service: {:?}, path: {:?}, interface: {:?}, member: {:?}", bus, path, interface, member),
}
#[doc = "Dbus method call failed"]
DbusCallFailed(bus: BusName<'static>, path: DbusPath<'static>, interface: Interface<'static>, member: Member<'static>) {
description("Dbus method call failed")
display("Dbus message call failed for service: {:?}, path: {:?}, interface: {:?}, member: {:?}", bus, path, interface, member),
}
#[doc = "Dbus method return had unexpected format"]
UnexpectedMethodReturn {
description("Dbus method return returned unexpected format")
}
#[doc = "Failed to setup dbus match rule"]
DbusMatchFailed(rule: String) {
description("Failed to setup dbus match rule"),
display("Failed to setup dbus match rule {}", rule),
}
#[doc = "Failed to stat device"]
FailedToStatDevice {
description("Failed to stat device")
}
#[doc = "Session is already closed"]
SessionLost {
description("Session is already closed")
}
}
}
impl AsErrno for Error {
fn as_errno(&self) -> Option<i32> {
None
}
}

View File

@ -0,0 +1,2 @@
#[cfg(feature = "backend_session_logind")]
pub mod logind;

View File

@ -376,7 +376,7 @@ pub fn direct_session_bind(
info!(notifier.logger, "Session shall become inactive"); info!(notifier.logger, "Session shall become inactive");
for signal in &mut notifier.signals { for signal in &mut notifier.signals {
if let &mut Some(ref mut signal) = signal { if let &mut Some(ref mut signal) = signal {
signal.pause(&mut evlh.state().as_proxy()); signal.pause(&mut evlh.state().as_proxy(), None);
} }
} }
notifier.active.store(false, Ordering::SeqCst); notifier.active.store(false, Ordering::SeqCst);
@ -391,7 +391,7 @@ pub fn direct_session_bind(
} }
for signal in &mut notifier.signals { for signal in &mut notifier.signals {
if let &mut Some(ref mut signal) = signal { if let &mut Some(ref mut signal) = signal {
signal.activate(&mut evlh.state().as_proxy()); signal.activate(&mut evlh.state().as_proxy(), None);
} }
} }
notifier.active.store(true, Ordering::SeqCst); notifier.active.store(true, Ordering::SeqCst);

View File

@ -68,16 +68,26 @@ pub trait SessionNotifier {
/// It might be impossible to interact with devices while the session is disabled. /// It might be impossible to interact with devices while the session is disabled.
/// This interface provides callbacks for when that happens. /// This interface provides callbacks for when that happens.
pub trait SessionObserver { pub trait SessionObserver {
/// Session is about to be paused. /// Session/Device is about to be paused.
/// ///
/// In case the implementor is a `StateToken` the state of the `EventLoop` /// In case the implementor is a `StateToken` the state of the `EventLoop`
/// is provided via a `StateProxy`. /// is provided via a `StateProxy`.
fn pause<'a>(&mut self, state: &mut StateProxy<'a>); ///
/// Session got active again /// If only a specific device shall be closed a device number in the form of
/// (major, minor) is provided. All observers not using the specified device should
/// ignore the signal in that case.
fn pause<'a>(&mut self, state: &mut StateProxy<'a>, device: Option<(u32, u32)>);
/// Session/Device got active again
/// ///
/// In case the implementor is a `StateToken` the state of the `EventLoop` /// In case the implementor is a `StateToken` the state of the `EventLoop`
/// is provided via a `StateProxy`. /// is provided via a `StateProxy`.
fn activate<'a>(&mut self, state: &mut StateProxy<'a>); ///
/// If only a specific device shall be activated again a device number in the form of
/// (major, major, Option<RawFd>) is provided. Optionally the session may decide to replace
/// the currently open file descriptor of the device with a new one. In that case the old one
/// should not be used anymore and be closed. All observers not using the specified device should
/// ignore the signal in that case.
fn activate<'a>(&mut self, state: &mut StateProxy<'a>, device: Option<(u32, u32, Option<RawFd>)>);
} }
impl Session for () { impl Session for () {
@ -163,3 +173,5 @@ impl AsErrno for () {
} }
pub mod direct; pub mod direct;
mod dbus;
pub use self::dbus::*;

View File

@ -178,20 +178,19 @@ impl<
H: DrmHandler<SessionFdDrmDevice> + 'static, H: DrmHandler<SessionFdDrmDevice> + 'static,
S: Session + 'static, S: Session + 'static,
T: UdevHandler<H> + 'static, T: UdevHandler<H> + 'static,
> SessionObserver for StateToken<UdevBackend<H, S, T>> > SessionObserver for StateToken<UdevBackend<H, S, T>> {
{ fn pause<'a>(&mut self, state: &mut StateProxy<'a>, devnum: Option<(u32, u32)>) {
fn pause<'a>(&mut self, state: &mut StateProxy<'a>) {
state.with_value(self, |state, udev| { state.with_value(self, |state, udev| {
for &mut (ref mut device, _) in udev.devices.values_mut() { for &mut (ref mut device, _) in udev.devices.values_mut() {
device.pause(state); device.pause(state, devnum);
} }
}); });
} }
fn activate<'a>(&mut self, state: &mut StateProxy<'a>) { fn activate<'a>(&mut self, state: &mut StateProxy<'a>, devnum: Option<(u32, u32, Option<RawFd>)>) {
state.with_value(self, |state, udev| { state.with_value(self, |state, udev| {
for &mut (ref mut device, _) in udev.devices.values_mut() { for &mut (ref mut device, _) in udev.devices.values_mut() {
device.activate(state); device.activate(state, devnum);
} }
}); });
} }

View File

@ -24,12 +24,10 @@ extern crate gbm;
extern crate input; extern crate input;
#[cfg(feature = "udev")] #[cfg(feature = "udev")]
extern crate udev; extern crate udev;
/* #[cfg(feature = "dbus")]
#[cfg(feature = "backend_session_logind")]
extern crate dbus; extern crate dbus;
#[cfg(feature = "backend_session_logind")] #[cfg(feature = "backend_session_logind")]
extern crate systemd; extern crate systemd;
*/
#[cfg(feature = "backend_winit")] #[cfg(feature = "backend_winit")]
extern crate wayland_client; extern crate wayland_client;
#[cfg(feature = "backend_winit")] #[cfg(feature = "backend_winit")]