diff --git a/src/backend/libinput.rs b/src/backend/libinput.rs index e00a9bf..f29a344 100644 --- a/src/backend/libinput.rs +++ b/src/backend/libinput.rs @@ -6,11 +6,14 @@ use backend::input::Axis; use backend::session::{AsErrno, Session, SessionObserver}; use input as libinput; use input::event; + +use std::cell::RefCell; use std::collections::hash_map::{DefaultHasher, Entry, HashMap}; use std::hash::{Hash, Hasher}; use std::io::Error as IoError; use std::os::unix::io::RawFd; use std::path::Path; +use std::rc::Rc; use wayland_server::calloop::generic::{EventedRawFd, Generic}; use wayland_server::calloop::{LoopHandle, Ready, Source}; @@ -588,15 +591,24 @@ impl libinput::LibinputInterface for LibinputSessionInterface { /// Automatically feeds the backend with incoming events without any manual calls to /// `dispatch_new_events`. Should be used to achieve the smallest possible latency. pub fn libinput_bind( - mut backend: LibinputInputBackend, + backend: LibinputInputBackend, handle: LoopHandle, -) -> ::std::result::Result>, IoError> { +) -> ::std::result::Result>, (IoError, LibinputInputBackend)> { let mut source = Generic::from_raw_fd(unsafe { backend.context.fd() }); source.set_interest(Ready::readable()); - handle.insert_source(source, move |_, _| { - use backend::input::InputBackend; - if let Err(error) = backend.dispatch_new_events() { - warn!(backend.logger, "Libinput errored: {}", error); - } - }) + let backend = Rc::new(RefCell::new(backend)); + let fail_backend = backend.clone(); + handle + .insert_source(source, move |_, _| { + use backend::input::InputBackend; + if let Err(error) = backend.borrow_mut().dispatch_new_events() { + warn!(backend.borrow().logger, "Libinput errored: {}", error); + } + }).map_err(move |e| { + // the backend in the closure should already have been dropped + let backend = Rc::try_unwrap(fail_backend) + .unwrap_or_else(|_| unreachable!()) + .into_inner(); + (e, backend) + }) } diff --git a/src/backend/session/auto.rs b/src/backend/session/auto.rs index 17b1ecb..652d11b 100644 --- a/src/backend/session/auto.rs +++ b/src/backend/session/auto.rs @@ -148,13 +148,15 @@ impl AutoSession { pub fn auto_session_bind( notifier: AutoSessionNotifier, handle: &LoopHandle, -) -> ::std::result::Result { +) -> ::std::result::Result { Ok(match notifier { #[cfg(feature = "backend_session_logind")] - AutoSessionNotifier::Logind(logind) => { - BoundAutoSession::Logind(logind_session_bind(logind, handle).map_err(|(e, _)| e)?) - } - AutoSessionNotifier::Direct(direct) => BoundAutoSession::Direct(direct_session_bind(direct, handle)?), + AutoSessionNotifier::Logind(logind) => BoundAutoSession::Logind( + logind_session_bind(logind, handle).map_err(|(e, n)| (e, AutoSessionNotifier::Logind(n)))?, + ), + AutoSessionNotifier::Direct(direct) => BoundAutoSession::Direct( + direct_session_bind(direct, handle).map_err(|(e, n)| (e, AutoSessionNotifier::Direct(n)))?, + ), }) } diff --git a/src/backend/session/direct.rs b/src/backend/session/direct.rs index 66d4bcf..c987e13 100644 --- a/src/backend/session/direct.rs +++ b/src/backend/session/direct.rs @@ -420,13 +420,25 @@ impl BoundDirectSession { pub fn direct_session_bind( notifier: DirectSessionNotifier, handle: &LoopHandle, -) -> ::std::result::Result { +) -> ::std::result::Result { let signal = notifier.signal; + let source = match Signals::new(&[signal]) { + Ok(s) => s, + Err(e) => return Err((e, notifier)), + }; let notifier = Rc::new(RefCell::new(notifier)); - let source = handle.insert_source(Signals::new(&[signal])?, { - let notifier = notifier.clone(); - move |_, _| notifier.borrow_mut().signal_received() - })?; + let fail_notifier = notifier.clone(); + let source = handle + .insert_source(source, { + let notifier = notifier.clone(); + move |_, _| notifier.borrow_mut().signal_received() + }).map_err(move |e| { + // the backend in the closure should already have been dropped + let notifier = Rc::try_unwrap(fail_notifier) + .unwrap_or_else(|_| unreachable!()) + .into_inner(); + (e, notifier) + })?; Ok(BoundDirectSession { source, notifier }) }