Return the backends to the user if binding fails.

This commit is contained in:
Victor Berger 2018-09-28 18:01:33 +02:00
parent 7f8d32429b
commit bd08f78acd
3 changed files with 44 additions and 18 deletions

View File

@ -6,11 +6,14 @@ use backend::input::Axis;
use backend::session::{AsErrno, Session, SessionObserver}; use backend::session::{AsErrno, Session, SessionObserver};
use input as libinput; use input as libinput;
use input::event; use input::event;
use std::cell::RefCell;
use std::collections::hash_map::{DefaultHasher, Entry, HashMap}; use std::collections::hash_map::{DefaultHasher, Entry, HashMap};
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::io::Error as IoError; use std::io::Error as IoError;
use std::os::unix::io::RawFd; use std::os::unix::io::RawFd;
use std::path::Path; use std::path::Path;
use std::rc::Rc;
use wayland_server::calloop::generic::{EventedRawFd, Generic}; use wayland_server::calloop::generic::{EventedRawFd, Generic};
use wayland_server::calloop::{LoopHandle, Ready, Source}; use wayland_server::calloop::{LoopHandle, Ready, Source};
@ -588,15 +591,24 @@ impl<S: Session> libinput::LibinputInterface for LibinputSessionInterface<S> {
/// Automatically feeds the backend with incoming events without any manual calls to /// Automatically feeds the backend with incoming events without any manual calls to
/// `dispatch_new_events`. Should be used to achieve the smallest possible latency. /// `dispatch_new_events`. Should be used to achieve the smallest possible latency.
pub fn libinput_bind<Data: 'static>( pub fn libinput_bind<Data: 'static>(
mut backend: LibinputInputBackend, backend: LibinputInputBackend,
handle: LoopHandle<Data>, handle: LoopHandle<Data>,
) -> ::std::result::Result<Source<Generic<EventedRawFd>>, IoError> { ) -> ::std::result::Result<Source<Generic<EventedRawFd>>, (IoError, LibinputInputBackend)> {
let mut source = Generic::from_raw_fd(unsafe { backend.context.fd() }); let mut source = Generic::from_raw_fd(unsafe { backend.context.fd() });
source.set_interest(Ready::readable()); source.set_interest(Ready::readable());
handle.insert_source(source, move |_, _| { let backend = Rc::new(RefCell::new(backend));
let fail_backend = backend.clone();
handle
.insert_source(source, move |_, _| {
use backend::input::InputBackend; use backend::input::InputBackend;
if let Err(error) = backend.dispatch_new_events() { if let Err(error) = backend.borrow_mut().dispatch_new_events() {
warn!(backend.logger, "Libinput errored: {}", error); 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)
}) })
} }

View File

@ -148,13 +148,15 @@ impl AutoSession {
pub fn auto_session_bind<Data: 'static>( pub fn auto_session_bind<Data: 'static>(
notifier: AutoSessionNotifier, notifier: AutoSessionNotifier,
handle: &LoopHandle<Data>, handle: &LoopHandle<Data>,
) -> ::std::result::Result<BoundAutoSession, IoError> { ) -> ::std::result::Result<BoundAutoSession, (IoError, AutoSessionNotifier)> {
Ok(match notifier { Ok(match notifier {
#[cfg(feature = "backend_session_logind")] #[cfg(feature = "backend_session_logind")]
AutoSessionNotifier::Logind(logind) => { AutoSessionNotifier::Logind(logind) => BoundAutoSession::Logind(
BoundAutoSession::Logind(logind_session_bind(logind, handle).map_err(|(e, _)| e)?) logind_session_bind(logind, handle).map_err(|(e, n)| (e, AutoSessionNotifier::Logind(n)))?,
} ),
AutoSessionNotifier::Direct(direct) => BoundAutoSession::Direct(direct_session_bind(direct, handle)?), AutoSessionNotifier::Direct(direct) => BoundAutoSession::Direct(
direct_session_bind(direct, handle).map_err(|(e, n)| (e, AutoSessionNotifier::Direct(n)))?,
),
}) })
} }

View File

@ -420,12 +420,24 @@ impl BoundDirectSession {
pub fn direct_session_bind<Data: 'static>( pub fn direct_session_bind<Data: 'static>(
notifier: DirectSessionNotifier, notifier: DirectSessionNotifier,
handle: &LoopHandle<Data>, handle: &LoopHandle<Data>,
) -> ::std::result::Result<BoundDirectSession, IoError> { ) -> ::std::result::Result<BoundDirectSession, (IoError, DirectSessionNotifier)> {
let signal = notifier.signal; 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 notifier = Rc::new(RefCell::new(notifier));
let source = handle.insert_source(Signals::new(&[signal])?, { let fail_notifier = notifier.clone();
let source = handle
.insert_source(source, {
let notifier = notifier.clone(); let notifier = notifier.clone();
move |_, _| notifier.borrow_mut().signal_received() 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 }) Ok(BoundDirectSession { source, notifier })
} }