[PATCH] desktop-shell: Properly handle seat hotplugging

Jason Ekstrand jason at jlekstrand.net
Mon Apr 21 17:42:58 PDT 2014


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.

This fixes bug #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 0e4329b..ac03a15 100644
--- a/desktop-shell/shell.c
+++ b/desktop-shell/shell.c
@@ -211,6 +211,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;
@@ -1918,19 +1922,6 @@ handle_pointer_focus(struct wl_listener *listener, void *data)
 }
 
 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)
 {
 	if (--shsurf->focus_count == 0)
@@ -1968,19 +1959,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)
 {
 	if (sc->ping_serial != serial)
@@ -2771,6 +2749,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)
 {
@@ -2789,6 +2791,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;
 }
 
@@ -2798,8 +2811,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);
@@ -5916,6 +5928,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[])
@@ -6015,10 +6035,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 5d127c6..9685cb2 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;
-- 
1.9.0



More information about the wayland-devel mailing list