#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;
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; */
};
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);
#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)
{
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);
}
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)
{
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);
}
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);
}
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");