From 4971278a257e9d4de52a3cb8369001540a2fcdf5 Mon Sep 17 00:00:00 2001 From: Drakulix Date: Wed, 24 Jan 2018 01:29:53 +0100 Subject: [PATCH 01/15] Remove unused type parameter --- src/backend/session/direct.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/backend/session/direct.rs b/src/backend/session/direct.rs index 41dbe4a..27659aa 100644 --- a/src/backend/session/direct.rs +++ b/src/backend/session/direct.rs @@ -365,12 +365,9 @@ impl SessionNotifier for DirectSessionNotifier { /// Allows the `DirectSessionNotifier` to listen for the incoming signals signalling the session state. /// If you don't use this function `DirectSessionNotifier` will not correctly tell you the current /// session state. -pub fn direct_session_bind( - notifier: DirectSessionNotifier, evlh: &mut EventLoopHandle, _logger: L -) -> IoResult> -where - L: Into>, -{ +pub fn direct_session_bind( + notifier: DirectSessionNotifier, evlh: &mut EventLoopHandle +) -> IoResult> { let signal = notifier.signal; evlh.add_signal_event_source( From b16c62b19f1f5e1ae09ea946976546d7c458ebfd Mon Sep 17 00:00:00 2001 From: Drakulix Date: Wed, 24 Jan 2018 00:10:00 +0100 Subject: [PATCH 02/15] Add logind session --- Cargo.toml | 5 +- src/backend/drm/mod.rs | 21 +- src/backend/libinput.rs | 19 +- src/backend/session/dbus/logind.rs | 502 +++++++++++++++++++++++++++++ src/backend/session/dbus/mod.rs | 2 + src/backend/session/direct.rs | 4 +- src/backend/session/mod.rs | 20 +- src/backend/udev.rs | 11 +- src/lib.rs | 4 +- 9 files changed, 566 insertions(+), 22 deletions(-) create mode 100644 src/backend/session/dbus/logind.rs create mode 100644 src/backend/session/dbus/mod.rs diff --git a/Cargo.toml b/Cargo.toml index 8f006dd..cab35f8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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 } input = { version = "0.4.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"] } image = "0.17.0" error-chain = "0.11.0" @@ -37,11 +39,12 @@ rand = "0.3" ctrlc = { version = "3.0", features = ["termination"] } [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_drm = ["drm", "gbm"] backend_libinput = ["input"] backend_session = [] backend_session_udev = ["udev", "backend_session"] +backend_session_logind = ["dbus", "systemd", "backend_session"] backend_udev = ["udev", "backend_drm", "backend_session_udev"] renderer_glium = ["glium"] diff --git a/src/backend/drm/mod.rs b/src/backend/drm/mod.rs index 57817da..d2a270f 100644 --- a/src/backend/drm/mod.rs +++ b/src/backend/drm/mod.rs @@ -221,7 +221,7 @@ use drm::control::framebuffer; use drm::result::Error as DrmError; use gbm::Device as GbmDevice; use nix; -use nix::sys::stat::{dev_t, fstat}; +use nix::sys::stat::{self, dev_t, fstat}; use std::collections::HashMap; use std::hash::{Hash, Hasher}; use std::io::Result as IoResult; @@ -597,8 +597,14 @@ where #[cfg(feature = "backend_session")] impl SessionObserver for StateToken> { - 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); + 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; if let Err(err) = device.drop_master() { error!( @@ -608,8 +614,17 @@ impl SessionObserver for StateToken> { } } - fn activate<'a>(&mut self, state: &mut StateProxy<'a>) { + fn activate<'a>(&mut self, state: &mut StateProxy<'a>, devnum: Option<(u32, u32, Option)>) { 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; if let Err(err) = device.set_master() { crit!( diff --git a/src/backend/libinput.rs b/src/backend/libinput.rs index e81a41d..5628e2b 100644 --- a/src/backend/libinput.rs +++ b/src/backend/libinput.rs @@ -14,6 +14,12 @@ use std::rc::Rc; use wayland_server::{EventLoopHandle, StateProxy}; 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`. /// /// Tracks input of all devices given manually or via a udev seat to a provided libinput @@ -568,12 +574,19 @@ impl From for backend::MouseButtonState { #[cfg(feature = "backend_session")] 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() } - fn activate<'a>(&mut self, _state: &mut StateProxy<'a>) { - // TODO Is this the best way to handle this failure? + fn activate<'a>(&mut self, _state: &mut StateProxy<'a>, _device: Option<(u32, u32, Option)>) { + // 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"); } } diff --git a/src/backend/session/dbus/logind.rs b/src/backend/session/dbus/logind.rs new file mode 100644 index 0000000..17ce24c --- /dev/null +++ b/src/backend/session/dbus/logind.rs @@ -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, + session_path: DbusPath<'static>, + active: AtomicBool, + signals: RefCell>>>, + seat: String, + logger: ::slog::Logger, +} + +#[derive(Clone)] +pub struct LogindSession { + internal: Weak, + seat: String, +} + +pub struct LogindSessionNotifier { + internal: Rc +} + +impl LogindSession { + pub fn new(logger: L) -> Result<(LogindSession, LogindSessionNotifier)> + where + L: Into> + { + 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::>() + .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> + ) -> Result + where + D: Into>, + P: Into>, + I: Into>, + M: Into>, + { + 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::(); + 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::(); + 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::, Iter>, Array>(); + 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 { + 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::(); + 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(&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, + sources: Vec>>, +} + +pub fn logind_session_bind( + notifier: LogindSessionNotifier, evlh: &mut EventLoopHandle +) -> IoResult +{ + 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::>>>>()?; + + 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> { + 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 { + None + } +} diff --git a/src/backend/session/dbus/mod.rs b/src/backend/session/dbus/mod.rs new file mode 100644 index 0000000..cc0676f --- /dev/null +++ b/src/backend/session/dbus/mod.rs @@ -0,0 +1,2 @@ +#[cfg(feature = "backend_session_logind")] +pub mod logind; diff --git a/src/backend/session/direct.rs b/src/backend/session/direct.rs index 27659aa..3a61b71 100644 --- a/src/backend/session/direct.rs +++ b/src/backend/session/direct.rs @@ -376,7 +376,7 @@ pub fn direct_session_bind( info!(notifier.logger, "Session shall become inactive"); for signal in &mut notifier.signals { 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); @@ -391,7 +391,7 @@ pub fn direct_session_bind( } for signal in &mut notifier.signals { 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); diff --git a/src/backend/session/mod.rs b/src/backend/session/mod.rs index 0d16259..3fd8ff8 100644 --- a/src/backend/session/mod.rs +++ b/src/backend/session/mod.rs @@ -68,16 +68,26 @@ pub trait SessionNotifier { /// It might be impossible to interact with devices while the session is disabled. /// This interface provides callbacks for when that happens. 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` /// 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` /// 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) 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)>); } impl Session for () { @@ -163,3 +173,5 @@ impl AsErrno for () { } pub mod direct; +mod dbus; +pub use self::dbus::*; diff --git a/src/backend/udev.rs b/src/backend/udev.rs index b85b4b2..c90936f 100644 --- a/src/backend/udev.rs +++ b/src/backend/udev.rs @@ -178,20 +178,19 @@ impl< H: DrmHandler + 'static, S: Session + 'static, T: UdevHandler + 'static, -> SessionObserver for StateToken> -{ - fn pause<'a>(&mut self, state: &mut StateProxy<'a>) { +> SessionObserver for StateToken> { + fn pause<'a>(&mut self, state: &mut StateProxy<'a>, devnum: Option<(u32, u32)>) { state.with_value(self, |state, udev| { 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)>) { state.with_value(self, |state, udev| { for &mut (ref mut device, _) in udev.devices.values_mut() { - device.activate(state); + device.activate(state, devnum); } }); } diff --git a/src/lib.rs b/src/lib.rs index 928e1a8..b5f4b4d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,12 +24,10 @@ extern crate gbm; extern crate input; #[cfg(feature = "udev")] extern crate udev; -/* -#[cfg(feature = "backend_session_logind")] +#[cfg(feature = "dbus")] extern crate dbus; #[cfg(feature = "backend_session_logind")] extern crate systemd; -*/ #[cfg(feature = "backend_winit")] extern crate wayland_client; #[cfg(feature = "backend_winit")] From a768e298f2b48cd0f5b225d7336f2a174fc6bc68 Mon Sep 17 00:00:00 2001 From: Drakulix Date: Wed, 24 Jan 2018 01:30:06 +0100 Subject: [PATCH 03/15] Add auto backend --- src/backend/session/auto.rs | 198 ++++++++++++++++++++++++++++++++++++ src/backend/session/mod.rs | 1 + 2 files changed, 199 insertions(+) create mode 100644 src/backend/session/auto.rs diff --git a/src/backend/session/auto.rs b/src/backend/session/auto.rs new file mode 100644 index 0000000..3540952 --- /dev/null +++ b/src/backend/session/auto.rs @@ -0,0 +1,198 @@ +use std::io::{Result as IoResult}; +use std::rc::Rc; +use std::cell::RefCell; +use std::os::unix::io::RawFd; +use std::path::Path; +use nix::fcntl::OFlag; +use wayland_server::{EventLoopHandle}; +use wayland_server::sources::SignalEventSource; + +use super::{Session, SessionNotifier, SessionObserver, AsErrno}; +#[cfg(feature = "backend_session_logind")] +use super::logind::{self, LogindSession, LogindSessionNotifier, BoundLogindSession, logind_session_bind}; +use super::direct::{self, DirectSession, DirectSessionNotifier, direct_session_bind}; + +#[derive(Clone)] +pub enum AutoSession { + #[cfg(feature = "backend_session_logind")] + Logind(LogindSession), + Direct(Rc>), +} + +pub enum AutoSessionNotifier { + #[cfg(feature = "backend_session_logind")] + Logind(LogindSessionNotifier), + Direct(DirectSessionNotifier), +} + +pub enum BoundAutoSession { + #[cfg(feature = "backend_session_logind")] + Logind(BoundLogindSession), + Direct(SignalEventSource), +} + +#[derive(PartialEq, Eq)] +pub struct AutoId(AutoIdInternal); +#[derive(PartialEq, Eq)] +enum AutoIdInternal { + #[cfg(feature = "backend_session_logind")] + Logind(logind::Id), + Direct(direct::Id), +} + +impl AutoSession { + #[cfg(feature = "backend_session_logind")] + pub fn new(logger: L) -> Option<(AutoSession, AutoSessionNotifier)> + where L: Into> + { + let logger = ::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(logger: L) -> Option<(AutoSession, AutoSessionNotifier)> + where L: Into> + { + let logger = ::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(notifier: AutoSessionNotifier, evlh: &mut EventLoopHandle) -> IoResult { + Ok(match notifier { + #[cfg(feature = "backend_session_logind")] + AutoSessionNotifier::Logind(logind) => BoundAutoSession::Logind(logind_session_bind(logind, evlh)?), + AutoSessionNotifier::Direct(direct) => BoundAutoSession::Direct(direct_session_bind(direct, evlh)?), + }) +} + +impl Session for AutoSession { + type Error = Error; + + fn open(&mut self, path: &Path, flags: OFlag) -> Result { + match self { + #[cfg(feature = "backend_session_logind")] + &mut AutoSession::Logind(ref mut logind) => logind.open(path, flags).map_err(|e| e.into()), + &mut 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")] + &mut AutoSession::Logind(ref mut logind) => logind.close(fd).map_err(|e| e.into()), + &mut 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")] + &mut AutoSession::Logind(ref mut logind) => logind.change_vt(vt).map_err(|e| e.into()), + &mut 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(&mut self, signal: S) -> Self::Id { + match self { + #[cfg(feature = "backend_session_logind")] + &mut AutoSessionNotifier::Logind(ref mut logind) => AutoId(AutoIdInternal::Logind(logind.register(signal))), + &mut AutoSessionNotifier::Direct(ref mut direct) => AutoId(AutoIdInternal::Direct(direct.register(signal))), + } + } + fn unregister(&mut self, signal: Self::Id) { + 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!(), + } + } + + fn is_active(&self) -> bool { + match self { + #[cfg(feature = "backend_session_logind")] + &AutoSessionNotifier::Logind(ref logind) => logind.is_active(), + &AutoSessionNotifier::Direct(ref direct) => direct.is_active(), + } + } + fn seat(&self) -> &str { + match self { + #[cfg(feature = "backend_session_logind")] + &AutoSessionNotifier::Logind(ref logind) => logind.seat(), + &AutoSessionNotifier::Direct(ref direct) => direct.seat(), + } + } +} + +impl BoundAutoSession { + pub fn remove(self) -> AutoSessionNotifier { + match self { + #[cfg(feature = "backend_session_logind")] + BoundAutoSession::Logind(logind) => AutoSessionNotifier::Logind(logind.close()), + BoundAutoSession::Direct(source) => AutoSessionNotifier::Direct(source.remove()), + } + } +} + +error_chain! { + links { + Logind(logind::Error, logind::ErrorKind) #[cfg(feature = "backend_session_logind")]; + } + + foreign_links { + Direct(::nix::Error); + } +} + +impl AsErrno for Error { + fn as_errno(&self) -> Option { + //TODO figure this out, I don't see a way.. + None + } +} diff --git a/src/backend/session/mod.rs b/src/backend/session/mod.rs index 3fd8ff8..d0a3320 100644 --- a/src/backend/session/mod.rs +++ b/src/backend/session/mod.rs @@ -172,6 +172,7 @@ impl AsErrno for () { } } +pub mod auto; pub mod direct; mod dbus; pub use self::dbus::*; From 11c9f2b0fb606267e67f001792e4b07519b81a03 Mon Sep 17 00:00:00 2001 From: Drakulix Date: Sat, 27 Jan 2018 13:07:35 +0100 Subject: [PATCH 04/15] Make udev example use new auto session --- examples/udev.rs | 41 ++++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/examples/udev.rs b/examples/udev.rs index 37c3796..7eb3d29 100644 --- a/examples/udev.rs +++ b/examples/udev.rs @@ -39,7 +39,7 @@ use smithay::backend::input::{self, Event, InputBackend, InputHandler, KeyState, use smithay::backend::libinput::{libinput_bind, LibinputInputBackend, LibinputSessionInterface, PointerAxisEvent as LibinputPointerAxisEvent}; use smithay::backend::session::{Session, SessionNotifier}; -use smithay::backend::session::direct::{direct_session_bind, DirectSession}; +use smithay::backend::session::auto::{auto_session_bind, AutoSession}; use smithay::backend::udev::{primary_gpu, udev_backend_bind, SessionFdDrmDevice, UdevBackend, UdevHandler}; use smithay::wayland::compositor::{CompositorToken, SubsurfaceRole, TraversalAction}; use smithay::wayland::compositor::roles::Role; @@ -67,6 +67,7 @@ struct LibinputInputHandler { pointer_location: Rc>, screen_size: (u32, u32), serial: u32, + session: AutoSession, running: Arc, } @@ -93,14 +94,32 @@ impl InputHandler for LibinputInputHandler { let keycode = evt.key(); let state = evt.state(); debug!(self.log, "key"; "keycode" => keycode, "state" => format!("{:?}", state)); - let serial = self.next_serial(); + + // we cannot borrow `self` into the closure, because we need self.keyboard. + // but rust does not borrow all fields separately, so we need to do that manually... + let running = &self.running; + let mut session = &mut self.session; + let log = &self.log; self.keyboard - .input(keycode, state, serial, |modifiers, keysym| { - if modifiers.ctrl && modifiers.alt && keysym == xkb::KEY_BackSpace { - self.running.store(false, Ordering::SeqCst); + .input(keycode, state, serial, move |modifiers, keysym| { + debug!(log, "keysym"; "state" => format!("{:?}", state), "mods" => format!("{:?}", modifiers), "keysym" => xkbcommon::xkb::keysym_get_name(keysym)); + if modifiers.ctrl && modifiers.alt && keysym == xkb::KEY_BackSpace && state == KeyState::Pressed { + info!(log, "Stopping example using Ctrl+Alt+Backspace"); + running.store(false, Ordering::SeqCst); + false + } else if modifiers.logo && keysym == xkb::KEY_q { + info!(log, "Stopping example using Logo+Q"); + running.store(false, Ordering::SeqCst); + false + } else if modifiers.ctrl && modifiers.alt && keysym == xkb::KEY_XF86Switch_VT_1 && state == KeyState::Pressed { + info!(log, "Trying to switch to vt 1"); + if let Err(err) = session.change_vt(1) { + error!(log, "Error switching to vt 1: {}", err); + } false } else if modifiers.logo && keysym == xkb::KEY_Return && state == KeyState::Pressed { + info!(log, "Launching terminal"); let _ = Command::new("weston-terminal").spawn(); false } else { @@ -228,10 +247,9 @@ fn main() { init_shell(&mut event_loop, log.clone(), active_egl_context.clone()); /* - * Initialize session on the current tty + * Initialize session */ - let (session, mut notifier) = DirectSession::new(None, log.clone()).unwrap(); - let session = Rc::new(RefCell::new(session)); + let (session, mut notifier) = AutoSession::new(log.clone()).unwrap(); let running = Arc::new(AtomicBool::new(true)); let r = running.clone(); @@ -318,8 +336,8 @@ fn main() { * Initialize libinput backend */ let mut libinput_context = Libinput::new_from_udev::< - LibinputSessionInterface>>, - >(session.into(), &context); + LibinputSessionInterface, + >(session.clone().into(), &context); let libinput_session_id = notifier.register(libinput_context.clone()); libinput_context.udev_assign_seat(&seat).unwrap(); let mut libinput_backend = LibinputInputBackend::new(libinput_context, log.clone()); @@ -333,12 +351,13 @@ fn main() { pointer_location, screen_size: (w, h), serial: 0, + session: session, running: running.clone(), }, ); let libinput_event_source = libinput_bind(libinput_backend, &mut event_loop).unwrap(); - let session_event_source = direct_session_bind(notifier, &mut event_loop, log.clone()).unwrap(); + let session_event_source = auto_session_bind(notifier, &mut event_loop).unwrap(); let udev_event_source = udev_backend_bind(&mut event_loop, udev_token).unwrap(); while running.load(Ordering::SeqCst) { From 495c492e507ef8e7bd40de23f6af751fd2ecb97e Mon Sep 17 00:00:00 2001 From: Drakulix Date: Sat, 27 Jan 2018 13:05:36 +0100 Subject: [PATCH 05/15] Fix trying to become drm master on logind session --- src/backend/drm/mod.rs | 48 ++++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/src/backend/drm/mod.rs b/src/backend/drm/mod.rs index d2a270f..f310382 100644 --- a/src/backend/drm/mod.rs +++ b/src/backend/drm/mod.rs @@ -251,6 +251,7 @@ pub struct DrmDevice { device_id: dev_t, backends: HashMap>>, active: bool, + priviledged: bool, logger: ::slog::Logger, } @@ -319,13 +320,17 @@ impl DrmDevice { device_id, old_state: HashMap::new(), active: true, + priviledged: true, logger: log.clone(), }; info!(log, "DrmDevice initializing"); - // we want to mode-set, so we better be the master - drm.set_master().chain_err(|| ErrorKind::DrmMasterFailed)?; + // we want to mode-set, so we better be the master, if we run via a tty session + if let Err(_) = drm.set_master() { + warn!(log, "Unable to become drm master, assuming unpriviledged mode"); + drm.priviledged = false; + }; let res_handles = drm.resource_handles().chain_err(|| { ErrorKind::DrmDev(format!( @@ -506,11 +511,13 @@ impl Drop for DrmDevice { ); } } - if let Err(err) = self.drop_master() { - error!( - self.logger, - "Failed to drop drm master state. Error: {}", err - ); + if self.priviledged { + if let Err(err) = self.drop_master() { + error!( + self.logger, + "Failed to drop drm master state. Error: {}", err + ); + } } } } @@ -606,11 +613,13 @@ impl SessionObserver for StateToken> { } } device.active = false; - if let Err(err) = device.drop_master() { - error!( - device.logger, - "Failed to drop drm master state. Error: {}", err - ); + if device.priviledged { + if let Err(err) = device.drop_master() { + error!( + device.logger, + "Failed to drop drm master state. Error: {}", err + ); + } } } @@ -622,16 +631,19 @@ impl SessionObserver for StateToken> { { return; } else if let Some(fd) = fd { + info!(device.logger, "Replacing fd"); nix::unistd::dup2(device.as_raw_fd(), fd).expect("Failed to replace file descriptor of drm device"); } } device.active = true; - if let Err(err) = device.set_master() { - crit!( - device.logger, - "Failed to acquire drm master again. Error: {}", - err - ); + if device.priviledged { + if let Err(err) = device.set_master() { + crit!( + device.logger, + "Failed to acquire drm master again. Error: {}", + err + ); + } } let mut crtcs = Vec::new(); for (crtc, backend) in device.backends.iter() { From 5411209bb575fe599bd46fb4b0d1c64906dd902e Mon Sep 17 00:00:00 2001 From: Drakulix Date: Sat, 27 Jan 2018 13:04:42 +0100 Subject: [PATCH 06/15] Fix libinput panic on tty switch --- src/backend/libinput.rs | 196 +++++++++++++++++++++------------------- 1 file changed, 104 insertions(+), 92 deletions(-) diff --git a/src/backend/libinput.rs b/src/backend/libinput.rs index 5628e2b..c43dc96 100644 --- a/src/backend/libinput.rs +++ b/src/backend/libinput.rs @@ -381,7 +381,8 @@ impl backend::InputBackend for LibinputInputBackend { .filter(|x| x.seat() == device_seat) .any(|x| x.has_capability(libinput::DeviceCapability::Touch)); } else { - panic!("Seat changed that was never created") + warn!(self.logger, "Seat changed that was never created"); + continue; } // check if the seat has any other devices @@ -393,13 +394,18 @@ impl backend::InputBackend for LibinputInputBackend { handler.on_seat_destroyed(evlh, &seat); } } else { - panic!("Seat destroyed that was never created"); + warn!(self.logger, "Seat destroyed that was never created"); + continue; } // it has, notify about updates } else if let Some(ref mut handler) = self.handler { - let seat = &self.seats[&device_seat]; - trace!(self.logger, "Calling on_seat_changed with {:?}", seat); - handler.on_seat_changed(evlh, seat); + if let Some(seat) = self.seats.get(&device_seat) { + trace!(self.logger, "Calling on_seat_changed with {:?}", seat); + handler.on_seat_changed(evlh, &seat); + } else { + warn!(self.logger, "Seat changed that was never created"); + continue; + } } } } @@ -411,38 +417,40 @@ impl backend::InputBackend for LibinputInputBackend { use input::event::touch::*; if let Some(ref mut handler) = self.handler { let device_seat = touch_event.device().seat(); - let seat = &self.seats - .get(&device_seat) - .expect("Recieved touch event of non existing Seat"); - match touch_event { - TouchEvent::Down(down_event) => { - trace!(self.logger, "Calling on_touch_down with {:?}", down_event); - handler.on_touch_down(evlh, seat, down_event) - } - TouchEvent::Motion(motion_event) => { - trace!( - self.logger, - "Calling on_touch_motion with {:?}", - motion_event - ); - handler.on_touch_motion(evlh, seat, motion_event) - } - TouchEvent::Up(up_event) => { - trace!(self.logger, "Calling on_touch_up with {:?}", up_event); - handler.on_touch_up(evlh, seat, up_event) - } - TouchEvent::Cancel(cancel_event) => { - trace!( - self.logger, - "Calling on_touch_cancel with {:?}", - cancel_event - ); - handler.on_touch_cancel(evlh, seat, cancel_event) - } - TouchEvent::Frame(frame_event) => { - trace!(self.logger, "Calling on_touch_frame with {:?}", frame_event); - handler.on_touch_frame(evlh, seat, frame_event) + if let &Some(ref seat) = &self.seats.get(&device_seat) { + match touch_event { + TouchEvent::Down(down_event) => { + trace!(self.logger, "Calling on_touch_down with {:?}", down_event); + handler.on_touch_down(evlh, seat, down_event) + } + TouchEvent::Motion(motion_event) => { + trace!( + self.logger, + "Calling on_touch_motion with {:?}", + motion_event + ); + handler.on_touch_motion(evlh, seat, motion_event) + } + TouchEvent::Up(up_event) => { + trace!(self.logger, "Calling on_touch_up with {:?}", up_event); + handler.on_touch_up(evlh, seat, up_event) + } + TouchEvent::Cancel(cancel_event) => { + trace!( + self.logger, + "Calling on_touch_cancel with {:?}", + cancel_event + ); + handler.on_touch_cancel(evlh, seat, cancel_event) + } + TouchEvent::Frame(frame_event) => { + trace!(self.logger, "Calling on_touch_frame with {:?}", frame_event); + handler.on_touch_frame(evlh, seat, frame_event) + } } + } else { + warn!(self.logger, "Recieved touch event of non existing Seat"); + continue; } } } @@ -451,11 +459,13 @@ impl backend::InputBackend for LibinputInputBackend { match keyboard_event { KeyboardEvent::Key(key_event) => if let Some(ref mut handler) = self.handler { let device_seat = key_event.device().seat(); - let seat = &self.seats - .get(&device_seat) - .expect("Recieved key event of non existing Seat"); - trace!(self.logger, "Calling on_keyboard_key with {:?}", key_event); - handler.on_keyboard_key(evlh, seat, key_event); + if let &Some(ref seat) = &self.seats.get(&device_seat) { + trace!(self.logger, "Calling on_keyboard_key with {:?}", key_event); + handler.on_keyboard_key(evlh, seat, key_event); + } else { + warn!(self.logger, "Recieved key event of non existing Seat"); + continue; + } }, } } @@ -463,67 +473,69 @@ impl backend::InputBackend for LibinputInputBackend { use input::event::pointer::*; if let Some(ref mut handler) = self.handler { let device_seat = pointer_event.device().seat(); - let seat = &self.seats - .get(&device_seat) - .expect("Recieved pointer event of non existing Seat"); - match pointer_event { - PointerEvent::Motion(motion_event) => { - trace!( - self.logger, - "Calling on_pointer_move with {:?}", - motion_event - ); - handler.on_pointer_move(evlh, seat, motion_event); - } - PointerEvent::MotionAbsolute(motion_abs_event) => { - trace!( - self.logger, - "Calling on_pointer_move_absolute with {:?}", - motion_abs_event - ); - handler.on_pointer_move_absolute(evlh, seat, motion_abs_event); - } - PointerEvent::Axis(axis_event) => { - let rc_axis_event = Rc::new(axis_event); - if rc_axis_event.has_axis(Axis::Vertical) { + if let &Some(ref seat) = &self.seats.get(&device_seat) { + match pointer_event { + PointerEvent::Motion(motion_event) => { trace!( self.logger, - "Calling on_pointer_axis for Axis::Vertical with {:?}", - *rc_axis_event - ); - handler.on_pointer_axis( - evlh, - seat, - self::PointerAxisEvent { - axis: Axis::Vertical, - event: rc_axis_event.clone(), - }, + "Calling on_pointer_move with {:?}", + motion_event ); + handler.on_pointer_move(evlh, seat, motion_event); } - if rc_axis_event.has_axis(Axis::Horizontal) { + PointerEvent::MotionAbsolute(motion_abs_event) => { trace!( self.logger, - "Calling on_pointer_axis for Axis::Horizontal with {:?}", - *rc_axis_event + "Calling on_pointer_move_absolute with {:?}", + motion_abs_event ); - handler.on_pointer_axis( - evlh, - seat, - self::PointerAxisEvent { - axis: Axis::Horizontal, - event: rc_axis_event.clone(), - }, + handler.on_pointer_move_absolute(evlh, seat, motion_abs_event); + } + PointerEvent::Axis(axis_event) => { + let rc_axis_event = Rc::new(axis_event); + if rc_axis_event.has_axis(Axis::Vertical) { + trace!( + self.logger, + "Calling on_pointer_axis for Axis::Vertical with {:?}", + *rc_axis_event + ); + handler.on_pointer_axis( + evlh, + seat, + self::PointerAxisEvent { + axis: Axis::Vertical, + event: rc_axis_event.clone(), + }, + ); + } + if rc_axis_event.has_axis(Axis::Horizontal) { + trace!( + self.logger, + "Calling on_pointer_axis for Axis::Horizontal with {:?}", + *rc_axis_event + ); + handler.on_pointer_axis( + evlh, + seat, + self::PointerAxisEvent { + axis: Axis::Horizontal, + event: rc_axis_event.clone(), + }, + ); + } + } + PointerEvent::Button(button_event) => { + trace!( + self.logger, + "Calling on_pointer_button with {:?}", + button_event ); + handler.on_pointer_button(evlh, seat, button_event); } } - PointerEvent::Button(button_event) => { - trace!( - self.logger, - "Calling on_pointer_button with {:?}", - button_event - ); - handler.on_pointer_button(evlh, seat, button_event); - } + } else { + warn!(self.logger, "Recieved pointer event of non existing Seat"); + continue; } } } From 310bc94a20fdda57bb60f46d2dcddf5efc85d35d Mon Sep 17 00:00:00 2001 From: Drakulix Date: Sat, 27 Jan 2018 13:05:52 +0100 Subject: [PATCH 07/15] Fix disappearing cursor after tty switch --- src/backend/drm/backend.rs | 10 +++++----- src/backend/drm/mod.rs | 21 ++++++++++++++++++++- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/backend/drm/backend.rs b/src/backend/drm/backend.rs index 76bfbac..95f5223 100644 --- a/src/backend/drm/backend.rs +++ b/src/backend/drm/backend.rs @@ -24,8 +24,8 @@ pub struct DrmBackend { } pub(crate) struct DrmBackendInternal { - context: Rc, GbmDevice>>, - cursor: Cell>, + pub(crate) context: Rc, GbmDevice>>, + pub(crate) cursor: Cell<(BufferObject<()>, (u32, u32))>, current_frame_buffer: Cell, front_buffer: Cell>, next_buffer: Cell>>, @@ -96,14 +96,14 @@ impl DrmBackend { })?; front_bo.set_userdata(fb).unwrap(); - let cursor = Cell::new(context + let cursor = Cell::new((context .create_buffer_object( 1, 1, GbmFormat::ARGB8888, BufferObjectFlags::CURSOR | BufferObjectFlags::WRITE, ) - .chain_err(|| ErrorKind::GbmInitFailed)?); + .chain_err(|| ErrorKind::GbmInitFailed)?, (0,0))); Ok(DrmBackend { backend: Rc::new(DrmBackendInternal { @@ -455,7 +455,7 @@ impl GraphicsBackend for DrmBackend { } // and store it - self.backend.cursor.set(cursor); + self.backend.cursor.set((cursor, hotspot)); Ok(()) } } diff --git a/src/backend/drm/mod.rs b/src/backend/drm/mod.rs index f310382..3a3d590 100644 --- a/src/backend/drm/mod.rs +++ b/src/backend/drm/mod.rs @@ -219,7 +219,7 @@ use drm::control::{connector, crtc, encoder, Mode, ResourceInfo}; use drm::control::Device as ControlDevice; use drm::control::framebuffer; use drm::result::Error as DrmError; -use gbm::Device as GbmDevice; +use gbm::{Device as GbmDevice, BufferObject}; use nix; use nix::sys::stat::{self, dev_t, fstat}; use std::collections::HashMap; @@ -655,6 +655,25 @@ impl SessionObserver for StateToken> { "Failed to activate crtc ({:?}) again. Error: {}", crtc, err ); } + // reset cursor + { + let &(ref cursor, ref hotspot) : &(BufferObject<()>, (u32, u32)) + = unsafe { &*backend.cursor.as_ptr() }; + if crtc::set_cursor2( + &*backend.context, + *crtc, + cursor, + ((*hotspot).0 as i32, (*hotspot).1 as i32), + ).is_err() + { + if let Err(err) = crtc::set_cursor(&*backend.context, *crtc, cursor) { + error!( + device.logger, + "Failed to reset cursor. Error: {}", err + ); + } + } + } } else { crtcs.push(*crtc); } From 4501ca5fe15d63cb3736300c3aa6ea934d35065c Mon Sep 17 00:00:00 2001 From: Drakulix Date: Sat, 27 Jan 2018 13:06:48 +0100 Subject: [PATCH 08/15] Fix weston-terminal spawn in example --- examples/udev.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/udev.rs b/examples/udev.rs index 7eb3d29..53deb7b 100644 --- a/examples/udev.rs +++ b/examples/udev.rs @@ -48,6 +48,7 @@ use smithay::wayland::seat::{KeyboardHandle, PointerHandle, Seat}; use smithay::wayland::shm::init_shm_global; use std::cell::RefCell; use std::collections::HashMap; +use std::env; use std::io::Error as IoError; use std::path::PathBuf; use std::process::Command; @@ -236,6 +237,7 @@ fn main() { */ let name = display.add_socket_auto().unwrap().into_string().unwrap(); println!("Listening on socket: {}", name); + env::set_var("WAYLAND_DISPLAY", name); let display = Rc::new(display); /* From 20e10612b9efa3994c45c113546682c381c50ba8 Mon Sep 17 00:00:00 2001 From: Drakulix Date: Sat, 27 Jan 2018 13:38:21 +0100 Subject: [PATCH 09/15] Add documentation for logind/auto session --- src/backend/session/auto.rs | 60 +++++++++++++++++++++++++-- src/backend/session/dbus/logind.rs | 66 +++++++++++++++++++++++++----- src/backend/session/direct.rs | 8 ++-- 3 files changed, 116 insertions(+), 18 deletions(-) diff --git a/src/backend/session/auto.rs b/src/backend/session/auto.rs index 3540952..b9bac5b 100644 --- a/src/backend/session/auto.rs +++ b/src/backend/session/auto.rs @@ -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>), } +/// `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), } +/// 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(logger: L) -> Option<(AutoSession, AutoSessionNotifier)> where L: Into> @@ -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 { 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"]; } } diff --git a/src/backend/session/dbus/logind.rs b/src/backend/session/dbus/logind.rs index 17ce24c..4aa415f 100644 --- a/src/backend/session/dbus/logind.rs +++ b/src/backend/session/dbus/logind.rs @@ -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, seat: String, } +/// `SessionNotifier` via the logind dbus interface pub struct LogindSessionNotifier { internal: Rc } impl LogindSession { + /// Tries to create a new session via the logind dbus interface. pub fn new(logger: L) -> Result<(LogindSession, LogindSessionNotifier)> where L: Into> @@ -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::>() .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, + _watches: Vec, sources: Vec>>, } +/// 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 @@ -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", diff --git a/src/backend/session/direct.rs b/src/backend/session/direct.rs index 3a61b71..e8c8e27 100644 --- a/src/backend/session/direct.rs +++ b/src/backend/session/direct.rs @@ -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(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> { From 525c9b60c460aa5cfee79dbc3ce244ec5758ad7d Mon Sep 17 00:00:00 2001 From: Drakulix Date: Sat, 27 Jan 2018 13:50:24 +0100 Subject: [PATCH 10/15] rustfmt --- examples/udev.rs | 13 +- src/backend/drm/backend.rs | 19 +-- src/backend/drm/mod.rs | 38 +++--- src/backend/session/auto.rs | 71 ++++++---- src/backend/session/dbus/logind.rs | 210 ++++++++++++++++------------- src/backend/udev.rs | 3 +- src/lib.rs | 8 +- 7 files changed, 211 insertions(+), 151 deletions(-) diff --git a/examples/udev.rs b/examples/udev.rs index 53deb7b..c6c227f 100644 --- a/examples/udev.rs +++ b/examples/udev.rs @@ -105,7 +105,9 @@ impl InputHandler for LibinputInputHandler { self.keyboard .input(keycode, state, serial, move |modifiers, keysym| { debug!(log, "keysym"; "state" => format!("{:?}", state), "mods" => format!("{:?}", modifiers), "keysym" => xkbcommon::xkb::keysym_get_name(keysym)); - if modifiers.ctrl && modifiers.alt && keysym == xkb::KEY_BackSpace && state == KeyState::Pressed { + if modifiers.ctrl && modifiers.alt && keysym == xkb::KEY_BackSpace + && state == KeyState::Pressed + { info!(log, "Stopping example using Ctrl+Alt+Backspace"); running.store(false, Ordering::SeqCst); false @@ -113,7 +115,9 @@ impl InputHandler for LibinputInputHandler { info!(log, "Stopping example using Logo+Q"); running.store(false, Ordering::SeqCst); false - } else if modifiers.ctrl && modifiers.alt && keysym == xkb::KEY_XF86Switch_VT_1 && state == KeyState::Pressed { + } else if modifiers.ctrl && modifiers.alt && keysym == xkb::KEY_XF86Switch_VT_1 + && state == KeyState::Pressed + { info!(log, "Trying to switch to vt 1"); if let Err(err) = session.change_vt(1) { error!(log, "Error switching to vt 1: {}", err); @@ -337,9 +341,8 @@ fn main() { /* * Initialize libinput backend */ - let mut libinput_context = Libinput::new_from_udev::< - LibinputSessionInterface, - >(session.clone().into(), &context); + let mut libinput_context = + Libinput::new_from_udev::>(session.clone().into(), &context); let libinput_session_id = notifier.register(libinput_context.clone()); libinput_context.udev_assign_seat(&seat).unwrap(); let mut libinput_backend = LibinputInputBackend::new(libinput_context, log.clone()); diff --git a/src/backend/drm/backend.rs b/src/backend/drm/backend.rs index 95f5223..72b537c 100644 --- a/src/backend/drm/backend.rs +++ b/src/backend/drm/backend.rs @@ -96,14 +96,17 @@ impl DrmBackend { })?; front_bo.set_userdata(fb).unwrap(); - let cursor = Cell::new((context - .create_buffer_object( - 1, - 1, - GbmFormat::ARGB8888, - BufferObjectFlags::CURSOR | BufferObjectFlags::WRITE, - ) - .chain_err(|| ErrorKind::GbmInitFailed)?, (0,0))); + let cursor = Cell::new(( + context + .create_buffer_object( + 1, + 1, + GbmFormat::ARGB8888, + BufferObjectFlags::CURSOR | BufferObjectFlags::WRITE, + ) + .chain_err(|| ErrorKind::GbmInitFailed)?, + (0, 0), + )); Ok(DrmBackend { backend: Rc::new(DrmBackendInternal { diff --git a/src/backend/drm/mod.rs b/src/backend/drm/mod.rs index 3a3d590..9a76cea 100644 --- a/src/backend/drm/mod.rs +++ b/src/backend/drm/mod.rs @@ -219,7 +219,7 @@ use drm::control::{connector, crtc, encoder, Mode, ResourceInfo}; use drm::control::Device as ControlDevice; use drm::control::framebuffer; use drm::result::Error as DrmError; -use gbm::{Device as GbmDevice, BufferObject}; +use gbm::{BufferObject, Device as GbmDevice}; use nix; use nix::sys::stat::{self, dev_t, fstat}; use std::collections::HashMap; @@ -328,7 +328,10 @@ impl DrmDevice { // we want to mode-set, so we better be the master, if we run via a tty session if let Err(_) = drm.set_master() { - warn!(log, "Unable to become drm master, assuming unpriviledged mode"); + warn!( + log, + "Unable to become drm master, assuming unpriviledged mode" + ); drm.priviledged = false; }; @@ -607,10 +610,10 @@ impl SessionObserver for StateToken> { fn pause<'a>(&mut self, state: &mut StateProxy<'a>, devnum: Option<(u32, u32)>) { 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; - } + if major as u64 != stat::major(device.device_id) || minor as u64 != stat::minor(device.device_id) + { + return; + } } device.active = false; if device.priviledged { @@ -626,14 +629,14 @@ impl SessionObserver for StateToken> { fn activate<'a>(&mut self, state: &mut StateProxy<'a>, devnum: Option<(u32, u32, Option)>) { 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) + if major as u64 != stat::major(device.device_id) || minor as u64 != stat::minor(device.device_id) { - return; - } else if let Some(fd) = fd { - info!(device.logger, "Replacing fd"); - nix::unistd::dup2(device.as_raw_fd(), fd).expect("Failed to replace file descriptor of drm device"); - } + return; + } else if let Some(fd) = fd { + info!(device.logger, "Replacing fd"); + nix::unistd::dup2(device.as_raw_fd(), fd) + .expect("Failed to replace file descriptor of drm device"); + } } device.active = true; if device.priviledged { @@ -657,8 +660,8 @@ impl SessionObserver for StateToken> { } // reset cursor { - let &(ref cursor, ref hotspot) : &(BufferObject<()>, (u32, u32)) - = unsafe { &*backend.cursor.as_ptr() }; + let &(ref cursor, ref hotspot): &(BufferObject<()>, (u32, u32)) = + unsafe { &*backend.cursor.as_ptr() }; if crtc::set_cursor2( &*backend.context, *crtc, @@ -667,10 +670,7 @@ impl SessionObserver for StateToken> { ).is_err() { if let Err(err) = crtc::set_cursor(&*backend.context, *crtc, cursor) { - error!( - device.logger, - "Failed to reset cursor. Error: {}", err - ); + error!(device.logger, "Failed to reset cursor. Error: {}", err); } } } diff --git a/src/backend/session/auto.rs b/src/backend/session/auto.rs index b9bac5b..56c4e64 100644 --- a/src/backend/session/auto.rs +++ b/src/backend/session/auto.rs @@ -29,20 +29,19 @@ //! automatically by the `UdevBackend`, if not done manually). //! ``` -use std::io::{Result as IoResult}; -use std::rc::Rc; +use super::{AsErrno, Session, SessionNotifier, SessionObserver}; +use super::direct::{self, direct_session_bind, DirectSession, DirectSessionNotifier}; +#[cfg(feature = "backend_session_logind")] +use super::logind::{self, logind_session_bind, BoundLogindSession, LogindSession, LogindSessionNotifier}; +use nix::fcntl::OFlag; use std::cell::RefCell; +use std::io::Result as IoResult; use std::os::unix::io::RawFd; use std::path::Path; -use nix::fcntl::OFlag; -use wayland_server::{EventLoopHandle}; +use std::rc::Rc; +use wayland_server::EventLoopHandle; use wayland_server::sources::SignalEventSource; -use super::{Session, SessionNotifier, SessionObserver, AsErrno}; -#[cfg(feature = "backend_session_logind")] -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 { @@ -80,8 +79,7 @@ pub enum BoundAutoSession { pub struct AutoId(AutoIdInternal); #[derive(PartialEq, Eq)] enum AutoIdInternal { - #[cfg(feature = "backend_session_logind")] - Logind(logind::Id), + #[cfg(feature = "backend_session_logind")] Logind(logind::Id), Direct(direct::Id), } @@ -89,22 +87,32 @@ impl AutoSession { /// Tries to create a new session via the best available interface. #[cfg(feature = "backend_session_logind")] pub fn new(logger: L) -> Option<(AutoSession, AutoSessionNotifier)> - where L: Into> + where + L: Into>, { let logger = ::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))), + 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))), + 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"); + error!( + logger, + "Could not create any session, possibilities exhausted" + ); None } } @@ -114,17 +122,24 @@ impl AutoSession { #[cfg(not(feature = "backend_session_logind"))] pub fn new(logger: L) -> Option<(AutoSession, AutoSessionNotifier)> - where L: Into> + where + L: Into>, { let logger = ::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))), + 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"); + error!( + logger, + "Could not create any session, possibilities exhausted" + ); None } } @@ -136,7 +151,9 @@ impl AutoSession { /// 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 { +pub fn auto_session_bind( + notifier: AutoSessionNotifier, evlh: &mut EventLoopHandle +) -> IoResult { Ok(match notifier { #[cfg(feature = "backend_session_logind")] AutoSessionNotifier::Logind(logind) => BoundAutoSession::Logind(logind_session_bind(logind, evlh)?), @@ -192,15 +209,23 @@ impl SessionNotifier for AutoSessionNotifier { fn register(&mut self, signal: S) -> Self::Id { match self { #[cfg(feature = "backend_session_logind")] - &mut AutoSessionNotifier::Logind(ref mut logind) => AutoId(AutoIdInternal::Logind(logind.register(signal))), - &mut AutoSessionNotifier::Direct(ref mut direct) => AutoId(AutoIdInternal::Direct(direct.register(signal))), + &mut AutoSessionNotifier::Logind(ref mut logind) => { + AutoId(AutoIdInternal::Logind(logind.register(signal))) + } + &mut AutoSessionNotifier::Direct(ref mut direct) => { + AutoId(AutoIdInternal::Direct(direct.register(signal))) + } } } fn unregister(&mut self, signal: Self::Id) { 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), + (&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!(), } } diff --git a/src/backend/session/dbus/logind.rs b/src/backend/session/dbus/logind.rs index 4aa415f..84918a3 100644 --- a/src/backend/session/dbus/logind.rs +++ b/src/backend/session/dbus/logind.rs @@ -30,17 +30,18 @@ //! automatically by the `UdevBackend`, if not done manually). //! ``` -use ::backend::session::{AsErrno, Session, SessionNotifier, SessionObserver}; +use backend::session::{AsErrno, Session, SessionNotifier, SessionObserver}; +use dbus::{BusName, BusType, Connection, ConnectionItem, ConnectionItems, Interface, Member, Message, + MessageItem, OwnedFd, Path as DbusPath, Watch, WatchEvent}; use nix::fcntl::OFlag; -use nix::sys::stat::{stat, fstat, major, minor}; +use nix::sys::stat::{fstat, major, minor, stat}; 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::rc::{Rc, Weak}; 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}; @@ -62,14 +63,14 @@ pub struct LogindSession { /// `SessionNotifier` via the logind dbus interface pub struct LogindSessionNotifier { - internal: Rc + internal: Rc, } impl LogindSession { /// Tries to create a new session via the logind dbus interface. pub fn new(logger: L) -> Result<(LogindSession, LogindSessionNotifier)> where - L: Into> + L: Into>, { let logger = ::slog_or_stdlog(logger) .new(o!("smithay_module" => "backend_session", "session_type" => "logind")); @@ -88,35 +89,50 @@ impl LogindSession { "/org/freedesktop/login1", "org.freedesktop.login1.Manager", "GetSession", - Some(vec![session_id.clone().into()]) + Some(vec![session_id.clone().into()]), )?.get1::>() - .chain_err(|| ErrorKind::UnexpectedMethodReturn)?; + .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',\ - 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))?; + 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))?; // Activate (switch to) the session and take control LogindSessionImpl::blocking_call( @@ -153,9 +169,7 @@ impl LogindSession { internal: Rc::downgrade(&internal), seat, }, - LogindSessionNotifier { - internal, - } + LogindSessionNotifier { internal }, )) } } @@ -171,14 +185,9 @@ impl LogindSessionNotifier { } 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> + fn blocking_call<'d, 'p, 'i, 'm, D, P, I, M>( + conn: &Connection, destination: D, path: P, interface: I, method: M, + arguments: Option>, ) -> Result where D: Into>, @@ -198,21 +207,26 @@ impl LogindSessionImpl { }; let mut message = conn.send_with_reply_and_block(message, 1000) - .chain_err(|| ErrorKind::FailedToSendDbusCall( - destination.clone(), - path.clone(), - interface.clone(), - method.clone() - ))?; + .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() - ))) + Err(err) => Err(Error::with_chain( + err, + ErrorKind::DbusCallFailed( + destination.clone(), + path.clone(), + interface.clone(), + method.clone(), + ), + )), } } @@ -221,7 +235,7 @@ impl LogindSessionImpl { let message = if let ConnectionItem::Signal(ref s) = item { s } else { - continue + continue; }; if &*message.interface().unwrap() == "org.freedesktop.login1.Manager" && &*message.member().unwrap() == "SessionRemoved" @@ -243,7 +257,10 @@ impl LogindSessionImpl { 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); + 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))); @@ -260,14 +277,15 @@ impl LogindSessionImpl { self.session_path.clone(), "org.freedesktop.login1.Session", "PauseDeviceComplete", - Some(vec![major.into(), minor.into()]) + Some(vec![major.into(), minor.into()]), )?; } } else if &*message.member().unwrap() == "ResumeDevice" { let (major, minor, fd) = message.get3::(); let major = major.chain_err(|| ErrorKind::UnexpectedMethodReturn)?; let minor = minor.chain_err(|| ErrorKind::UnexpectedMethodReturn)?; - let fd = fd.chain_err(|| ErrorKind::UnexpectedMethodReturn)?.into_fd(); + 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 { @@ -278,9 +296,10 @@ impl LogindSessionImpl { } else if &*message.interface().unwrap() == "org.freedesktop.DBus.Properties" && &*message.member().unwrap() == "PropertiesChanged" { - use dbus::arg::{Array, Dict, Iter, Variant, Get}; + use dbus::arg::{Array, Dict, Get, Iter, Variant}; - let (_, changed, _) = message.get3::, Iter>, Array>(); + let (_, changed, _) = + message.get3::, Iter>, Array>(); 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) { @@ -303,15 +322,16 @@ impl Session for LogindSession { let (fd, _paused) = LogindSessionImpl::blocking_call( &*session.conn.borrow(), "org.freedesktop.login1", - session.session_path.clone(), + 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::(); - let fd = fd.chain_err(|| ErrorKind::UnexpectedMethodReturn)?.into_fd(); + let fd = fd.chain_err(|| ErrorKind::UnexpectedMethodReturn)? + .into_fd(); Ok(fd) } else { bail!(ErrorKind::SessionLost) @@ -324,13 +344,13 @@ impl Session for LogindSession { LogindSessionImpl::blocking_call( &*session.conn.borrow(), "org.freedesktop.login1", - session.session_path.clone(), + 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) @@ -354,12 +374,10 @@ impl Session for LogindSession { LogindSessionImpl::blocking_call( &*session.conn.borrow_mut(), "org.freedesktop.login1", - "/org/freedesktop/login1/seat/self", + "/org/freedesktop/login1/seat/self", "org.freedesktop.login1.Seat", "SwitchTo", - Some(vec![ - (vt_num as u32).into(), - ]) + Some(vec![(vt_num as u32).into()]), ).map(|_| ()) } else { bail!(ErrorKind::SessionLost) @@ -375,7 +393,10 @@ impl SessionNotifier for LogindSessionNotifier { type Id = Id; fn register(&mut self, signal: S) -> Id { - self.internal.signals.borrow_mut().push(Some(Box::new(signal))); + self.internal + .signals + .borrow_mut() + .push(Some(Box::new(signal))); Id(self.internal.signals.borrow().len() - 1) } fn unregister(&mut self, signal: Id) { @@ -409,20 +430,23 @@ pub struct BoundLogindSession { /// session state and call it's `SessionObservers`. pub fn logind_session_bind( notifier: LogindSessionNotifier, evlh: &mut EventLoopHandle -) -> IoResult -{ +) -> IoResult { 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::>>>>()?; + 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::>>>>()?; Ok(BoundLogindSession { notifier, @@ -460,13 +484,17 @@ fn fd_event_source_implementation() -> FdEventSourceImpl> 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, - }); + 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); } diff --git a/src/backend/udev.rs b/src/backend/udev.rs index c90936f..aad9472 100644 --- a/src/backend/udev.rs +++ b/src/backend/udev.rs @@ -178,7 +178,8 @@ impl< H: DrmHandler + 'static, S: Session + 'static, T: UdevHandler + 'static, -> SessionObserver for StateToken> { +> SessionObserver for StateToken> +{ fn pause<'a>(&mut self, state: &mut StateProxy<'a>, devnum: Option<(u32, u32)>) { state.with_value(self, |state, udev| { for &mut (ref mut device, _) in udev.devices.values_mut() { diff --git a/src/lib.rs b/src/lib.rs index b5f4b4d..ec1d923 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,18 +16,18 @@ extern crate wayland_server; extern crate wayland_sys; extern crate xkbcommon; +#[cfg(feature = "dbus")] +extern crate dbus; #[cfg(feature = "backend_drm")] extern crate drm; #[cfg(feature = "backend_drm")] extern crate gbm; #[cfg(feature = "backend_libinput")] extern crate input; -#[cfg(feature = "udev")] -extern crate udev; -#[cfg(feature = "dbus")] -extern crate dbus; #[cfg(feature = "backend_session_logind")] extern crate systemd; +#[cfg(feature = "udev")] +extern crate udev; #[cfg(feature = "backend_winit")] extern crate wayland_client; #[cfg(feature = "backend_winit")] From 1d042d04e1b69e66fea7a1dfbd29a2ea131d6e01 Mon Sep 17 00:00:00 2001 From: Drakulix Date: Sun, 28 Jan 2018 18:18:06 +0100 Subject: [PATCH 11/15] fix vagga build --- examples/udev.rs | 2 +- vagga.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/udev.rs b/examples/udev.rs index c6c227f..4f11611 100644 --- a/examples/udev.rs +++ b/examples/udev.rs @@ -376,7 +376,7 @@ fn main() { println!("Bye Bye"); - let mut notifier = session_event_source.remove(); + let mut notifier = session_event_source.unbind(); notifier.unregister(udev_session_id); notifier.unregister(libinput_session_id); diff --git a/vagga.yaml b/vagga.yaml index e85e4ae..9518ea5 100644 --- a/vagga.yaml +++ b/vagga.yaml @@ -6,7 +6,7 @@ containers: setup: - !UbuntuRelease { codename: artful } - !UbuntuUniverse - - !Install [build-essential, wget, curl, pkg-config, file, openssl, sudo, ca-certificates, libssl-dev, cmake, libudev-dev, libgbm-dev, libxkbcommon-dev, libegl1-mesa-dev, libwayland-dev, libinput-dev] + - !Install [build-essential, wget, curl, pkg-config, file, openssl, sudo, ca-certificates, libssl-dev, cmake, libudev-dev, libgbm-dev, libxkbcommon-dev, libegl1-mesa-dev, libwayland-dev, libinput-dev, libsystemd-dev, libdbus-1-dev] stable: auto-clean: true From 2017d8cd165869f4867a221a08943da42a136969 Mon Sep 17 00:00:00 2001 From: Drakulix Date: Thu, 1 Feb 2018 14:57:04 +0100 Subject: [PATCH 12/15] use systemd crates.io release --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index cab35f8..a4ae995 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ glium = { version = "0.19.0", optional = true, default-features = false } input = { version = "0.4.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 } +systemd = { version = "^0.2.0", optional = true } wayland-protocols = { version = "0.12.5", features = ["unstable_protocols", "server"] } image = "0.17.0" error-chain = "0.11.0" From e3113caa7274bc9bd38bd41eddfa803a1bb5da7f Mon Sep 17 00:00:00 2001 From: Drakulix Date: Sun, 18 Feb 2018 13:46:26 +0100 Subject: [PATCH 13/15] Add new travis feature for logind --- .travis.yml | 1 + src/backend/session/auto.rs | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 73bb244..1243de1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,6 +36,7 @@ env: - FEATURES="backend_udev" - FEATURES="backend_session" - FEATURES="backend_session_udev" + - FEATURES="backend_session_logind" - FEATURES="renderer_glium" # test default features - FEATURES="default" diff --git a/src/backend/session/auto.rs b/src/backend/session/auto.rs index 56c4e64..7c6530a 100644 --- a/src/backend/session/auto.rs +++ b/src/backend/session/auto.rs @@ -79,7 +79,8 @@ pub enum BoundAutoSession { pub struct AutoId(AutoIdInternal); #[derive(PartialEq, Eq)] enum AutoIdInternal { - #[cfg(feature = "backend_session_logind")] Logind(logind::Id), + #[cfg(feature = "backend_session_logind")] + Logind(logind::Id), Direct(direct::Id), } From 5725d1bb348d3b323ab1535ff9aa4933678c4e6a Mon Sep 17 00:00:00 2001 From: Drakulix Date: Tue, 20 Feb 2018 17:35:19 +0100 Subject: [PATCH 14/15] Remove broken ctrlc helper --- Cargo.toml | 1 - examples/udev.rs | 6 ------ 2 files changed, 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a4ae995..7b77650 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,7 +36,6 @@ gl_generator = "0.7" slog-term = "2.3" slog-async = "2.2" rand = "0.3" -ctrlc = { version = "3.0", features = ["termination"] } [features] default = ["backend_winit", "backend_drm", "backend_libinput", "backend_udev", "renderer_glium", "backend_session_logind"] diff --git a/examples/udev.rs b/examples/udev.rs index 4f11611..d8139db 100644 --- a/examples/udev.rs +++ b/examples/udev.rs @@ -15,8 +15,6 @@ extern crate slog; extern crate slog_async; extern crate slog_term; -extern crate ctrlc; - mod helpers; use drm::control::{Device as ControlDevice, ResourceInfo}; @@ -258,10 +256,6 @@ fn main() { let (session, mut notifier) = AutoSession::new(log.clone()).unwrap(); let running = Arc::new(AtomicBool::new(true)); - let r = running.clone(); - ctrlc::set_handler(move || { - r.store(false, Ordering::SeqCst); - }).expect("Error setting Ctrl-C handler"); let pointer_location = Rc::new(RefCell::new((0.0, 0.0))); From 2294e7981488952e7f97c0856fc71a72424dd41e Mon Sep 17 00:00:00 2001 From: Drakulix Date: Tue, 20 Feb 2018 17:37:44 +0100 Subject: [PATCH 15/15] Reset drm device into text mode on tty switch --- src/backend/drm/mod.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/backend/drm/mod.rs b/src/backend/drm/mod.rs index 9a76cea..d4260e5 100644 --- a/src/backend/drm/mod.rs +++ b/src/backend/drm/mod.rs @@ -615,6 +615,21 @@ impl SessionObserver for StateToken> { return; } } + for (handle, &(ref info, ref connectors)) in device.old_state.iter() { + if let Err(err) = crtc::set( + &*device.context, + *handle, + info.fb(), + connectors, + info.position(), + info.mode(), + ) { + error!( + device.logger, + "Failed to reset crtc ({:?}). Error: {}", handle, err + ); + } + } device.active = false; if device.priviledged { if let Err(err) = device.drop_master() {