From 024177cecb5bfad228804656e17ac02ac6fd96bf Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Mon, 21 Apr 2014 19:42:58 -0500 Subject: [PATCH] desktop-shell: Properly handle seat hotplugging Previously, desktop-shell would only create its internal shell_seat object for each seat available when the desktop-shell module is loaded. This is a problem any time seats are created dynamically. In particular, the Wayland and RDP backends create seats on an as-needed basis and they weren't getting picked up proprely by desktop-shell. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=77649 --- desktop-shell/shell.c | 84 ++++++++++++++++++++++++++----------------- desktop-shell/shell.h | 1 + 2 files changed, 53 insertions(+), 32 deletions(-) diff --git a/desktop-shell/shell.c b/desktop-shell/shell.c index 66b7618b..7631f1b8 100644 --- a/desktop-shell/shell.c +++ b/desktop-shell/shell.c @@ -217,6 +217,10 @@ struct shell_seat { struct wl_listener seat_destroy_listener; struct weston_surface *focused_surface; + struct wl_listener caps_changed_listener; + struct wl_listener pointer_focus_listener; + struct wl_listener keyboard_focus_listener; + struct { struct weston_pointer_grab grab; struct wl_list surfaces_list; @@ -1984,19 +1988,6 @@ handle_pointer_focus(struct wl_listener *listener, void *data) ping_handler(view->surface, serial); } -static void -create_pointer_focus_listener(struct weston_seat *seat) -{ - struct wl_listener *listener; - - if (!seat->pointer) - return; - - listener = malloc(sizeof *listener); - listener->notify = handle_pointer_focus; - wl_signal_add(&seat->pointer->focus_signal, listener); -} - static void shell_surface_lose_keyboard_focus(struct shell_surface *shsurf) { @@ -2034,19 +2025,6 @@ handle_keyboard_focus(struct wl_listener *listener, void *data) } } -static void -create_keyboard_focus_listener(struct weston_seat *seat) -{ - struct wl_listener *listener; - - if (!seat->keyboard) - return; - - listener = malloc(sizeof *listener); - listener->notify = handle_keyboard_focus; - wl_signal_add(&seat->keyboard->focus_signal, listener); -} - static void shell_client_pong(struct shell_client *sc, uint32_t serial) { @@ -2850,6 +2828,30 @@ destroy_shell_seat(struct wl_listener *listener, void *data) free(shseat); } +static void +shell_seat_caps_changed(struct wl_listener *listener, void *data) +{ + struct shell_seat *seat; + + seat = container_of(listener, struct shell_seat, caps_changed_listener); + + if (seat->seat->keyboard && + wl_list_empty(&seat->keyboard_focus_listener.link)) { + wl_signal_add(&seat->seat->keyboard->focus_signal, + &seat->keyboard_focus_listener); + } else if (!seat->seat->keyboard) { + wl_list_init(&seat->keyboard_focus_listener.link); + } + + if (seat->seat->pointer && + wl_list_empty(&seat->pointer_focus_listener.link)) { + wl_signal_add(&seat->seat->pointer->focus_signal, + &seat->pointer_focus_listener); + } else if (!seat->seat->pointer) { + wl_list_init(&seat->pointer_focus_listener.link); + } +} + static struct shell_seat * create_shell_seat(struct weston_seat *seat) { @@ -2868,6 +2870,17 @@ create_shell_seat(struct weston_seat *seat) wl_signal_add(&seat->destroy_signal, &shseat->seat_destroy_listener); + shseat->keyboard_focus_listener.notify = handle_keyboard_focus; + wl_list_init(&shseat->keyboard_focus_listener.link); + + shseat->pointer_focus_listener.notify = handle_pointer_focus; + wl_list_init(&shseat->pointer_focus_listener.link); + + shseat->caps_changed_listener.notify = shell_seat_caps_changed; + wl_signal_add(&seat->updated_caps_signal, + &shseat->caps_changed_listener); + shell_seat_caps_changed(&shseat->caps_changed_listener, NULL); + return shseat; } @@ -2877,8 +2890,7 @@ get_shell_seat(struct weston_seat *seat) struct wl_listener *listener; listener = wl_signal_get(&seat->destroy_signal, destroy_shell_seat); - if (listener == NULL) - return create_shell_seat(seat); + assert(listener != NULL); return container_of(listener, struct shell_seat, seat_destroy_listener); @@ -6060,6 +6072,14 @@ shell_add_bindings(struct weston_compositor *ec, struct desktop_shell *shell) debug_binding, shell); } +static void +handle_seat_created(struct wl_listener *listener, void *data) +{ + struct weston_seat *seat = data; + + create_shell_seat(seat); +} + WL_EXPORT int module_init(struct weston_compositor *ec, int *argc, char *argv[]) @@ -6159,10 +6179,10 @@ module_init(struct weston_compositor *ec, shell->screensaver.timer = wl_event_loop_add_timer(loop, screensaver_timeout, shell); - wl_list_for_each(seat, &ec->seat_list, link) { - create_pointer_focus_listener(seat); - create_keyboard_focus_listener(seat); - } + wl_list_for_each(seat, &ec->seat_list, link) + handle_seat_created(NULL, seat); + shell->seat_create_listener.notify = handle_seat_created; + wl_signal_add(&ec->seat_created_signal, &shell->seat_create_listener); screenshooter_create(ec); diff --git a/desktop-shell/shell.h b/desktop-shell/shell.h index 09f8b79f..6e637850 100644 --- a/desktop-shell/shell.h +++ b/desktop-shell/shell.h @@ -199,6 +199,7 @@ struct desktop_shell { struct weston_layer minimized_layer; + struct wl_listener seat_create_listener; struct wl_listener output_create_listener; struct wl_listener output_move_listener; struct wl_list output_list;