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) @@ -2747,6 +2764,20 @@ desktop_surface_resize(struct weston_desktop_surface *desktop_surface, 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 desktop_surface_fullscreen_requested(struct weston_desktop_surface *desktop_surface, bool fullscreen, @@ -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)