]> git.mdlowis.com Git - proto/labwc.git/commitdiff
Decorations: handle results of kde-server-decoration negotiations
authorJohan Malm <jgm323@gmail.com>
Wed, 22 Mar 2023 19:56:59 +0000 (19:56 +0000)
committerJohan Malm <johanmalm@users.noreply.github.com>
Sat, 25 Mar 2023 07:24:40 +0000 (07:24 +0000)
include/decorations.h
include/labwc.h
src/decorations/kde-deco.c [new file with mode: 0644]
src/decorations/meson.build
src/server.c
src/xdg.c

index bad8569fcef5e27617e77706c5430a3664a57aa8..2f43c559d08c7b264ca1a6e8b93a974357295815 100644 (file)
@@ -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 */
index 718162bbce9013966d230dab30f70169daefd528..eee3b47367bbf37d4bc8c87b6dac825390b6e019 100644 (file)
@@ -34,7 +34,6 @@
 #include <wlr/types/wlr_pointer_constraints_v1.h>
 #include <wlr/types/wlr_pointer_gestures_v1.h>
 #include <wlr/types/wlr_seat.h>
-#include <wlr/types/wlr_server_decoration.h>
 #include <wlr/types/wlr_subcompositor.h>
 #include <wlr/types/wlr_xcursor_manager.h>
 #include <wlr/types/wlr_xdg_activation_v1.h>
@@ -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 (file)
index 0000000..f4dd876
--- /dev/null
@@ -0,0 +1,132 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <assert.h>
+#include <wlr/types/wlr_server_decoration.h>
+#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;
+}
+
index b12a30f0e05015c63a82c655e3ee0438257048f0..732e85d3eb9202ea15fe4854ecf7ba00e1ba3468 100644 (file)
@@ -1,3 +1,4 @@
 labwc_sources += files(
+  'kde-deco.c',
   'xdg-deco.c',
 )
index ffae132e11c9af4411d18b93ad57e5c9895819e8..8d7280a93993b90d94ce216fb13de34284910e43 100644 (file)
@@ -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) {
index 89775e608bf67aad0c143e80033c0f1758ec55ba..921a5864f9e9dcce07c537edb54002a8f5d7a15e 100644 (file)
--- a/src/xdg.c
+++ b/src/xdg.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 #include <assert.h>
 #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;