From beece0215f82885bc97cdf615d6b66b54b9d935d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20G=C3=B3mez?= Date: Fri, 26 May 2023 17:01:21 -0500 Subject: [PATCH] kiosk-shell: Handle relinking of surface trees when setting a parent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds code to maintain the correct order and linking of a surface in its surface tree list for when a new parent is being set on it. If the new parent is not NULL, the child might already belong to the same surface tree as the new parent's root, in which case no relinking is necessary. Check this by calling kiosk_shell_surface_is_surface_in_tree(shsurf, shroot), to see if 'shsurf' is in the surface tree list represented by 'shroot', where 'shroot' is the new parent's root surface. In case 'shsurf' doesn't belong to this surface tree, relink it there. If parent is NULL, 'shsurf' will become root of a new surface tree list. In this case 'shroot' is the root surface of shsurf's current surface tree list. Iterate through the surface tree list of this 'shroot' to relink all descendents of 'shsurf' into this new list and set it as the new active surface tree for the output. Signed-off-by: Sergio Gómez --- kiosk-shell/kiosk-shell.c | 72 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/kiosk-shell/kiosk-shell.c b/kiosk-shell/kiosk-shell.c index 476aca478..53affdd81 100644 --- a/kiosk-shell/kiosk-shell.c +++ b/kiosk-shell/kiosk-shell.c @@ -121,6 +121,12 @@ kiosk_shell_surface_set_output(struct kiosk_shell_surface *shsurf, static void kiosk_shell_surface_set_parent(struct kiosk_shell_surface *shsurf, struct kiosk_shell_surface *parent); +static void +kiosk_shell_output_set_active_surface_tree(struct kiosk_shell_output *shoutput, + struct kiosk_shell_surface *shroot); +static struct kiosk_shell_output * +kiosk_shell_find_shell_output(struct kiosk_shell *shell, + struct weston_output *output); static void kiosk_shell_surface_notify_parent_destroy(struct wl_listener *listener, void *data) @@ -257,10 +263,58 @@ kiosk_shell_surface_set_normal(struct kiosk_shell_surface *shsurf) weston_desktop_surface_set_size(shsurf->desktop_surface, 0, 0); } +static bool +kiosk_shell_surface_is_surface_in_tree(struct kiosk_shell_surface *shsurf, + struct kiosk_shell_surface *shroot) +{ + struct kiosk_shell_surface *s; + + wl_list_for_each(s, &shroot->surface_tree_list, surface_tree_link) { + if (s == shsurf) + return true; + } + + return false; +} + +static bool +kiosk_shell_surface_is_descendant_of(struct kiosk_shell_surface *shsurf, + struct kiosk_shell_surface *ancestor) +{ + while (shsurf) { + if (shsurf == ancestor) + return true; + shsurf = shsurf->parent; + } + + return false; +} + +static void +active_surface_tree_move_element_to_top(struct wl_list *active_surface_tree, + struct wl_list *element) +{ + wl_list_remove(element); + wl_list_insert(active_surface_tree, element); +} + static void kiosk_shell_surface_set_parent(struct kiosk_shell_surface *shsurf, struct kiosk_shell_surface *parent) { + struct kiosk_shell_output *shoutput = + kiosk_shell_find_shell_output(shsurf->shell, + shsurf->output); + struct kiosk_shell_surface *shroot = parent ? + kiosk_shell_surface_get_parent_root(parent) : + kiosk_shell_surface_get_parent_root(shsurf); + + /* There are cases where xdg clients call .set_parent(nil) on a surface + * that does not have a parent. The protocol states that this is + * effectively a no-op. */ + if (!parent && shsurf == shroot) + return; + if (shsurf->parent_destroy_listener.notify) { wl_list_remove(&shsurf->parent_destroy_listener.link); shsurf->parent_destroy_listener.notify = NULL; @@ -273,9 +327,27 @@ kiosk_shell_surface_set_parent(struct kiosk_shell_surface *shsurf, kiosk_shell_surface_notify_parent_destroy; wl_signal_add(&shsurf->parent->destroy_signal, &shsurf->parent_destroy_listener); + + if (!kiosk_shell_surface_is_surface_in_tree(shsurf, shroot)) { + active_surface_tree_move_element_to_top(&shroot->surface_tree_list, + &shsurf->surface_tree_link); + } kiosk_shell_surface_set_output(shsurf, NULL); kiosk_shell_surface_set_normal(shsurf); } else { + struct kiosk_shell_surface *s, *tmp; + + /* Relink the child and all its descendents to a new surface + * tree list, with the child as root. */ + wl_list_init(&shsurf->surface_tree_list); + wl_list_for_each_reverse_safe(s, tmp, &shroot->surface_tree_list, + surface_tree_link) { + if (kiosk_shell_surface_is_descendant_of(s, shsurf)) { + active_surface_tree_move_element_to_top(&shsurf->surface_tree_list, + &s->surface_tree_link); + } + } + kiosk_shell_output_set_active_surface_tree(shoutput, shsurf); kiosk_shell_surface_set_fullscreen(shsurf, shsurf->output); } }