diff options
author | Stefan Agner <stefan@agner.ch> | 2019-06-23 14:53:59 +0200 |
---|---|---|
committer | Stefan Agner <stefan@agner.ch> | 2020-01-13 13:18:00 +0100 |
commit | a8da208453ccc748bf331e83956b85d43ef0f05f (patch) | |
tree | d0870d3ddbb18211219ee6998740ff5a5e3a51f0 | |
parent | 105e0b9c2711b09b1ee655fb40d6c13a79945ff3 (diff) |
desktop-shell: make sure child window stays active
If a xdg_toplevel surface has a child (or multiple), the desktop shell
still allows to activate the parent. This can be problematic with
modal dialogs such as message boxes which then are hidden behind the
main window, which might be non-responsive to inputs at this this
point.
The protocol specifies set_parent as follows: "Set the 'parent' of
this surface. This surface should be stacked above the parent surface
and all other ancestor surfaces."
Track parent/child relationship in desktop-shell. Follow the protocol
recommendation and make sure the child stays stacked above the parent.
Fixes: #231
Signed-off-by: Stefan Agner <stefan@agner.ch>
-rw-r--r-- | desktop-shell/shell.c | 53 |
1 files changed, 52 insertions, 1 deletions
diff --git a/desktop-shell/shell.c b/desktop-shell/shell.c index a05a5fe0..7d9d703c 100644 --- a/desktop-shell/shell.c +++ b/desktop-shell/shell.c @@ -104,6 +104,9 @@ struct shell_surface { struct desktop_shell *shell; + struct wl_list children_list; + struct wl_list children_link; + int32_t saved_x, saved_y; bool saved_position_valid; bool saved_rotation_valid; @@ -2416,6 +2419,13 @@ desktop_surface_added(struct weston_desktop_surface *desktop_surface, wl_list_init(&shsurf->workspace_transform.link); + /* + * initialize list as well as link. The latter allows to use + * wl_list_remove() even when this surface is not in another list. + */ + wl_list_init(&shsurf->children_list); + wl_list_init(&shsurf->children_link); + weston_desktop_surface_set_user_data(desktop_surface, shsurf); weston_desktop_surface_set_activated(desktop_surface, shsurf->focus_count > 0); @@ -2427,12 +2437,19 @@ desktop_surface_removed(struct weston_desktop_surface *desktop_surface, { struct shell_surface *shsurf = weston_desktop_surface_get_user_data(desktop_surface); + struct shell_surface *shsurf_child, *tmp; struct weston_surface *surface = weston_desktop_surface_get_surface(desktop_surface); if (!shsurf) return; + wl_list_for_each_safe(shsurf_child, tmp, &shsurf->children_list, children_link) { + wl_list_remove(&shsurf_child->children_link); + wl_list_init(&shsurf_child->children_link); + } + wl_list_remove(&shsurf->children_link); + wl_signal_emit(&shsurf->destroy_signal, shsurf); if (shsurf->fullscreen.black_view) @@ -2748,6 +2765,20 @@ desktop_surface_resize(struct weston_desktop_surface *desktop_surface, } static void +desktop_surface_set_parent(struct weston_desktop_surface *desktop_surface, + struct weston_desktop_surface *parent, + void *shell) +{ + struct shell_surface *shsurf = + weston_desktop_surface_get_user_data(desktop_surface); + struct shell_surface *shsurf_parent = + weston_desktop_surface_get_user_data(parent); + + wl_list_insert(shsurf_parent->children_list.prev, + &shsurf->children_link); +} + +static void desktop_surface_fullscreen_requested(struct weston_desktop_surface *desktop_surface, bool fullscreen, struct weston_output *output, void *shell) @@ -2929,6 +2960,7 @@ static const struct weston_desktop_api shell_desktop_api = { .committed = desktop_surface_committed, .move = desktop_surface_move, .resize = desktop_surface_resize, + .set_parent = desktop_surface_set_parent, .fullscreen_requested = desktop_surface_fullscreen_requested, .maximized_requested = desktop_surface_maximized_requested, .minimized_requested = desktop_surface_minimized_requested, @@ -3777,6 +3809,18 @@ lower_fullscreen_layer(struct desktop_shell *shell, } } +static struct shell_surface *get_last_child(struct shell_surface *shsurf) +{ + struct shell_surface *shsurf_child; + + wl_list_for_each_reverse(shsurf_child, &shsurf->children_list, children_link) { + if (weston_view_is_mapped(shsurf_child->view)) + return shsurf_child; + } + + return NULL; +} + void activate(struct desktop_shell *shell, struct weston_view *view, struct weston_seat *seat, uint32_t flags) @@ -3786,12 +3830,19 @@ activate(struct desktop_shell *shell, struct weston_view *view, struct focus_state *state; struct workspace *ws; struct weston_surface *old_es; - struct shell_surface *shsurf; + struct shell_surface *shsurf, *shsurf_child; main_surface = weston_surface_get_main_surface(es); shsurf = get_shell_surface(main_surface); assert(shsurf); + shsurf_child = get_last_child(shsurf); + if (shsurf_child) { + /* Activate last xdg child instead of parent. */ + activate(shell, shsurf_child->view, seat, flags); + return; + } + /* Only demote fullscreen surfaces on the output of activated shsurf. * Leave fullscreen surfaces on unrelated outputs alone. */ if (shsurf->output) |