1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-25 14:22:37 +03:00

wayland: attempt to handle seat changes that impact the keyboard

A couple of times today while debugging things on wayland, I lost
keyboard input to wezterm.

I don't know if that is strictly a wezterm bug, or just a general
wayland bug (not long after, the whole mutter session hung, and
somehow wedged all processes with my uid).

So, this is a quick stab in that direction.
This commit is contained in:
Wez Furlong 2021-02-13 21:07:22 -08:00
parent b4ded64e14
commit 41cb9d3f38
2 changed files with 62 additions and 10 deletions

View File

@ -16,6 +16,7 @@ use std::time::{Duration, Instant};
use toolkit::environment::Environment; use toolkit::environment::Environment;
use toolkit::reexports::calloop::{EventLoop, EventSource, Interest, Mode, Poll, Readiness, Token}; use toolkit::reexports::calloop::{EventLoop, EventSource, Interest, Mode, Poll, Readiness, Token};
use toolkit::reexports::client::Display; use toolkit::reexports::client::Display;
use toolkit::seat::SeatListener;
use toolkit::WaylandSource; use toolkit::WaylandSource;
toolkit::default_environment!(MyEnvironment, desktop); toolkit::default_environment!(MyEnvironment, desktop);
@ -37,6 +38,7 @@ pub struct WaylandConnection {
pub(crate) gl_connection: RefCell<Option<Rc<crate::egl::GlConnection>>>, pub(crate) gl_connection: RefCell<Option<Rc<crate::egl::GlConnection>>>,
pub(crate) pointer: PointerDispatcher, pub(crate) pointer: PointerDispatcher,
pub(crate) keyboard: KeyboardDispatcher, pub(crate) keyboard: KeyboardDispatcher,
seat_listener: SeatListener,
pub(crate) environment: RefCell<Environment<MyEnvironment>>, pub(crate) environment: RefCell<Environment<MyEnvironment>>,
event_q: RefCell<EventLoop<()>>, event_q: RefCell<EventLoop<()>>,
pub(crate) display: RefCell<Display>, pub(crate) display: RefCell<Display>,
@ -52,14 +54,17 @@ impl WaylandConnection {
let mut pointer = None; let mut pointer = None;
for seat in environment.get_all_seats() { for seat in environment.get_all_seats() {
if let Some((has_kbd, has_ptr)) = toolkit::seat::with_seat_data(&seat, |seat_data| { if let Some((has_kbd, has_ptr, name)) =
toolkit::seat::with_seat_data(&seat, |seat_data| {
( (
seat_data.has_keyboard && !seat_data.defunct, seat_data.has_keyboard && !seat_data.defunct,
seat_data.has_pointer && !seat_data.defunct, seat_data.has_pointer && !seat_data.defunct,
seat_data.name.clone(),
) )
}) { })
{
if has_kbd { if has_kbd {
keyboard.register(event_loop.handle(), &seat)?; keyboard.register(event_loop.handle(), &seat, &name)?;
} }
if has_ptr { if has_ptr {
pointer.replace(PointerDispatcher::register( pointer.replace(PointerDispatcher::register(
@ -72,6 +77,36 @@ impl WaylandConnection {
} }
} }
let seat_listener;
{
let loop_handle = event_loop.handle();
let keyboard = keyboard.clone();
seat_listener = environment.listen_for_seats(move |seat, seat_data, _| {
if seat_data.has_keyboard {
if seat_data.defunct {
keyboard.deregister(loop_handle.clone(), &seat_data.name);
} else {
if let Err(err) =
keyboard.register(loop_handle.clone(), &seat, &seat_data.name)
{
log::error!("{:#}", err);
}
}
}
if seat_data.has_pointer {
// TODO: ideally do something similar to the keyboard state,
// but the pointer state has a lot of other stuff floating
// around it so it's not so clear cut right now.
log::error!(
"seat {} changed; it has a pointer that is
defunct={} and we don't know what to do about it",
seat_data.name,
seat_data.defunct
);
}
});
}
WaylandSource::new(event_q) WaylandSource::new(event_q)
.quick_insert(event_loop.handle()) .quick_insert(event_loop.handle())
.map_err(|e| anyhow!("failed to setup WaylandSource: {:?}", e))?; .map_err(|e| anyhow!("failed to setup WaylandSource: {:?}", e))?;
@ -86,6 +121,7 @@ impl WaylandConnection {
windows: RefCell::new(HashMap::new()), windows: RefCell::new(HashMap::new()),
keyboard, keyboard,
pointer: pointer.unwrap(), pointer: pointer.unwrap(),
seat_listener,
gl_connection: RefCell::new(None), gl_connection: RefCell::new(None),
}) })
} }

View File

@ -3,10 +3,11 @@ use anyhow::anyhow;
use smithay_client_toolkit as toolkit; use smithay_client_toolkit as toolkit;
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use toolkit::reexports::calloop::LoopHandle; use toolkit::reexports::calloop::{LoopHandle, Source};
use toolkit::seat::keyboard::{ use toolkit::seat::keyboard::{
map_keyboard_repeat, Event as KbEvent, KeyState, ModifiersState, RepeatKind, map_keyboard_repeat, Event as KbEvent, KeyState, ModifiersState, RepeatKind, RepeatSource,
}; };
use wayland_client::protocol::wl_keyboard::WlKeyboard;
use wayland_client::protocol::wl_seat::WlSeat; use wayland_client::protocol::wl_seat::WlSeat;
use wayland_client::protocol::wl_surface::WlSurface; use wayland_client::protocol::wl_surface::WlSurface;
use wayland_client::Attached; use wayland_client::Attached;
@ -16,6 +17,7 @@ use wezterm_input_types::*;
struct Inner { struct Inner {
active_surface_id: u32, active_surface_id: u32,
surface_to_window_id: HashMap<u32, usize>, surface_to_window_id: HashMap<u32, usize>,
by_name: HashMap<String, (WlKeyboard, Source<RepeatSource>)>,
} }
impl Inner { impl Inner {
@ -64,9 +66,10 @@ impl KeyboardDispatcher {
&self, &self,
loop_handle: LoopHandle<()>, loop_handle: LoopHandle<()>,
seat: &Attached<WlSeat>, seat: &Attached<WlSeat>,
name: &str,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
let inner = Arc::clone(&self.inner); let inner = Arc::clone(&self.inner);
let (_kbd, _source) = map_keyboard_repeat( let pair = map_keyboard_repeat(
loop_handle, loop_handle,
&seat, &seat,
None, None,
@ -90,9 +93,22 @@ impl KeyboardDispatcher {
) )
.map_err(|e| anyhow!("Failed to configure keyboard callback: {:?}", e))?; .map_err(|e| anyhow!("Failed to configure keyboard callback: {:?}", e))?;
self.inner
.lock()
.unwrap()
.by_name
.insert(name.to_string(), pair);
Ok(()) Ok(())
} }
pub fn deregister(&self, loop_handle: LoopHandle<()>, name: &str) {
if let Some((kbd, source)) = self.inner.lock().unwrap().by_name.remove(name) {
kbd.release();
loop_handle.remove(source);
}
}
pub fn add_window(&self, window_id: usize, surface: &WlSurface) { pub fn add_window(&self, window_id: usize, surface: &WlSurface) {
let mut inner = self.inner.lock().unwrap(); let mut inner = self.inner.lock().unwrap();
inner inner