[PATCH weston v2 5/5] shell: Store focus state in workspaces

Jonas Ådahl jadahl at gmail.com
Mon Jun 11 13:03:06 PDT 2012


When moving moving back to a workspace or resuming a locked desktop the
keyboard focus state information was lost. By pushing the state to the
workspace when navigating away from a workspace, or locking a desktop,
we can restore it when navigating back, or resuming.

Signed-off-by: Jonas Ådahl <jadahl at gmail.com>
---
 src/compositor.c |    4 ++
 src/compositor.h |    2 +
 src/shell.c      |  154 ++++++++++++++++++++++++++++++++++++++++++++++++++----
 3 files changed, 149 insertions(+), 11 deletions(-)

diff --git a/src/compositor.c b/src/compositor.c
index 86d5eae..8ec1f5e 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -2417,6 +2417,8 @@ weston_seat_init(struct weston_seat *seat, struct weston_compositor *ec)
 	seat->has_keyboard = 0;
 	seat->has_touch = 0;
 
+	wl_signal_init(&seat->destroyed_signal);
+
 	wl_display_add_global(ec->wl_display, &wl_seat_interface, seat,
 			      bind_seat);
 
@@ -2444,6 +2446,8 @@ weston_seat_init(struct weston_seat *seat, struct weston_compositor *ec)
 WL_EXPORT void
 weston_seat_release(struct weston_seat *seat)
 {
+	wl_signal_emit(&seat->destroyed_signal, seat);
+
 	wl_list_remove(&seat->link);
 	/* The global object is destroyed at wl_display_destroy() time. */
 
diff --git a/src/compositor.h b/src/compositor.h
index d1ffdea..61bfc08 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -184,6 +184,8 @@ struct weston_seat {
 	struct wl_touch touch;
 	int has_touch;
 
+	struct wl_signal destroyed_signal;
+
 	struct weston_compositor *compositor;
 	struct weston_surface *sprite;
 	struct weston_surface *drag_surface;
diff --git a/src/shell.c b/src/shell.c
index 993b104..5a8df3d 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -48,8 +48,19 @@ enum animation_type {
 	ANIMATION_FADE
 };
 
+struct focus_state {
+	struct weston_seat *seat;
+	struct weston_surface *keyboard_focus;
+	struct wl_list link;
+	struct wl_listener seat_destroy_listener;
+	struct wl_listener surface_destroy_listener;
+};
+
 struct workspace {
 	struct weston_layer layer;
+
+	struct wl_list focus_list;
+	struct wl_listener seat_destroyed_listener;
 };
 
 struct desktop_shell {
@@ -176,6 +187,8 @@ struct shell_surface {
 
 	struct weston_transform workspace_transform;
 
+	struct focus_state *focus_state;
+
 	struct weston_output *fullscreen_output;
 	struct weston_output *output;
 	struct wl_list link;
@@ -330,11 +343,126 @@ shell_configuration(struct desktop_shell *shell)
 }
 
 static void
+focus_state_destroy(struct focus_state *state)
+{
+	wl_list_remove(&state->seat_destroy_listener.link);
+	wl_list_remove(&state->surface_destroy_listener.link);
+	free(state);
+}
+
+static void
+focus_state_seat_destroy(struct wl_listener *listener, void *data)
+{
+	struct focus_state *state = container_of(listener,
+						 struct focus_state,
+						 seat_destroy_listener);
+
+	wl_list_remove(&state->link);
+	focus_state_destroy(state);
+}
+
+static void
+focus_state_surface_destroy(struct wl_listener *listener, void *data)
+{
+	struct focus_state *state = container_of(listener,
+						 struct focus_state,
+						 seat_destroy_listener);
+
+	wl_list_remove(&state->link);
+	focus_state_destroy(state);
+}
+
+static struct focus_state *
+focus_state_create(struct weston_seat *seat)
+{
+	struct wl_keyboard *keyboard = seat->seat.keyboard;
+	struct focus_state *state;
+	struct wl_surface *surface;
+	struct shell_surface *shsurf;
+
+	state = malloc(sizeof *state);
+	if (state == NULL)
+		return NULL;
+
+	surface = keyboard->focus;
+	shsurf = get_shell_surface((struct weston_surface *)keyboard->focus);
+	shsurf->focus_state = state;
+
+	state->seat = seat;
+	state->keyboard_focus = shsurf->surface;
+	wl_list_init(&state->link);
+
+	state->seat_destroy_listener.notify = focus_state_seat_destroy;
+	state->surface_destroy_listener.notify = focus_state_surface_destroy;
+	wl_signal_add(&seat->destroyed_signal,
+		      &state->seat_destroy_listener);
+	wl_signal_add(&surface->resource.destroy_signal,
+		      &state->surface_destroy_listener);
+
+	return state;
+}
+
+static void
+pop_focus_state(struct desktop_shell *shell, struct workspace *ws)
+{
+	struct focus_state *state, *next;
+
+	wl_list_for_each_safe(state, next, &ws->focus_list, link) {
+		if (state->keyboard_focus)
+			wl_keyboard_set_focus(state->seat->seat.keyboard,
+					      &state->keyboard_focus->surface);
+
+		focus_state_destroy(state);
+	}
+	wl_list_init(&ws->focus_list);
+}
+
+static void
+push_focus_state(struct desktop_shell *shell, struct workspace *ws)
+{
+	struct weston_seat *seat;
+	struct focus_state *state;
+	struct wl_keyboard *keyboard;
+
+	wl_list_for_each(seat, &shell->compositor->seat_list, link) {
+		keyboard = seat->seat.keyboard;
+		if (keyboard && keyboard->focus) {
+			state = focus_state_create(seat);
+			if (state == NULL)
+				return;
+
+			wl_list_insert(&ws->focus_list, &state->link);
+
+			wl_keyboard_set_focus(seat->seat.keyboard, NULL);
+		}
+	}
+}
+
+static void
 workspace_destroy(struct workspace *ws)
 {
+	struct focus_state *state, *next;
+
+	wl_list_for_each_safe(state, next, &ws->focus_list, link)
+		focus_state_destroy(state);
+
 	free(ws);
 }
 
+static void
+seat_destroyed(struct wl_listener *listener, void *data)
+{
+	struct weston_seat *seat = data;
+	struct focus_state *state, *next;
+	struct workspace *ws = container_of(listener,
+					    struct workspace,
+					    seat_destroyed_listener);
+
+	wl_list_for_each_safe(state, next, &ws->focus_list, link)
+		if (state->seat == seat)
+			wl_list_remove(&state->link);
+}
+
 static struct workspace *
 workspace_create(void)
 {
@@ -344,6 +472,10 @@ workspace_create(void)
 
 	weston_layer_init(&ws->layer, NULL);
 
+	wl_list_init(&ws->focus_list);
+	wl_list_init(&ws->seat_destroyed_listener.link);
+	ws->seat_destroyed_listener.notify = seat_destroyed;
+
 	return ws;
 }
 
@@ -515,6 +647,7 @@ animate_workspace_change_frame(struct weston_animation *animation,
 
 	if (workspace_is_empty(from) && workspace_is_empty(to)) {
 		finish_workspace_change_animation(shell, from, to);
+		pop_focus_state(shell, to);
 		return;
 	}
 
@@ -543,6 +676,7 @@ animate_workspace_change_frame(struct weston_animation *animation,
 	}
 	else {
 		finish_workspace_change_animation(shell, from, to);
+		pop_focus_state(shell, to);
 	}
 }
 
@@ -582,6 +716,8 @@ animate_workspace_change(struct desktop_shell *shell,
 
 	workspace_translate_in(to, 0);
 
+	push_focus_state(shell, from);
+
 	workspace_damage_all_surfaces(from);
 	workspace_damage_all_surfaces(to);
 }
@@ -591,7 +727,6 @@ change_workspace(struct desktop_shell *shell, unsigned int index)
 {
 	struct workspace *from;
 	struct workspace *to;
-	struct weston_seat *seat;
 	struct weston_surface *surface;
 
 	if (index == shell->workspaces.current)
@@ -601,11 +736,6 @@ change_workspace(struct desktop_shell *shell, unsigned int index)
 	if (!wl_list_empty(&shell->fullscreen_layer.surface_list))
 		return;
 
-	/* Clear keyboard focus so that no hidden surfaces will keep it. */
-	wl_list_for_each(seat, &shell->compositor->seat_list, link)
-		if (seat->seat.keyboard)
-			wl_keyboard_set_focus(seat->seat.keyboard, NULL);
-
 	from = get_current_workspace(shell);
 	to = get_workspace(shell, index);
 
@@ -629,6 +759,9 @@ change_workspace(struct desktop_shell *shell, unsigned int index)
 			weston_surface_assign_output(surface);
 		wl_list_for_each(surface, &from->layer.surface_list, layer_link)
 			surface->output = NULL;
+
+		push_focus_state(shell, from);
+		pop_focus_state(shell, to);
 	}
 	else
 		animate_workspace_change(shell, index, from, to);
@@ -1873,6 +2006,8 @@ resume_desktop(struct desktop_shell *shell)
 	wl_list_insert(&shell->fullscreen_layer.link,
 		       &shell->panel_layer.link);
 
+	pop_focus_state(shell, get_current_workspace(shell));
+
 	shell->locked = false;
 	shell->compositor->idle_time = shell->compositor->option_idle_time;
 	weston_compositor_wake(shell->compositor);
@@ -2352,7 +2487,6 @@ lock(struct wl_listener *listener, void *data)
 {
 	struct desktop_shell *shell =
 		container_of(listener, struct desktop_shell, lock_listener);
-	struct weston_seat *seat;
 	struct shell_surface *shsurf;
 	struct weston_output *output;
 
@@ -2389,10 +2523,8 @@ lock(struct wl_listener *listener, void *data)
 	/* reset pointer foci */
 	weston_compositor_schedule_repaint(shell->compositor);
 
-	/* reset keyboard foci */
-	wl_list_for_each(seat, &shell->compositor->seat_list, link) {
-		wl_keyboard_set_focus(seat->seat.keyboard, NULL);
-	}
+	/* stash keyboard foci in current workspace */
+	push_focus_state(shell, get_current_workspace(shell));
 
 	/* TODO: disable bindings that should not work while locked. */
 
-- 
1.7.9.5



More information about the wayland-devel mailing list