summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Agner <stefan@agner.ch>2019-06-23 14:53:59 +0200
committerStefan Agner <stefan@agner.ch>2020-01-13 13:18:00 +0100
commita8da208453ccc748bf331e83956b85d43ef0f05f (patch)
treed0870d3ddbb18211219ee6998740ff5a5e3a51f0
parent105e0b9c2711b09b1ee655fb40d6c13a79945ff3 (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.c53
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)