]> git.mdlowis.com Git - proto/labwc.git/commitdiff
xwayland: support querying window types
authorConsolatis <35009135+Consolatis@users.noreply.github.com>
Wed, 24 Jan 2024 17:06:57 +0000 (18:06 +0100)
committerJohan Malm <johanmalm@users.noreply.github.com>
Thu, 25 Jan 2024 21:14:30 +0000 (21:14 +0000)
include/labwc.h
include/xwayland.h
src/xwayland.c

index 78b8b3b624daba8eea53dbe536e104cab877d4cd..70cef9475a18a7741c4b792ebd44679beaae154b 100644 (file)
@@ -220,7 +220,8 @@ struct server {
        struct wl_listener xdg_toplevel_decoration;
 #if HAVE_XWAYLAND
        struct wlr_xwayland *xwayland;
-       struct wl_listener xwayland_ready;
+       struct wl_listener xwayland_server_ready;
+       struct wl_listener xwayland_xwm_ready;
        struct wl_listener xwayland_new_surface;
 #endif
 
index e452dbe35ab646a9fed578540eebaeb67f3bbf5f..6009ad9d5abe0fdafab17692fe41c721f7944492 100644 (file)
@@ -2,13 +2,61 @@
 #ifndef LABWC_XWAYLAND_H
 #define LABWC_XWAYLAND_H
 #include "config.h"
+
 #if HAVE_XWAYLAND
+#include <assert.h>
+#include <stdbool.h>
+#include <xcb/xcb.h>
+#include "common/macros.h"
 #include "view.h"
 
 struct wlr_compositor;
 struct wlr_output;
 struct wlr_output_layout;
 
+enum atom {
+       /* https://specifications.freedesktop.org/wm-spec/wm-spec-1.4.html#idm45649101374512 */
+       NET_WM_WINDOW_TYPE_DESKTOP = 0,
+       NET_WM_WINDOW_TYPE_DOCK,
+       NET_WM_WINDOW_TYPE_TOOLBAR,
+       NET_WM_WINDOW_TYPE_MENU,
+       NET_WM_WINDOW_TYPE_UTILITY,
+       NET_WM_WINDOW_TYPE_SPLASH,
+       NET_WM_WINDOW_TYPE_DIALOG,
+       NET_WM_WINDOW_TYPE_DROPDOWN_MENU,
+       NET_WM_WINDOW_TYPE_POPUP_MENU,
+       NET_WM_WINDOW_TYPE_TOOLTIP,
+       NET_WM_WINDOW_TYPE_NOTIFICATION,
+       NET_WM_WINDOW_TYPE_COMBO,
+       NET_WM_WINDOW_TYPE_DND,
+       NET_WM_WINDOW_TYPE_NORMAL,
+
+       ATOM_LEN
+};
+
+static const char * const atom_names[] = {
+       "_NET_WM_WINDOW_TYPE_DESKTOP",
+       "_NET_WM_WINDOW_TYPE_DOCK",
+       "_NET_WM_WINDOW_TYPE_TOOLBAR",
+       "_NET_WM_WINDOW_TYPE_MENU",
+       "_NET_WM_WINDOW_TYPE_UTILITY",
+       "_NET_WM_WINDOW_TYPE_SPLASH",
+       "_NET_WM_WINDOW_TYPE_DIALOG",
+       "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU",
+       "_NET_WM_WINDOW_TYPE_POPUP_MENU",
+       "_NET_WM_WINDOW_TYPE_TOOLTIP",
+       "_NET_WM_WINDOW_TYPE_NOTIFICATION",
+       "_NET_WM_WINDOW_TYPE_COMBO",
+       "_NET_WM_WINDOW_TYPE_DND",
+       "_NET_WM_WINDOW_TYPE_NORMAL",
+};
+
+static_assert(
+       ARRAY_SIZE(atom_names) == ATOM_LEN,
+       "Xwayland atoms out of sync");
+
+extern xcb_atom_t atoms[ATOM_LEN];
+
 struct xwayland_unmanaged {
        struct server *server;
        struct wlr_xwayland_surface *xwayland_surface;
@@ -40,10 +88,10 @@ struct xwayland_view {
        struct wl_listener set_decorations;
        struct wl_listener set_override_redirect;
        struct wl_listener set_strut_partial;
+       struct wl_listener set_window_type;
 
        /* Not (yet) implemented */
 /*     struct wl_listener set_role; */
-/*     struct wl_listener set_window_type; */
 /*     struct wl_listener set_hints; */
 };
 
@@ -57,6 +105,9 @@ void xwayland_adjust_stacking_order(struct server *server);
 
 struct wlr_xwayland_surface *xwayland_surface_from_view(struct view *view);
 
+bool xwayland_surface_contains_window_type(
+       struct wlr_xwayland_surface *surface, enum atom window_type);
+
 void xwayland_server_init(struct server *server,
        struct wlr_compositor *compositor);
 void xwayland_server_finish(struct server *server);
index 60ce52749a467c28d3848d4c9079d04e770508af..6c954deefe4ed83b34b7c11e6c99a809cbd87503 100644 (file)
 #include "workspaces.h"
 #include "xwayland.h"
 
+xcb_atom_t atoms[ATOM_LEN] = {0};
+
 static void xwayland_view_unmap(struct view *view, bool client_request);
 
+bool
+xwayland_surface_contains_window_type(
+               struct wlr_xwayland_surface *surface, enum atom window_type)
+{
+       assert(surface);
+       for (size_t i = 0; i < surface->window_type_len; i++) {
+               if (surface->window_type[i] == atoms[window_type]) {
+                       return true;
+               }
+       }
+       return false;
+}
+
 static struct view_size_hints
 xwayland_view_get_size_hints(struct view *view)
 {
@@ -313,6 +328,7 @@ handle_destroy(struct wl_listener *listener, void *data)
        wl_list_remove(&xwayland_view->set_decorations.link);
        wl_list_remove(&xwayland_view->set_override_redirect.link);
        wl_list_remove(&xwayland_view->set_strut_partial.link);
+       wl_list_remove(&xwayland_view->set_window_type.link);
 
        view_destroy(view);
 }
@@ -478,6 +494,12 @@ handle_set_decorations(struct wl_listener *listener, void *data)
        view_set_decorations(view, want_deco(xwayland_view->xwayland_surface));
 }
 
+static void
+handle_set_window_type(struct wl_listener *listener, void *data)
+{
+       /* Intentionally left blank */
+}
+
 static void
 handle_set_override_redirect(struct wl_listener *listener, void *data)
 {
@@ -865,6 +887,7 @@ xwayland_view_create(struct server *server,
        CONNECT_SIGNAL(xsurface, xwayland_view, set_decorations);
        CONNECT_SIGNAL(xsurface, xwayland_view, set_override_redirect);
        CONNECT_SIGNAL(xsurface, xwayland_view, set_strut_partial);
+       CONNECT_SIGNAL(xsurface, xwayland_view, set_window_type);
 
        wl_list_insert(&view->server->views, &view->link);
 
@@ -896,10 +919,62 @@ handle_new_surface(struct wl_listener *listener, void *data)
 }
 
 static void
-handle_ready(struct wl_listener *listener, void *data)
+sync_atoms(xcb_connection_t *xcb_conn)
+{
+       assert(xcb_conn);
+
+       wlr_log(WLR_DEBUG, "Syncing X11 atoms");
+       xcb_intern_atom_cookie_t cookies[ATOM_LEN];
+
+       /* First request everything and then loop over the results to reduce latency */
+       for (size_t i = 0; i < ATOM_LEN; i++) {
+               cookies[i] = xcb_intern_atom(xcb_conn, 0,
+                       strlen(atom_names[i]), atom_names[i]);
+       }
+
+       for (size_t i = 0; i < ATOM_LEN; i++) {
+               xcb_generic_error_t *err = NULL;
+               xcb_intern_atom_reply_t *reply =
+                       xcb_intern_atom_reply(xcb_conn, cookies[i], &err);
+               if (reply) {
+                       atoms[i] = reply->atom;
+                       wlr_log(WLR_DEBUG, "Got X11 atom for %s: %u",
+                               atom_names[i], reply->atom);
+               }
+               if (err) {
+                       wlr_log(WLR_INFO, "Failed to get X11 atom for %s",
+                               atom_names[i]);
+               }
+               free(reply);
+               free(err);
+       }
+}
+
+static void
+handle_server_ready(struct wl_listener *listener, void *data)
+{
+       xcb_connection_t *xcb_conn = xcb_connect(NULL, NULL);
+       if (xcb_connection_has_error(xcb_conn)) {
+               wlr_log(WLR_ERROR, "Failed to create xcb connection");
+
+               /* Just clear all existing atoms */
+               for (size_t i = 0; i < ATOM_LEN; i++) {
+                       atoms[i] = XCB_ATOM_NONE;
+               }
+               return;
+       }
+
+       wlr_log(WLR_DEBUG, "Connected to xwayland");
+       sync_atoms(xcb_conn);
+       wlr_log(WLR_DEBUG, "Disconnecting from xwayland");
+       xcb_disconnect(xcb_conn);
+}
+
+static void
+handle_xwm_ready(struct wl_listener *listener, void *data)
 {
        struct server *server =
-               wl_container_of(listener, server, xwayland_ready);
+               wl_container_of(listener, server, xwayland_xwm_ready);
        wlr_xwayland_set_seat(server->xwayland, server->seat.seat);
        xwayland_update_workarea(server);
 }
@@ -917,9 +992,13 @@ xwayland_server_init(struct server *server, struct wlr_compositor *compositor)
        wl_signal_add(&server->xwayland->events.new_surface,
                &server->xwayland_new_surface);
 
-       server->xwayland_ready.notify = handle_ready;
+       server->xwayland_server_ready.notify = handle_server_ready;
+       wl_signal_add(&server->xwayland->server->events.ready,
+               &server->xwayland_server_ready);
+
+       server->xwayland_xwm_ready.notify = handle_xwm_ready;
        wl_signal_add(&server->xwayland->events.ready,
-               &server->xwayland_ready);
+               &server->xwayland_xwm_ready);
 
        if (setenv("DISPLAY", server->xwayland->display_name, true) < 0) {
                wlr_log_errno(WLR_ERROR, "unable to set DISPLAY for xwayland");