From ef30e3750d2579d3107b13e0d27eca6d72d6abc0 Mon Sep 17 00:00:00 2001 From: Johan Malm Date: Wed, 22 Mar 2023 19:56:59 +0000 Subject: [PATCH] Decorations: handle results of kde-server-decoration negotiations --- include/decorations.h | 6 ++ include/labwc.h | 2 +- src/decorations/kde-deco.c | 132 ++++++++++++++++++++++++++++++++++++ src/decorations/meson.build | 1 + src/server.c | 13 +--- src/xdg.c | 42 +++++------- 6 files changed, 160 insertions(+), 36 deletions(-) create mode 100644 src/decorations/kde-deco.c diff --git a/include/decorations.h b/include/decorations.h index bad8569f..2f43c559 100644 --- a/include/decorations.h +++ b/include/decorations.h @@ -3,7 +3,13 @@ #define __LAB_DECORATIONS_H struct server; +struct view; +struct wlr_surface; +void kde_server_decoration_init(struct server *server); void xdg_server_decoration_init(struct server *server); +void kde_server_decoration_update_default(void); +void kde_server_decoration_set_view(struct view *view, struct wlr_surface *surface); + #endif /* __LAB_DECORATIONS_H */ diff --git a/include/labwc.h b/include/labwc.h index 718162bb..eee3b473 100644 --- a/include/labwc.h +++ b/include/labwc.h @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include @@ -220,6 +219,7 @@ struct server { struct wl_listener new_xdg_surface; struct wl_listener new_layer_surface; + struct wl_listener kde_server_decoration; struct wl_listener xdg_toplevel_decoration; #if HAVE_XWAYLAND struct wlr_xwayland *xwayland; diff --git a/src/decorations/kde-deco.c b/src/decorations/kde-deco.c new file mode 100644 index 00000000..f4dd876d --- /dev/null +++ b/src/decorations/kde-deco.c @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include +#include +#include "common/list.h" +#include "common/mem.h" +#include "decorations.h" +#include "labwc.h" +#include "view.h" + +static struct wl_list decorations; +static struct wlr_server_decoration_manager *kde_deco_mgr; + +struct kde_deco { + struct wl_list link; /* decorations */ + struct wlr_server_decoration *wlr_kde_decoration; + struct view *view; + struct wl_listener mode; + struct wl_listener destroy; +}; + +static void +handle_destroy(struct wl_listener *listener, void *data) +{ + struct kde_deco *kde_deco = wl_container_of(listener, kde_deco, destroy); + wl_list_remove(&kde_deco->destroy.link); + wl_list_remove(&kde_deco->mode.link); + wl_list_remove(&kde_deco->link); + free(kde_deco); +} + +static void +handle_mode(struct wl_listener *listener, void *data) +{ + struct kde_deco *kde_deco = wl_container_of(listener, kde_deco, mode); + if (!kde_deco->view) { + return; + } + + enum wlr_server_decoration_manager_mode client_mode = + kde_deco->wlr_kde_decoration->mode; + + switch (client_mode) { + case WLR_SERVER_DECORATION_MANAGER_MODE_SERVER: + kde_deco->view->ssd_preference = LAB_SSD_PREF_SERVER; + break; + case WLR_SERVER_DECORATION_MANAGER_MODE_NONE: + case WLR_SERVER_DECORATION_MANAGER_MODE_CLIENT: + kde_deco->view->ssd_preference = LAB_SSD_PREF_CLIENT; + break; + default: + wlr_log(WLR_ERROR, "Unspecified kde decoration variant " + "requested: %u", client_mode); + } + + view_set_decorations(kde_deco->view, + kde_deco->view->ssd_preference == LAB_SSD_PREF_SERVER); +} + +static void +handle_new_server_decoration(struct wl_listener *listener, void *data) +{ + struct wlr_server_decoration *wlr_deco = data; + struct kde_deco *kde_deco = znew(*kde_deco); + kde_deco->wlr_kde_decoration = wlr_deco; + + if (wlr_surface_is_xdg_surface(wlr_deco->surface)) { + /* + * Depending on the application event flow, the supplied + * wlr_surface may already have been set up as a xdg_surface + * or not (e.g. for GTK4). In the second case, the xdg.c + * new_surface handler will try to set the view via + * kde_server_decoration_set_view(). + */ + struct wlr_xdg_surface *xdg_surface = + wlr_xdg_surface_from_wlr_surface(wlr_deco->surface); + if (xdg_surface && xdg_surface->data) { + kde_deco->view = (struct view *)xdg_surface->data; + handle_mode(&kde_deco->mode, wlr_deco); + } + } + + wl_signal_add(&wlr_deco->events.destroy, &kde_deco->destroy); + kde_deco->destroy.notify = handle_destroy; + + wl_signal_add(&wlr_deco->events.mode, &kde_deco->mode); + kde_deco->mode.notify = handle_mode; + + wl_list_append(&decorations, &kde_deco->link); +} + +void +kde_server_decoration_set_view(struct view *view, struct wlr_surface *surface) +{ + struct kde_deco *kde_deco; + wl_list_for_each(kde_deco, &decorations, link) { + if (kde_deco->wlr_kde_decoration->surface == surface) { + if (!kde_deco->view) { + kde_deco->view = view; + handle_mode(&kde_deco->mode, kde_deco->wlr_kde_decoration); + } + return; + } + } +} + +void +kde_server_decoration_update_default(void) +{ + assert(kde_deco_mgr); + wlr_server_decoration_manager_set_default_mode(kde_deco_mgr, + rc.xdg_shell_server_side_deco + ? WLR_SERVER_DECORATION_MANAGER_MODE_SERVER + : WLR_SERVER_DECORATION_MANAGER_MODE_CLIENT); +} + +void +kde_server_decoration_init(struct server *server) +{ + assert(!kde_deco_mgr); + kde_deco_mgr = wlr_server_decoration_manager_create(server->wl_display); + if (!kde_deco_mgr) { + wlr_log(WLR_ERROR, "unable to create the kde server deco manager"); + exit(EXIT_FAILURE); + } + + wl_list_init(&decorations); + kde_server_decoration_update_default(); + + wl_signal_add(&kde_deco_mgr->events.new_decoration, &server->kde_server_decoration); + server->kde_server_decoration.notify = handle_new_server_decoration; +} + diff --git a/src/decorations/meson.build b/src/decorations/meson.build index b12a30f0..732e85d3 100644 --- a/src/decorations/meson.build +++ b/src/decorations/meson.build @@ -1,3 +1,4 @@ labwc_sources += files( + 'kde-deco.c', 'xdg-deco.c', ) diff --git a/src/server.c b/src/server.c index ffae132e..8d7280a9 100644 --- a/src/server.c +++ b/src/server.c @@ -53,6 +53,7 @@ reload_config_and_theme(void) menu_reconfigure(g_server); seat_reconfigure(g_server); regions_reconfigure(g_server); + kde_server_decoration_update_default(); } static int @@ -310,18 +311,8 @@ server_init(struct server *server) wl_signal_add(&server->xdg_shell->events.new_surface, &server->new_xdg_surface); - /* Disable CSD */ + kde_server_decoration_init(server); xdg_server_decoration_init(server); - struct wlr_server_decoration_manager *deco_mgr = NULL; - deco_mgr = wlr_server_decoration_manager_create(server->wl_display); - if (!deco_mgr) { - wlr_log(WLR_ERROR, "unable to create the server deco manager"); - exit(EXIT_FAILURE); - } - wlr_server_decoration_manager_set_default_mode( - deco_mgr, rc.xdg_shell_server_side_deco - ? WLR_SERVER_DECORATION_MANAGER_MODE_SERVER - : WLR_SERVER_DECORATION_MANAGER_MODE_CLIENT); server->xdg_activation = wlr_xdg_activation_v1_create(server->wl_display); if (!server->xdg_activation) { diff --git a/src/xdg.c b/src/xdg.c index 89775e60..921a5864 100644 --- a/src/xdg.c +++ b/src/xdg.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only #include #include "common/mem.h" +#include "decorations.h" #include "labwc.h" #include "node.h" #include "view.h" @@ -48,38 +49,22 @@ handle_new_xdg_popup(struct wl_listener *listener, void *data) static bool has_ssd(struct view *view) { + /* + * view->ssd_preference may be set by the decoration implementation + * e.g. src/decorations/xdg-deco.c or src/decorations/kde-deco.c. + */ switch (view->ssd_preference) { case LAB_SSD_PREF_SERVER: return true; case LAB_SSD_PREF_CLIENT: return false; default: - break; - } - - if (!rc.xdg_shell_server_side_deco) { /* - * User prefers client side decorations and - * the view didn't negotiate server side ones. + * We don't know anything about the client preference + * so fall back to core.decoration settings in rc.xml */ - return false; + return rc.xdg_shell_server_side_deco; } - - /* - * Some XDG shells refuse to disable CSD in which case their - * geometry.{x,y} seems to be greater than zero. We filter on that - * on the assumption that this will remain true. - * - * TODO: Replace this with a proper implementation of - * the KDE decoration variant as can be seen at - * https://github.com/swaywm/sway/blob/master/sway/decoration.c - */ - struct wlr_xdg_surface_state *current = - &xdg_surface_from_view(view)->current; - if (current->geometry.x || current->geometry.y) { - return false; - } - return true; } static void @@ -560,9 +545,18 @@ xdg_surface_new(struct wl_listener *listener, void *data) node_descriptor_create(&view->scene_tree->node, LAB_NODE_DESC_VIEW, view); - /* In support of xdg_toplevel_decoration */ + /* In support of xdg_toplevel_decoration and kde_server_decoration */ xdg_surface->data = view; + /* + * GTK4 initializes the decorations on the wl_surface before + * converting it into a xdg surface. This call takes care of + * connecting the view to an existing decoration. If there + * is no existing decoration object available for the + * wl_surface, this call is a no-op. + */ + kde_server_decoration_set_view(view, xdg_surface->surface); + /* In support of xdg popups */ xdg_surface->surface->data = tree; -- 2.52.0