wl_backend: safely re-wire input listeners on VT switch
When the session resumes after a VT switch, wlroots may destroy and recreate input devices. Remove old listeners before adding new ones to avoid assertion failure in wlr_keyboard_finish. Initialize all listener links at startup so the first remove is safe.
This commit is contained in:
parent
0801fb7d86
commit
81f60abca7
|
|
@ -380,6 +380,7 @@ struct wl_compositor_state {
|
|||
struct wl_listener backend_new_input_listener;
|
||||
struct wl_listener real_keyboard_key_listener;
|
||||
struct wl_listener real_keyboard_modifiers_listener;
|
||||
struct wl_listener real_keyboard_destroy_listener;
|
||||
struct wl_listener real_pointer_motion_abs_listener;
|
||||
struct wl_listener real_pointer_button_listener;
|
||||
struct wl_listener real_pointer_frame_listener;
|
||||
|
|
@ -475,6 +476,7 @@ struct wl_compositor_state {
|
|||
/* Phase 29 axis listeners (headless pointer + real nested pointer). */
|
||||
struct wl_listener pointer_axis_listener;
|
||||
struct wl_listener real_pointer_axis_listener;
|
||||
struct wl_listener real_pointer_destroy_listener;
|
||||
/* Phase 30: WM dock panel (native Wayland rendering via wm_shm_surface). */
|
||||
struct wm_shm_surface *dock_surface; /* NULL until screen_create_internals */
|
||||
int dock_width; /* pixels reserved on right edge */
|
||||
|
|
@ -1749,6 +1751,40 @@ handle_keyboard_modifiers(struct wl_listener *listener, void *data)
|
|||
* events from the host compositor's seat and must be wired so key presses
|
||||
* and mouse motion reach focused Wayland clients.
|
||||
*/
|
||||
static void
|
||||
handle_keyboard_destroy(struct wl_listener *listener, void *data)
|
||||
{
|
||||
(void)listener; (void)data;
|
||||
wl_list_remove(&wl_state.real_keyboard_key_listener.link);
|
||||
wl_list_remove(&wl_state.real_keyboard_modifiers_listener.link);
|
||||
wl_list_remove(&wl_state.real_keyboard_destroy_listener.link);
|
||||
wl_list_init(&wl_state.real_keyboard_key_listener.link);
|
||||
wl_list_init(&wl_state.real_keyboard_modifiers_listener.link);
|
||||
wl_list_init(&wl_state.real_keyboard_destroy_listener.link);
|
||||
wl_state.real_keyboard_dev = NULL;
|
||||
wl_state.keyboard_dev = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
handle_pointer_destroy(struct wl_listener *listener, void *data)
|
||||
{
|
||||
(void)listener; (void)data;
|
||||
wl_list_remove(&wl_state.pointer_motion_listener.link);
|
||||
wl_list_remove(&wl_state.real_pointer_motion_abs_listener.link);
|
||||
wl_list_remove(&wl_state.real_pointer_button_listener.link);
|
||||
wl_list_remove(&wl_state.real_pointer_frame_listener.link);
|
||||
wl_list_remove(&wl_state.real_pointer_axis_listener.link);
|
||||
wl_list_remove(&wl_state.real_pointer_destroy_listener.link);
|
||||
wl_list_init(&wl_state.pointer_motion_listener.link);
|
||||
wl_list_init(&wl_state.real_pointer_motion_abs_listener.link);
|
||||
wl_list_init(&wl_state.real_pointer_button_listener.link);
|
||||
wl_list_init(&wl_state.real_pointer_frame_listener.link);
|
||||
wl_list_init(&wl_state.real_pointer_axis_listener.link);
|
||||
wl_list_init(&wl_state.real_pointer_destroy_listener.link);
|
||||
wl_state.real_pointer_dev = NULL;
|
||||
wl_state.pointer_dev = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
handle_backend_new_input(struct wl_listener *listener, void *data)
|
||||
{
|
||||
|
|
@ -1761,13 +1797,10 @@ handle_backend_new_input(struct wl_listener *listener, void *data)
|
|||
switch (dev->type) {
|
||||
case WLR_INPUT_DEVICE_KEYBOARD: {
|
||||
struct wlr_keyboard *kb = wlr_keyboard_from_input_device(dev);
|
||||
/* Apply default keymap only if the host hasn't provided one yet */
|
||||
if (wl_state.xkb_keymap && !kb->xkb_state)
|
||||
wlr_keyboard_set_keymap(kb, wl_state.xkb_keymap);
|
||||
wl_state.real_keyboard_dev = dev;
|
||||
wl_state.keyboard_dev = dev;
|
||||
/* Seat may not exist yet if new_input fires during wlr_backend_start()
|
||||
* before wlr_seat_create() is called later in wl_display_open(). */
|
||||
if (wl_state.seat)
|
||||
wlr_seat_set_keyboard(wl_state.seat, kb);
|
||||
wl_state.real_keyboard_key_listener.notify = handle_keyboard_key;
|
||||
|
|
@ -1776,18 +1809,19 @@ handle_backend_new_input(struct wl_listener *listener, void *data)
|
|||
wl_state.real_keyboard_modifiers_listener.notify = handle_keyboard_modifiers;
|
||||
wl_signal_add(&kb->events.modifiers,
|
||||
&wl_state.real_keyboard_modifiers_listener);
|
||||
wwarning("wl_backend: real keyboard wired from nested backend");
|
||||
wl_state.real_keyboard_destroy_listener.notify = handle_keyboard_destroy;
|
||||
wl_signal_add(&dev->events.destroy,
|
||||
&wl_state.real_keyboard_destroy_listener);
|
||||
wwarning("wl_backend: real keyboard wired");
|
||||
break;
|
||||
}
|
||||
case WLR_INPUT_DEVICE_POINTER: {
|
||||
struct wlr_pointer *ptr = wlr_pointer_from_input_device(dev);
|
||||
wl_state.real_pointer_dev = dev;
|
||||
wl_state.pointer_dev = dev;
|
||||
/* Relative motion (libinput / standalone DRM) */
|
||||
wl_state.pointer_motion_listener.notify = handle_pointer_motion;
|
||||
wl_signal_add(&ptr->events.motion,
|
||||
&wl_state.pointer_motion_listener);
|
||||
/* Absolute motion (nested Wayland backend) */
|
||||
wl_state.real_pointer_motion_abs_listener.notify =
|
||||
handle_pointer_motion_absolute;
|
||||
wl_signal_add(&ptr->events.motion_absolute,
|
||||
|
|
@ -1801,6 +1835,9 @@ handle_backend_new_input(struct wl_listener *listener, void *data)
|
|||
wl_state.real_pointer_axis_listener.notify = handle_pointer_axis;
|
||||
wl_signal_add(&ptr->events.axis,
|
||||
&wl_state.real_pointer_axis_listener);
|
||||
wl_state.real_pointer_destroy_listener.notify = handle_pointer_destroy;
|
||||
wl_signal_add(&dev->events.destroy,
|
||||
&wl_state.real_pointer_destroy_listener);
|
||||
wwarning("wl_backend: real pointer wired");
|
||||
break;
|
||||
}
|
||||
|
|
@ -2029,9 +2066,17 @@ wl_display_open(const char *name)
|
|||
|
||||
(void)name; /* Wayland compositor picks its own socket name */
|
||||
|
||||
/* Make Xlib thread-safe before any X11 call. The startup pump thread
|
||||
* runs concurrently with the main thread during wScreenInit(); without
|
||||
* XInitThreads() any concurrent Xlib access is undefined behaviour. */
|
||||
/* Initialize listener links so wl_list_remove is safe before first add */
|
||||
wl_list_init(&wl_state.real_keyboard_key_listener.link);
|
||||
wl_list_init(&wl_state.real_keyboard_modifiers_listener.link);
|
||||
wl_list_init(&wl_state.real_keyboard_destroy_listener.link);
|
||||
wl_list_init(&wl_state.pointer_motion_listener.link);
|
||||
wl_list_init(&wl_state.real_pointer_motion_abs_listener.link);
|
||||
wl_list_init(&wl_state.real_pointer_button_listener.link);
|
||||
wl_list_init(&wl_state.real_pointer_frame_listener.link);
|
||||
wl_list_init(&wl_state.real_pointer_axis_listener.link);
|
||||
wl_list_init(&wl_state.real_pointer_destroy_listener.link);
|
||||
|
||||
XInitThreads();
|
||||
|
||||
/* Install X error handler immediately: Mesa/EGL may open a connection to
|
||||
|
|
|
|||
Loading…
Reference in New Issue