wlr_xdg_toplevel: reparent on parent unmap

From the xdg-shell specification:
	If the parent is unmapped then its children are managed as
	though the parent of the now-unmapped parent has become the
	parent of this surface. If no parent exists for the now-unmapped
	parent then the children are managed as though they have no
	parent surface.
This commit is contained in:
Brian Ashworth 2019-08-14 20:36:08 -04:00 committed by Simon Ser
parent 8d2ea9544b
commit 9914784594
3 changed files with 36 additions and 3 deletions

View file

@ -117,9 +117,11 @@ struct wlr_xdg_toplevel_state {
struct wlr_xdg_toplevel { struct wlr_xdg_toplevel {
struct wl_resource *resource; struct wl_resource *resource;
struct wlr_xdg_surface *base; struct wlr_xdg_surface *base;
struct wlr_xdg_surface *parent;
bool added; bool added;
struct wlr_xdg_surface *parent;
struct wl_listener parent_unmap;
struct wlr_xdg_toplevel_state client_pending; struct wlr_xdg_toplevel_state client_pending;
struct wlr_xdg_toplevel_state server_pending; struct wlr_xdg_toplevel_state server_pending;
struct wlr_xdg_toplevel_state current; struct wlr_xdg_toplevel_state current;

View file

@ -41,6 +41,10 @@ void unmap_xdg_surface(struct wlr_xdg_surface *surface) {
switch (surface->role) { switch (surface->role) {
case WLR_XDG_SURFACE_ROLE_TOPLEVEL: case WLR_XDG_SURFACE_ROLE_TOPLEVEL:
if (surface->toplevel->parent) {
wl_list_remove(&surface->toplevel->parent_unmap.link);
surface->toplevel->parent = NULL;
}
free(surface->toplevel->title); free(surface->toplevel->title);
surface->toplevel->title = NULL; surface->toplevel->title = NULL;
free(surface->toplevel->app_id); free(surface->toplevel->app_id);

View file

@ -207,6 +207,34 @@ struct wlr_xdg_surface *wlr_xdg_surface_from_toplevel_resource(
return wl_resource_get_user_data(resource); return wl_resource_get_user_data(resource);
} }
static void set_parent(struct wlr_xdg_surface *surface,
struct wlr_xdg_surface *parent);
static void handle_parent_unmap(struct wl_listener *listener, void *data) {
struct wlr_xdg_toplevel *toplevel =
wl_container_of(listener, toplevel, parent_unmap);
set_parent(toplevel->base, toplevel->parent->toplevel->parent);
}
static void set_parent(struct wlr_xdg_surface *surface,
struct wlr_xdg_surface *parent) {
assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL);
assert(!parent || parent->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL);
if (surface->toplevel->parent) {
wl_list_remove(&surface->toplevel->parent_unmap.link);
}
surface->toplevel->parent = parent;
if (surface->toplevel->parent) {
surface->toplevel->parent_unmap.notify = handle_parent_unmap;
wl_signal_add(&surface->toplevel->parent->events.unmap,
&surface->toplevel->parent_unmap);
}
wlr_signal_emit_safe(&surface->toplevel->events.set_parent, surface);
}
static void xdg_toplevel_handle_set_parent(struct wl_client *client, static void xdg_toplevel_handle_set_parent(struct wl_client *client,
struct wl_resource *resource, struct wl_resource *parent_resource) { struct wl_resource *resource, struct wl_resource *parent_resource) {
struct wlr_xdg_surface *surface = struct wlr_xdg_surface *surface =
@ -217,8 +245,7 @@ static void xdg_toplevel_handle_set_parent(struct wl_client *client,
parent = wlr_xdg_surface_from_toplevel_resource(parent_resource); parent = wlr_xdg_surface_from_toplevel_resource(parent_resource);
} }
surface->toplevel->parent = parent; set_parent(surface, parent);
wlr_signal_emit_safe(&surface->toplevel->events.set_parent, surface);
} }
static void xdg_toplevel_handle_set_title(struct wl_client *client, static void xdg_toplevel_handle_set_title(struct wl_client *client,