From d54a998dd8e1a3faff4f39b8bc88597f213b3ef2 Mon Sep 17 00:00:00 2001 From: Johan Malm Date: Tue, 2 Mar 2021 20:37:23 +0000 Subject: [PATCH] Handle wlr_surface->events.new_subsurface Add view-child.c, xdg-popup.c, subsurface.c in order to track damage associated with new XDG subsurfaces. --- include/labwc.h | 27 +++++++++++++-- src/meson.build | 3 ++ src/subsurface.c | 34 +++++++++++++++++++ src/view-child.c | 46 +++++++++++++++++++++++++ src/view.c | 2 +- src/xdg-popup.c | 74 ++++++++++++++++++++++++++++++++++++++++ src/xdg.c | 88 ++++++++---------------------------------------- 7 files changed, 196 insertions(+), 78 deletions(-) create mode 100644 src/subsurface.c create mode 100644 src/view-child.c create mode 100644 src/xdg-popup.c diff --git a/include/labwc.h b/include/labwc.h index 30359aef..1891af7f 100644 --- a/include/labwc.h +++ b/include/labwc.h @@ -230,7 +230,8 @@ struct view { struct wl_listener request_resize; struct wl_listener request_configure; struct wl_listener request_maximize; - struct wl_listener new_popup; /* xdg-shell only */ + struct wl_listener new_popup; /* xdg-shell only */ + struct wl_listener new_subsurface; /* xdg-shell only */ }; #if HAVE_XWAYLAND @@ -248,18 +249,33 @@ struct xwayland_unmanaged { }; #endif +struct view_child { + struct wlr_surface *surface; + struct view *parent; + struct wl_listener commit; + struct wl_listener new_subsurface; +}; + +struct view_subsurface { + struct view_child view_child; + struct wlr_subsurface *subsurface; + struct wl_listener destroy; +}; + struct xdg_popup { + struct view_child view_child; struct wlr_xdg_popup *wlr_popup; - struct view *view; struct wl_listener destroy; - struct wl_listener commit; struct wl_listener map; struct wl_listener unmap; struct wl_listener new_popup; }; +void xdg_popup_create(struct view *view, struct wlr_xdg_popup *wlr_popup); + void xdg_toplevel_decoration(struct wl_listener *listener, void *data); + void xdg_surface_new(struct wl_listener *listener, void *data); #if HAVE_XWAYLAND @@ -268,6 +284,11 @@ void xwayland_unmanaged_create(struct server *server, struct wlr_xwayland_surface *xsurface); #endif +void view_child_init(struct view_child *child, struct view *view, + struct wlr_surface *wlr_surface); +void view_child_finish(struct view_child *child); +void subsurface_create(struct view *view, struct wlr_subsurface *wlr_subsurface); + void view_move_resize(struct view *view, struct wlr_box geo); void view_move(struct view *view, double x, double y); void view_minimize(struct view *view); diff --git a/src/meson.build b/src/meson.build index 8808657a..2220eb24 100644 --- a/src/meson.build +++ b/src/meson.build @@ -12,9 +12,12 @@ labwc_sources = files( 'output.c', 'seat.c', 'server.c', + 'subsurface.c', 'theme.c', 'view.c', + 'view-child.c', 'xdg.c', + 'xdg-popup.c', ) if have_xwayland diff --git a/src/subsurface.c b/src/subsurface.c new file mode 100644 index 00000000..2e49e71d --- /dev/null +++ b/src/subsurface.c @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2020 the sway authors + * This file is only needed in support of tracking damage + */ + +#include "labwc.h" + +static void +subsurface_handle_destroy(struct wl_listener *listener, void *data) +{ + struct view_subsurface *subsurface = wl_container_of(listener, + subsurface, destroy); + struct view_child *view_child = (struct view_child *)subsurface; + if (!view_child) { + return; + } + wl_list_remove(&subsurface->destroy.link); + view_child_finish(&subsurface->view_child); + free(subsurface); +} + +void +subsurface_create(struct view *view, struct wlr_subsurface *wlr_subsurface) +{ + struct view_subsurface *subsurface = calloc(1, sizeof(struct view_subsurface)); + if (!subsurface) { + return; + } + view_child_init(&subsurface->view_child, view, wlr_subsurface->surface); + subsurface->subsurface = wlr_subsurface; + + subsurface->destroy.notify = subsurface_handle_destroy; + wl_signal_add(&wlr_subsurface->events.destroy, &subsurface->destroy); +} diff --git a/src/view-child.c b/src/view-child.c new file mode 100644 index 00000000..d1b0b904 --- /dev/null +++ b/src/view-child.c @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2020 the sway authors + * This file is only needed in support of tracking damage + */ + +#include "labwc.h" + +static void +view_child_handle_commit(struct wl_listener *listener, void *data) +{ + struct view_child *child = wl_container_of(listener, child, commit); + damage_view_part(child->parent); +} + +static void +view_child_handle_new_subsurface(struct wl_listener *listener, void *data) +{ + struct view_child *child; + child = wl_container_of(listener, child, new_subsurface); + struct wlr_subsurface *wlr_subsurface = data; + subsurface_create(child->parent, wlr_subsurface); +} + +void +view_child_finish(struct view_child *child) +{ + if (!child) { + return; + } + damage_view_whole(child->parent); + wl_list_remove(&child->commit.link); + wl_list_remove(&child->new_subsurface.link); +} + +void +view_child_init(struct view_child *child, struct view *view, + struct wlr_surface *wlr_surface) +{ + child->parent = view; + child->surface = wlr_surface; + + child->commit.notify = view_child_handle_commit; + wl_signal_add(&wlr_surface->events.commit, &child->commit); + child->new_subsurface.notify = view_child_handle_new_subsurface; + wl_signal_add(&wlr_surface->events.new_subsurface, &child->new_subsurface); +} diff --git a/src/view.c b/src/view.c index 56aef3f3..cc7ac1db 100644 --- a/src/view.c +++ b/src/view.c @@ -1,7 +1,7 @@ #include "labwc.h" #include -#include + void view_move_resize(struct view *view, struct wlr_box geo) { diff --git a/src/xdg-popup.c b/src/xdg-popup.c new file mode 100644 index 00000000..f4b9b181 --- /dev/null +++ b/src/xdg-popup.c @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2020 the sway authors + * This file is only needed in support of tracking damage + */ + +#include "labwc.h" + +static void +xdg_popup_destroy(struct view_child *view_child) +{ + if (!view_child) { + return; + } + struct xdg_popup *popup = (struct xdg_popup *)view_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) +{ + struct xdg_popup *popup = wl_container_of(listener, popup, map); + damage_view_whole(popup->view_child.parent); +} + +static void +handle_xdg_popup_unmap(struct wl_listener *listener, void *data) +{ + struct xdg_popup *popup = wl_container_of(listener, popup, unmap); + damage_view_whole(popup->view_child.parent); +} + +static void +handle_xdg_popup_destroy(struct wl_listener *listener, void *data) +{ + struct xdg_popup *popup = wl_container_of(listener, popup, destroy); + struct view_child *view_child = (struct view_child *)popup; + xdg_popup_destroy(view_child); +} + +static void +popup_handle_new_xdg_popup(struct wl_listener *listener, void *data) +{ + struct xdg_popup *popup = wl_container_of(listener, popup, new_popup); + struct wlr_xdg_popup *wlr_popup = data; + xdg_popup_create(popup->view_child.parent, wlr_popup); +} + +void +xdg_popup_create(struct view *view, struct wlr_xdg_popup *wlr_popup) +{ + struct xdg_popup *popup = calloc(1, sizeof(struct xdg_popup)); + if (!popup) { + return; + } + + popup->wlr_popup = wlr_popup; + view_child_init(&popup->view_child, view, wlr_popup->base->surface); + + 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); + + /* TODO: popup_unconstrain() */ +} diff --git a/src/xdg.c b/src/xdg.c index 3b70f56c..73923291 100644 --- a/src/xdg.c +++ b/src/xdg.c @@ -52,78 +52,6 @@ xdg_toplevel_decoration(struct wl_listener *listener, void *data) xdg_deco_request_mode(&xdg_deco->request_mode, wlr_decoration); } -static void -handle_xdg_popup_commit(struct wl_listener *listener, void *data) -{ - struct xdg_popup *popup = wl_container_of(listener, popup, map); - /* TODO */ -} - -static void -handle_xdg_popup_map(struct wl_listener *listener, void *data) -{ - struct xdg_popup *popup = wl_container_of(listener, popup, map); - /* damagage whole output here as popup might go outside view */ - damage_all_outputs(popup->view->server); -} - -static void -handle_xdg_popup_unmap(struct wl_listener *listener, void *data) -{ - struct xdg_popup *popup = wl_container_of(listener, popup, unmap); - damage_all_outputs(popup->view->server); -} - -static void -handle_xdg_popup_destroy(struct wl_listener *listener, void *data) -{ - struct xdg_popup *popup = wl_container_of(listener, popup, destroy); - wl_list_remove(&popup->destroy.link); - wl_list_remove(&popup->commit.link); - wl_list_remove(&popup->map.link); - wl_list_remove(&popup->unmap.link); - wl_list_remove(&popup->new_popup.link); - free(popup); -} - -static void xdg_popup_create(struct view *view, struct wlr_xdg_popup *wlr_popup); - -static void -popup_handle_new_xdg_popup(struct wl_listener *listener, void *data) -{ - struct xdg_popup *popup = wl_container_of(listener, popup, new_popup); - struct wlr_xdg_popup *wlr_popup = data; - xdg_popup_create(popup->view, wlr_popup); -} - -/* - * We need to pass view to this function for damage tracking. - * TODO: Could we just damage surface or whole output? - * That would allow us to only have one 'handle_new_*' - */ -static void -xdg_popup_create(struct view *view, struct wlr_xdg_popup *wlr_popup) -{ - struct xdg_popup *popup = calloc(1, sizeof(struct xdg_popup)); - if (!popup) { - return; - } - - popup->wlr_popup = wlr_popup; - popup->view = view; - - popup->destroy.notify = handle_xdg_popup_destroy; - wl_signal_add(&wlr_popup->base->events.destroy, &popup->destroy); - popup->commit.notify = handle_xdg_popup_commit; - wl_signal_add(&wlr_popup->base->surface->events.commit, &popup->commit); - 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); -} - /* This is merely needed to track damage */ static void handle_new_xdg_popup(struct wl_listener *listener, void *data) @@ -133,6 +61,14 @@ handle_new_xdg_popup(struct wl_listener *listener, void *data) xdg_popup_create(view, wlr_popup); } +static void +new_subsurface_notify(struct wl_listener *listener, void *data) +{ + struct view *view = wl_container_of(listener, view, new_subsurface); + struct wlr_subsurface *wlr_subsurface = data; + subsurface_create(view, wlr_subsurface); +} + static bool has_ssd(struct view *view) { @@ -348,9 +284,12 @@ xdg_toplevel_view_map(struct view *view) } view->been_mapped = true; - wl_signal_add(&view->xdg_surface->surface->events.commit, - &view->commit); view->commit.notify = handle_commit; + wl_signal_add(&view->xdg_surface->surface->events.commit, + &view->commit); + view->new_subsurface.notify = new_subsurface_notify; + wl_signal_add(&view->surface->events.new_subsurface, + &view->new_subsurface); desktop_focus_view(&view->server->seat, view); damage_all_outputs(view->server); @@ -362,6 +301,7 @@ xdg_toplevel_view_unmap(struct view *view) view->mapped = false; damage_all_outputs(view->server); wl_list_remove(&view->commit.link); + wl_list_remove(&view->new_subsurface.link); desktop_focus_topmost_mapped_view(view->server); }