From f5e5b1819bf88841f6f42fdfe416fa588abbeeb5 Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 5 Apr 2018 16:48:11 -0400 Subject: [PATCH] Track damage of xdg-shell-v6 popups --- include/sway/tree/view.h | 11 ++++++ sway/desktop/xdg_shell_v6.c | 72 +++++++++++++++++++++++++++++++++++++ sway/tree/view.c | 2 ++ 3 files changed, 85 insertions(+) diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index f8e41652..2eca7a3e 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h @@ -60,6 +60,7 @@ struct sway_xdg_shell_v6_view { struct wl_listener request_move; struct wl_listener request_resize; struct wl_listener request_maximize; + struct wl_listener new_popup; struct wl_listener map; struct wl_listener unmap; struct wl_listener destroy; @@ -122,6 +123,16 @@ struct sway_view_child { struct wl_listener view_unmap; }; +struct sway_xdg_popup_v6 { + struct sway_view_child child; + + struct wlr_xdg_surface_v6 *wlr_xdg_surface_v6; + + struct wl_listener new_popup; + struct wl_listener unmap; + struct wl_listener destroy; +}; + const char *view_get_title(struct sway_view *view); const char *view_get_app_id(struct sway_view *view); diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index 7b9d5fb7..baf07a1e 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c @@ -11,6 +11,66 @@ #include "sway/input/input-manager.h" #include "log.h" +static const struct sway_view_child_impl popup_impl; + +static void popup_destroy(struct sway_view_child *child) { + if (!sway_assert(child->impl == &popup_impl, + "Expected an xdg_shell_v6 popup")) { + return; + } + struct sway_xdg_popup_v6 *popup = (struct sway_xdg_popup_v6 *)child; + wl_list_remove(&popup->new_popup.link); + wl_list_remove(&popup->unmap.link); + wl_list_remove(&popup->destroy.link); + free(popup); +} + +static const struct sway_view_child_impl popup_impl = { + .destroy = popup_destroy, +}; + +static struct sway_xdg_popup_v6 *popup_create( + struct wlr_xdg_popup_v6 *wlr_popup, struct sway_view *view); + +static void popup_handle_new_popup(struct wl_listener *listener, void *data) { + struct sway_xdg_popup_v6 *popup = + wl_container_of(listener, popup, new_popup); + struct wlr_xdg_popup_v6 *wlr_popup = data; + popup_create(wlr_popup, popup->child.view); +} + +static void popup_handle_unmap(struct wl_listener *listener, void *data) { + struct sway_xdg_popup_v6 *popup = wl_container_of(listener, popup, unmap); + view_child_destroy(&popup->child); +} + +static void popup_handle_destroy(struct wl_listener *listener, void *data) { + struct sway_xdg_popup_v6 *popup = wl_container_of(listener, popup, destroy); + view_child_destroy(&popup->child); +} + +static struct sway_xdg_popup_v6 *popup_create( + struct wlr_xdg_popup_v6 *wlr_popup, struct sway_view *view) { + struct wlr_xdg_surface_v6 *xdg_surface = wlr_popup->base; + + struct sway_xdg_popup_v6 *popup = + calloc(1, sizeof(struct sway_xdg_popup_v6)); + if (popup == NULL) { + return NULL; + } + view_child_init(&popup->child, &popup_impl, view, xdg_surface->surface); + + wl_signal_add(&xdg_surface->events.new_popup, &popup->new_popup); + popup->new_popup.notify = popup_handle_new_popup; + wl_signal_add(&xdg_surface->events.unmap, &popup->unmap); + popup->unmap.notify = popup_handle_unmap; + wl_signal_add(&xdg_surface->events.destroy, &popup->destroy); + popup->destroy.notify = popup_handle_destroy; + + return popup; +} + + static struct sway_xdg_shell_v6_view *xdg_shell_v6_view_from_view( struct sway_view *view) { if (!sway_assert(view->type == SWAY_VIEW_XDG_SHELL_V6, @@ -76,6 +136,7 @@ static void destroy(struct sway_view *view) { } wl_list_remove(&xdg_shell_v6_view->commit.link); wl_list_remove(&xdg_shell_v6_view->destroy.link); + wl_list_remove(&xdg_shell_v6_view->new_popup.link); wl_list_remove(&xdg_shell_v6_view->map.link); wl_list_remove(&xdg_shell_v6_view->unmap.link); free(xdg_shell_v6_view); @@ -100,6 +161,13 @@ static void handle_commit(struct wl_listener *listener, void *data) { view_damage_from(view); } +static void handle_new_popup(struct wl_listener *listener, void *data) { + struct sway_xdg_shell_v6_view *xdg_shell_v6_view = + wl_container_of(listener, xdg_shell_v6_view, new_popup); + struct wlr_xdg_popup_v6 *wlr_popup = data; + popup_create(wlr_popup, &xdg_shell_v6_view->view); +} + static void handle_unmap(struct wl_listener *listener, void *data) { struct sway_xdg_shell_v6_view *xdg_shell_v6_view = wl_container_of(listener, xdg_shell_v6_view, unmap); @@ -151,6 +219,10 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { wl_signal_add(&xdg_surface->surface->events.commit, &xdg_shell_v6_view->commit); + xdg_shell_v6_view->new_popup.notify = handle_new_popup; + wl_signal_add(&xdg_surface->events.new_popup, + &xdg_shell_v6_view->new_popup); + xdg_shell_v6_view->map.notify = handle_map; wl_signal_add(&xdg_surface->events.map, &xdg_shell_v6_view->map); diff --git a/sway/tree/view.c b/sway/tree/view.c index 85fd3093..293edc95 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -176,6 +176,8 @@ void view_unmap(struct sway_view *view) { struct sway_container *parent = container_destroy(view->swayc); + wl_list_remove(&view->surface_new_subsurface.link); + view->swayc = NULL; view->surface = NULL;