From 2587a855a8e79ea96695825e02294e83b9f8d326 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 27 Oct 2021 16:19:06 +0200 Subject: [PATCH] Use wlr_scene_xdg_surface_create for popups See https://github.com/swaywm/wlroots/pull/3298 --- xdg_shell.c | 187 ++++++++++++++++++++++------------------------------ xdg_shell.h | 12 ---- 2 files changed, 78 insertions(+), 121 deletions(-) diff --git a/xdg_shell.c b/xdg_shell.c index 271b05e..a51ed70 100644 --- a/xdg_shell.c +++ b/xdg_shell.c @@ -6,6 +6,7 @@ * See the LICENSE file accompanying this file. */ +#include #include #include #include @@ -41,67 +42,32 @@ xdg_decoration_handle_request_mode(struct wl_listener *listener, void *data) wlr_xdg_toplevel_decoration_v1_set_mode(xdg_decoration->wlr_decoration, mode); } -static void -xdg_popup_destroy(struct cg_view_child *child) +static struct cg_view * +popup_get_view(struct wlr_xdg_popup *popup) { - if (!child) { - return; + while (true) { + if (popup->parent == NULL || !wlr_surface_is_xdg_surface(popup->parent)) { + return NULL; + } + + struct wlr_xdg_surface *xdg_surface = wlr_xdg_surface_from_wlr_surface(popup->parent); + switch (xdg_surface->role) { + case WLR_XDG_SURFACE_ROLE_TOPLEVEL: + return xdg_surface->data; + case WLR_XDG_SURFACE_ROLE_POPUP: + popup = xdg_surface->popup; + break; + case WLR_XDG_SURFACE_ROLE_NONE: + return NULL; + } } - - struct cg_xdg_popup *popup = (struct cg_xdg_popup *) child; - wl_list_remove(&popup->destroy.link); - wl_list_remove(&popup->map.link); - wl_list_remove(&popup->unmap.link); - wl_list_remove(&popup->new_popup.link); - view_child_finish(&popup->view_child); - free(popup); } static void -handle_xdg_popup_map(struct wl_listener *listener, void *data) +popup_unconstrain(struct cg_view *view, struct wlr_xdg_popup *popup) { - struct cg_xdg_popup *popup = wl_container_of(listener, popup, map); - struct wlr_scene_node *parent_node = popup->view_child.view->scene_node; - popup->scene_surface = wlr_scene_surface_create(parent_node, popup->view_child.wlr_surface); - if (!popup->scene_surface) { - return; - } - double sx, sy; - wlr_xdg_popup_get_position(popup->wlr_popup, &sx, &sy); - wlr_scene_node_set_position(&popup->scene_surface->node, sx, sy); -} - -static void -handle_xdg_popup_unmap(struct wl_listener *listener, void *data) -{ - struct cg_xdg_popup *popup = wl_container_of(listener, popup, unmap); - wlr_scene_node_destroy(&popup->scene_surface->node); -} - -static void -handle_xdg_popup_destroy(struct wl_listener *listener, void *data) -{ - struct cg_xdg_popup *popup = wl_container_of(listener, popup, destroy); - struct cg_view_child *view_child = (struct cg_view_child *) popup; - xdg_popup_destroy(view_child); -} - -static void xdg_popup_create(struct cg_view *view, struct wlr_xdg_popup *wlr_popup); - -static void -popup_handle_new_xdg_popup(struct wl_listener *listener, void *data) -{ - struct cg_xdg_popup *popup = wl_container_of(listener, popup, new_popup); - struct wlr_xdg_popup *wlr_popup = data; - xdg_popup_create(popup->view_child.view, wlr_popup); -} - -static void -popup_unconstrain(struct cg_xdg_popup *popup) -{ - struct cg_view *view = popup->view_child.view; struct cg_server *server = view->server; - struct wlr_box *popup_box = &popup->wlr_popup->geometry; + struct wlr_box *popup_box = &popup->geometry; struct wlr_output_layout *output_layout = server->output_layout; struct wlr_output *wlr_output = @@ -115,38 +81,7 @@ popup_unconstrain(struct cg_xdg_popup *popup) .height = output_box->height, }; - wlr_xdg_popup_unconstrain_from_box(popup->wlr_popup, &output_toplevel_box); -} - -static void -xdg_popup_create(struct cg_view *view, struct wlr_xdg_popup *wlr_popup) -{ - struct cg_xdg_popup *popup = calloc(1, sizeof(struct cg_xdg_popup)); - if (!popup) { - return; - } - - popup->wlr_popup = wlr_popup; - view_child_init(&popup->view_child, view, wlr_popup->base->surface); - popup->view_child.destroy = xdg_popup_destroy; - popup->destroy.notify = handle_xdg_popup_destroy; - wl_signal_add(&wlr_popup->base->events.destroy, &popup->destroy); - popup->map.notify = handle_xdg_popup_map; - wl_signal_add(&wlr_popup->base->events.map, &popup->map); - popup->unmap.notify = handle_xdg_popup_unmap; - wl_signal_add(&wlr_popup->base->events.unmap, &popup->unmap); - popup->new_popup.notify = popup_handle_new_xdg_popup; - wl_signal_add(&wlr_popup->base->events.new_popup, &popup->new_popup); - - popup_unconstrain(popup); -} - -static void -handle_new_xdg_popup(struct wl_listener *listener, void *data) -{ - struct cg_xdg_shell_view *xdg_shell_view = wl_container_of(listener, xdg_shell_view, new_popup); - struct wlr_xdg_popup *wlr_popup = data; - xdg_popup_create(&xdg_shell_view->view, wlr_popup); + wlr_xdg_popup_unconstrain_from_box(popup, &output_toplevel_box); } static struct cg_xdg_shell_view * @@ -261,7 +196,6 @@ handle_xdg_shell_surface_destroy(struct wl_listener *listener, void *data) wl_list_remove(&xdg_shell_view->unmap.link); wl_list_remove(&xdg_shell_view->destroy.link); wl_list_remove(&xdg_shell_view->request_fullscreen.link); - wl_list_remove(&xdg_shell_view->new_popup.link); xdg_shell_view->xdg_surface = NULL; view_destroy(view); @@ -283,29 +217,64 @@ handle_xdg_shell_surface_new(struct wl_listener *listener, void *data) struct cg_server *server = wl_container_of(listener, server, new_xdg_shell_surface); struct wlr_xdg_surface *xdg_surface = data; - if (xdg_surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) { - return; + switch (xdg_surface->role) { + case WLR_XDG_SURFACE_ROLE_TOPLEVEL:; + struct cg_xdg_shell_view *xdg_shell_view = calloc(1, sizeof(struct cg_xdg_shell_view)); + if (!xdg_shell_view) { + wlr_log(WLR_ERROR, "Failed to allocate XDG Shell view"); + return; + } + + view_init(&xdg_shell_view->view, server, CAGE_XDG_SHELL_VIEW, &xdg_shell_view_impl); + xdg_shell_view->xdg_surface = xdg_surface; + + xdg_shell_view->map.notify = handle_xdg_shell_surface_map; + wl_signal_add(&xdg_surface->events.map, &xdg_shell_view->map); + xdg_shell_view->unmap.notify = handle_xdg_shell_surface_unmap; + wl_signal_add(&xdg_surface->events.unmap, &xdg_shell_view->unmap); + xdg_shell_view->destroy.notify = handle_xdg_shell_surface_destroy; + wl_signal_add(&xdg_surface->events.destroy, &xdg_shell_view->destroy); + xdg_shell_view->request_fullscreen.notify = handle_xdg_shell_surface_request_fullscreen; + wl_signal_add(&xdg_surface->toplevel->events.request_fullscreen, &xdg_shell_view->request_fullscreen); + + xdg_surface->data = xdg_shell_view; + break; + case WLR_XDG_SURFACE_ROLE_POPUP:; + struct wlr_xdg_popup *popup = xdg_surface->popup; + struct cg_view *view = popup_get_view(popup); + if (view == NULL) { + return; + } + + struct wlr_scene_node *parent_scene_node = NULL; + struct wlr_xdg_surface *parent = wlr_xdg_surface_from_wlr_surface(popup->parent); + switch (parent->role) { + case WLR_XDG_SURFACE_ROLE_TOPLEVEL:; + parent_scene_node = view->scene_node; + break; + case WLR_XDG_SURFACE_ROLE_POPUP: + parent_scene_node = parent->data; + break; + case WLR_XDG_SURFACE_ROLE_NONE: + break; + } + if (parent_scene_node == NULL) { + return; + } + + struct wlr_scene_node *popup_scene_node = wlr_scene_xdg_surface_create(parent_scene_node, xdg_surface); + if (popup_scene_node == NULL) { + wlr_log(WLR_ERROR, "Failed to allocate scene-graph node for XDG popup"); + return; + } + + popup_unconstrain(view, popup); + + xdg_surface->data = popup_scene_node; + break; + case WLR_XDG_SURFACE_ROLE_NONE: + assert(false); // unreachable } - - struct cg_xdg_shell_view *xdg_shell_view = calloc(1, sizeof(struct cg_xdg_shell_view)); - if (!xdg_shell_view) { - wlr_log(WLR_ERROR, "Failed to allocate XDG Shell view"); - return; - } - - view_init(&xdg_shell_view->view, server, CAGE_XDG_SHELL_VIEW, &xdg_shell_view_impl); - xdg_shell_view->xdg_surface = xdg_surface; - - xdg_shell_view->map.notify = handle_xdg_shell_surface_map; - wl_signal_add(&xdg_surface->events.map, &xdg_shell_view->map); - xdg_shell_view->unmap.notify = handle_xdg_shell_surface_unmap; - wl_signal_add(&xdg_surface->events.unmap, &xdg_shell_view->unmap); - xdg_shell_view->destroy.notify = handle_xdg_shell_surface_destroy; - wl_signal_add(&xdg_surface->events.destroy, &xdg_shell_view->destroy); - xdg_shell_view->request_fullscreen.notify = handle_xdg_shell_surface_request_fullscreen; - wl_signal_add(&xdg_surface->toplevel->events.request_fullscreen, &xdg_shell_view->request_fullscreen); - xdg_shell_view->new_popup.notify = handle_new_xdg_popup; - wl_signal_add(&xdg_surface->events.new_popup, &xdg_shell_view->new_popup); } void diff --git a/xdg_shell.h b/xdg_shell.h index a5539b9..9a101c6 100644 --- a/xdg_shell.h +++ b/xdg_shell.h @@ -15,18 +15,6 @@ struct cg_xdg_shell_view { struct wl_listener unmap; struct wl_listener map; struct wl_listener request_fullscreen; - struct wl_listener new_popup; -}; - -struct cg_xdg_popup { - struct cg_view_child view_child; - struct wlr_xdg_popup *wlr_popup; - struct wlr_scene_surface *scene_surface; - - struct wl_listener destroy; - struct wl_listener map; - struct wl_listener unmap; - struct wl_listener new_popup; }; struct cg_xdg_decoration {