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 <[email protected]> --- 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 _______________________________________________ wayland-devel mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/wayland-devel
