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>
dev
Stefan Agner 6 years ago
parent 105e0b9c27
commit a8da208453
  1. 53
      desktop-shell/shell.c

@ -104,6 +104,9 @@ struct shell_surface {
struct desktop_shell *shell; struct desktop_shell *shell;
struct wl_list children_list;
struct wl_list children_link;
int32_t saved_x, saved_y; int32_t saved_x, saved_y;
bool saved_position_valid; bool saved_position_valid;
bool saved_rotation_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); 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_user_data(desktop_surface, shsurf);
weston_desktop_surface_set_activated(desktop_surface, weston_desktop_surface_set_activated(desktop_surface,
shsurf->focus_count > 0); shsurf->focus_count > 0);
@ -2427,12 +2437,19 @@ desktop_surface_removed(struct weston_desktop_surface *desktop_surface,
{ {
struct shell_surface *shsurf = struct shell_surface *shsurf =
weston_desktop_surface_get_user_data(desktop_surface); weston_desktop_surface_get_user_data(desktop_surface);
struct shell_surface *shsurf_child, *tmp;
struct weston_surface *surface = struct weston_surface *surface =
weston_desktop_surface_get_surface(desktop_surface); weston_desktop_surface_get_surface(desktop_surface);
if (!shsurf) if (!shsurf)
return; 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); wl_signal_emit(&shsurf->destroy_signal, shsurf);
if (shsurf->fullscreen.black_view) if (shsurf->fullscreen.black_view)
@ -2747,6 +2764,20 @@ desktop_surface_resize(struct weston_desktop_surface *desktop_surface,
wl_resource_post_no_memory(resource); wl_resource_post_no_memory(resource);
} }
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 static void
desktop_surface_fullscreen_requested(struct weston_desktop_surface *desktop_surface, desktop_surface_fullscreen_requested(struct weston_desktop_surface *desktop_surface,
bool fullscreen, bool fullscreen,
@ -2929,6 +2960,7 @@ static const struct weston_desktop_api shell_desktop_api = {
.committed = desktop_surface_committed, .committed = desktop_surface_committed,
.move = desktop_surface_move, .move = desktop_surface_move,
.resize = desktop_surface_resize, .resize = desktop_surface_resize,
.set_parent = desktop_surface_set_parent,
.fullscreen_requested = desktop_surface_fullscreen_requested, .fullscreen_requested = desktop_surface_fullscreen_requested,
.maximized_requested = desktop_surface_maximized_requested, .maximized_requested = desktop_surface_maximized_requested,
.minimized_requested = desktop_surface_minimized_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 void
activate(struct desktop_shell *shell, struct weston_view *view, activate(struct desktop_shell *shell, struct weston_view *view,
struct weston_seat *seat, uint32_t flags) 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 focus_state *state;
struct workspace *ws; struct workspace *ws;
struct weston_surface *old_es; struct weston_surface *old_es;
struct shell_surface *shsurf; struct shell_surface *shsurf, *shsurf_child;
main_surface = weston_surface_get_main_surface(es); main_surface = weston_surface_get_main_surface(es);
shsurf = get_shell_surface(main_surface); shsurf = get_shell_surface(main_surface);
assert(shsurf); 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. /* Only demote fullscreen surfaces on the output of activated shsurf.
* Leave fullscreen surfaces on unrelated outputs alone. */ * Leave fullscreen surfaces on unrelated outputs alone. */
if (shsurf->output) if (shsurf->output)

Loading…
Cancel
Save