[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