commit c9bd0ea004f240e3e4babcfd3686e897e73db3ef
parent 99c5c6058b30e11dbdfd313190a75835a9186e29
Author: deurzen <max@deurzen.net>
Date: Mon, 30 May 2022 20:52:45 +0200
provides xwayland subsystem establishment
Diffstat:
9 files changed, 222 insertions(+), 72 deletions(-)
diff --git a/include/kranewl/model.hh b/include/kranewl/model.hh
@@ -23,6 +23,7 @@ typedef class Context* Context_ptr;
typedef class Workspace* Workspace_ptr;
typedef class Server* Server_ptr;
typedef struct View* View_ptr;
+typedef struct XWayland* XWayland_ptr;
typedef struct XDGView* XDGView_ptr;
#ifdef XWAYLAND
typedef struct XWaylandView* XWaylandView_ptr;
@@ -53,7 +54,7 @@ public:
XDGView_ptr create_xdg_shell_view(struct wlr_xdg_surface*, Seat_ptr);
#ifdef XWAYLAND
- XWaylandView_ptr create_xwayland_view(struct wlr_xwayland_surface*, Seat_ptr);
+ XWaylandView_ptr create_xwayland_view(struct wlr_xwayland_surface*, Seat_ptr, XWayland_ptr);
#endif
void register_view(View_ptr, Workspace_ptr);
void unregister_view(View_ptr);
diff --git a/include/kranewl/server.hh b/include/kranewl/server.hh
@@ -2,6 +2,7 @@
#include <kranewl/geometry.hh>
#include <kranewl/input/seat.hh>
+#include <kranewl/xwayland.hh>
extern "C" {
#include <wlr/backend.h>
@@ -45,9 +46,6 @@ private:
#ifdef XWAYLAND
static void handle_xwayland_ready(struct wl_listener*, void*);
static void handle_new_xwayland_surface(struct wl_listener*, void*);
- static void handle_xwayland_request_activate(struct wl_listener*, void*);
- static void handle_xwayland_request_configure(struct wl_listener*, void*);
- static void handle_xwayland_set_hints(struct wl_listener*, void*);
#endif
Model_ptr mp_model;
@@ -61,7 +59,8 @@ public:
struct wlr_allocator* mp_allocator;
struct wlr_compositor* mp_compositor;
#ifdef XWAYLAND
- struct wlr_xwayland* mp_xwayland;
+ struct wlr_xwayland* mp_wlr_xwayland;
+ XWayland m_xwayland;
#endif
struct wlr_data_device_manager* mp_data_device_manager;
struct wlr_output_layout* mp_output_layout;
@@ -87,10 +86,6 @@ private:
struct wl_listener ml_xdg_activation;
struct wl_listener ml_new_input;
struct wl_listener ml_xdg_new_toplevel_decoration;
-#ifdef XWAYLAND
- struct wl_listener ml_xwayland_ready;
- struct wl_listener ml_new_xwayland_surface;
-#endif
const std::string m_socket;
diff --git a/include/kranewl/tree/xwayland_view.hh b/include/kranewl/tree/xwayland_view.hh
@@ -1,5 +1,6 @@
#pragma once
+#ifdef XWAYLAND
#include <kranewl/tree/view.hh>
#include <kranewl/util.hh>
@@ -9,14 +10,15 @@ typedef class Seat* Seat_ptr;
typedef class Output* Output_ptr;
typedef class Context* Context_ptr;
typedef class Workspace* Workspace_ptr;
+typedef struct XWayland* XWayland_ptr;
-#ifdef XWAYLAND
typedef struct XWaylandView final : public View {
XWaylandView(
struct wlr_xwayland_surface*,
Server_ptr,
Model_ptr,
- Seat_ptr
+ Seat_ptr,
+ XWayland_ptr
);
~XWaylandView();
@@ -56,6 +58,8 @@ typedef struct XWaylandView final : public View {
static void handle_destroy(struct wl_listener*, void*);
static void handle_override_redirect(struct wl_listener*, void*);
+ XWayland_ptr mp_xwayland;
+
struct wlr_xwayland_surface* mp_wlr_xwayland_surface;
struct wl_listener ml_commit;
@@ -80,9 +84,11 @@ typedef struct XWaylandView final : public View {
}* XWaylandView_ptr;
typedef struct XWaylandUnmanaged final {
- XWaylandUnmanaged(struct wlr_xwayland_surface*);
+ XWaylandUnmanaged(struct wlr_xwayland_surface*, XWayland_ptr);
~XWaylandUnmanaged();
+ XWayland_ptr mp_xwayland;
+
Pos m_pos;
struct wlr_xwayland_surface* mp_wlr_xwayland_surface;
diff --git a/include/kranewl/xwayland.hh b/include/kranewl/xwayland.hh
@@ -0,0 +1,48 @@
+#pragma once
+
+#ifdef XWAYLAND
+extern "C" {
+#include <wayland-server-core.h>
+#define Cursor Cursor_
+#include <xcb/xproto.h>
+#undef Cursor
+}
+
+#include <array>
+
+typedef class Server* Server_ptr;
+
+typedef struct XWayland final {
+ enum XAtom {
+ NET_WM_WINDOW_TYPE_NORMAL = 0,
+ NET_WM_WINDOW_TYPE_DIALOG,
+ NET_WM_WINDOW_TYPE_UTILITY,
+ NET_WM_WINDOW_TYPE_TOOLBAR,
+ NET_WM_WINDOW_TYPE_SPLASH,
+ NET_WM_WINDOW_TYPE_MENU,
+ NET_WM_WINDOW_TYPE_DROPDOWN_MENU,
+ NET_WM_WINDOW_TYPE_POPUP_MENU,
+ NET_WM_WINDOW_TYPE_TOOLTIP,
+ NET_WM_WINDOW_TYPE_NOTIFICATION,
+ NET_WM_STATE_MODAL,
+ XATOM_LAST,
+ };
+
+ XWayland(struct wlr_xwayland*, Server_ptr);
+ ~XWayland();
+
+ static void handle_ready(struct wl_listener*, void*);
+ static void handle_new_surface(struct wl_listener*, void*);
+
+ struct wlr_xwayland* mp_wlr_xwayland;
+ struct wlr_xcursor_manager* mp_cursor_manager;
+
+ std::array<xcb_atom_t, XATOM_LAST> m_atoms;
+
+ Server_ptr mp_server;
+
+ struct wl_listener ml_ready;
+ struct wl_listener ml_new_surface;
+
+}* XWayland_ptr;
+#endif
diff --git a/src/kranewl/input/cursor.cc b/src/kranewl/input/cursor.cc
@@ -54,7 +54,7 @@ Cursor::Cursor(
{
TRACE();
- wlr_xcursor_manager_load(mp_cursor_manager, 1);
+ wlr_xcursor_manager_load(mp_cursor_manager, 1.f);
wl_signal_add(&cursor->events.motion, &ml_cursor_motion);
wl_signal_add(&cursor->events.motion_absolute, &ml_cursor_motion_absolute);
diff --git a/src/kranewl/model.cc b/src/kranewl/model.cc
@@ -1823,7 +1823,8 @@ Model::create_xdg_shell_view(
XWaylandView_ptr
Model::create_xwayland_view(
struct wlr_xwayland_surface* wlr_xwayland_surface,
- Seat_ptr seat
+ Seat_ptr seat,
+ XWayland_ptr xwayland
)
{
TRACE();
@@ -1832,7 +1833,8 @@ Model::create_xwayland_view(
wlr_xwayland_surface,
mp_server,
this,
- seat
+ seat,
+ xwayland
);
m_view_map[view->m_uid] = view;
diff --git a/src/kranewl/server.cc b/src/kranewl/server.cc
@@ -10,6 +10,7 @@
#include <kranewl/tree/xdg_view.hh>
#ifdef XWAYLAND
#include <kranewl/tree/xwayland_view.hh>
+#include <kranewl/xwayland.hh>
#endif
#include <spdlog/spdlog.h>
@@ -130,7 +131,8 @@ Server::Server(Model_ptr model)
};
}()),
#ifdef XWAYLAND
- mp_xwayland(wlr_xwayland_create(mp_display, mp_compositor, 1)),
+ mp_wlr_xwayland(wlr_xwayland_create(mp_display, mp_compositor, true)),
+ m_xwayland({mp_wlr_xwayland, this}),
#endif
mp_layer_shell(wlr_layer_shell_v1_create(mp_display)),
mp_xdg_shell(wlr_xdg_shell_create(mp_display)),
@@ -147,10 +149,6 @@ Server::Server(Model_ptr model)
ml_xdg_activation({ .notify = Server::handle_xdg_activation }),
ml_new_input({ .notify = Server::handle_new_input }),
ml_xdg_new_toplevel_decoration({ .notify = Server::handle_xdg_new_toplevel_decoration }),
-#ifdef XWAYLAND
- ml_xwayland_ready({ .notify = Server::handle_xwayland_ready }),
- ml_new_xwayland_surface({ .notify = Server::handle_new_xwayland_surface }),
-#endif
m_socket(wl_display_add_socket_auto(mp_display))
{
TRACE();
@@ -189,17 +187,6 @@ Server::Server(Model_ptr model)
// TODO: mp_virtual_pointer_manager signals
// TODO: mp_virtual_keyboard_manager signals
-#ifdef XWAYLAND
- if (mp_xwayland) {
- wl_signal_add(&mp_xwayland->events.ready, &ml_xwayland_ready);
- wl_signal_add(&mp_xwayland->events.new_surface, &ml_new_xwayland_surface);
- setenv("DISPLAY", mp_xwayland->display_name, 1);
- } else {
- spdlog::error("Failed to initiate XWayland");
- spdlog::warn("Continuing without XWayland functionality");
- }
-#endif
-
if (!wlr_backend_start(mp_backend)) {
wlr_backend_destroy(mp_backend);
wl_display_destroy(mp_display);
@@ -363,11 +350,11 @@ Server::handle_new_xdg_surface(struct wl_listener* listener, void* data)
{
TRACE();
- View_ptr view;
Server_ptr server = wl_container_of(listener, server, ml_new_xdg_surface);
struct wlr_xdg_surface* xdg_surface
= reinterpret_cast<struct wlr_xdg_surface*>(data);
+ View_ptr view;
switch (xdg_surface->role) {
case WLR_XDG_SURFACE_ROLE_POPUP:
{
@@ -554,40 +541,3 @@ Server::handle_xdg_toplevel_request_resize(struct wl_listener*, void*)
TRACE();
}
-
-#ifdef XWAYLAND
-void
-Server::handle_xwayland_ready(struct wl_listener*, void*)
-{
- TRACE();
-
-}
-
-void
-Server::handle_new_xwayland_surface(struct wl_listener*, void*)
-{
- TRACE();
-
-}
-
-void
-Server::handle_xwayland_request_activate(struct wl_listener*, void*)
-{
- TRACE();
-
-}
-
-void
-Server::handle_xwayland_request_configure(struct wl_listener*, void*)
-{
- TRACE();
-
-}
-
-void
-Server::handle_xwayland_set_hints(struct wl_listener*, void*)
-{
- TRACE();
-
-}
-#endif
diff --git a/src/kranewl/tree/xwayland_view.cc b/src/kranewl/tree/xwayland_view.cc
@@ -20,7 +20,8 @@ XWaylandView::XWaylandView(
struct wlr_xwayland_surface* wlr_xwayland_surface,
Server_ptr server,
Model_ptr model,
- Seat_ptr seat
+ Seat_ptr seat,
+ XWayland_ptr xwayland
)
: View(
this,
@@ -30,6 +31,7 @@ XWaylandView::XWaylandView(
seat,
wlr_xwayland_surface->surface
),
+ mp_xwayland(xwayland),
mp_wlr_xwayland_surface(wlr_xwayland_surface),
ml_commit({ .notify = XWaylandView::handle_commit }),
ml_request_move({ .notify = XWaylandView::handle_request_move }),
@@ -274,8 +276,12 @@ XWaylandView::handle_override_redirect(struct wl_listener* listener, void* data)
}
-XWaylandUnmanaged::XWaylandUnmanaged(struct wlr_xwayland_surface* wlr_xwayland_surface)
- : mp_wlr_xwayland_surface(wlr_xwayland_surface)
+XWaylandUnmanaged::XWaylandUnmanaged(
+ struct wlr_xwayland_surface* wlr_xwayland_surface,
+ XWayland_ptr xwayland
+)
+ : mp_wlr_xwayland_surface(wlr_xwayland_surface),
+ mp_xwayland(xwayland)
{}
XWaylandUnmanaged::~XWaylandUnmanaged()
diff --git a/src/kranewl/xwayland.cc b/src/kranewl/xwayland.cc
@@ -0,0 +1,142 @@
+#include <trace.hh>
+
+#include <kranewl/input/seat.hh>
+#include <kranewl/server.hh>
+#include <kranewl/xwayland.hh>
+
+// https://github.com/swaywm/wlroots/issues/682
+#include <pthread.h>
+#define class class_
+#define namespace namespace_
+#define static
+extern "C" {
+#include <wlr/types/wlr_cursor.h>
+#include <wlr/types/wlr_xcursor_manager.h>
+#include <wlr/xwayland.h>
+#define Cursor Cursor_
+#include <X11/Xlib.h>
+#undef Cursor
+}
+#undef static
+#undef namespace
+#undef class
+
+#include <spdlog/spdlog.h>
+
+#include <cstdlib>
+
+XWayland::XWayland(struct wlr_xwayland* xwayland, Server_ptr server)
+ : mp_wlr_xwayland(xwayland),
+ mp_cursor_manager(wlr_xcursor_manager_create(nullptr, 24)),
+ m_atoms({}),
+ mp_server(server),
+ ml_ready({ .notify = XWayland::handle_ready }),
+ ml_new_surface({ .notify = XWayland::handle_new_surface })
+{
+ wlr_xcursor_manager_load(mp_cursor_manager, 1.f);
+
+ if (mp_wlr_xwayland) {
+ setenv("DISPLAY", mp_wlr_xwayland->display_name, 1);
+ wl_signal_add(&mp_wlr_xwayland->events.ready, &ml_ready);
+ wl_signal_add(&mp_wlr_xwayland->events.new_surface, &ml_new_surface);
+ } else {
+ spdlog::error("Failed to initiate XWayland");
+ spdlog::warn("Continuing without XWayland functionality");
+ }
+}
+
+XWayland::~XWayland()
+{}
+
+static inline constexpr std::array<char const*, XWayland::XATOM_LAST>
+constexpr_atom_names()
+{
+ std::array<char const*, XWayland::XATOM_LAST> atom_names_ = {};
+
+ atom_names_[XWayland::NET_WM_WINDOW_TYPE_NORMAL] = "_NET_WM_WINDOW_TYPE_NORMAL";
+ atom_names_[XWayland::NET_WM_WINDOW_TYPE_DIALOG] = "_NET_WM_WINDOW_TYPE_DIALOG";
+ atom_names_[XWayland::NET_WM_WINDOW_TYPE_UTILITY] = "_NET_WM_WINDOW_TYPE_UTILITY";
+ atom_names_[XWayland::NET_WM_WINDOW_TYPE_TOOLBAR] = "_NET_WM_WINDOW_TYPE_TOOLBAR";
+ atom_names_[XWayland::NET_WM_WINDOW_TYPE_SPLASH] = "_NET_WM_WINDOW_TYPE_SPLASH";
+ atom_names_[XWayland::NET_WM_WINDOW_TYPE_MENU] = "_NET_WM_WINDOW_TYPE_MENU";
+ atom_names_[XWayland::NET_WM_WINDOW_TYPE_DROPDOWN_MENU] = "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU";
+ atom_names_[XWayland::NET_WM_WINDOW_TYPE_POPUP_MENU] = "_NET_WM_WINDOW_TYPE_POPUP_MENU";
+ atom_names_[XWayland::NET_WM_WINDOW_TYPE_TOOLTIP] = "_NET_WM_WINDOW_TYPE_TOOLTIP";
+ atom_names_[XWayland::NET_WM_WINDOW_TYPE_NOTIFICATION] = "_NET_WM_WINDOW_TYPE_NOTIFICATION";
+ atom_names_[XWayland::NET_WM_STATE_MODAL] = "_NET_WM_STATE_MODAL";
+
+ return atom_names_;
+}
+
+void
+XWayland::handle_ready(struct wl_listener* listener, void*)
+{
+ TRACE();
+
+ static constexpr std::array<char const*, XATOM_LAST> atom_names = constexpr_atom_names();
+
+ XWayland_ptr xwayland = wl_container_of(listener, xwayland, ml_ready);
+ xcb_connection_t* xconn = xcb_connect(xwayland->mp_wlr_xwayland->display_name, nullptr);
+
+ int error = xcb_connection_has_error(xconn);
+ if (error) {
+ spdlog::error("Establishing connection with the X server failed with X11 error code {}", error);
+ spdlog::warn("Continuing without XWayland support");
+ return;
+ }
+
+ xcb_intern_atom_cookie_t atom_cookies[XATOM_LAST];
+ for (std::size_t i = 0; i < XATOM_LAST; ++i)
+ atom_cookies[i]
+ = xcb_intern_atom(xconn, 0, strlen(atom_names[i]), atom_names[i]);
+
+ for (std::size_t i = 0; i < XATOM_LAST; ++i) {
+ xcb_generic_error_t* error = NULL;
+ xcb_intern_atom_reply_t *reply
+ = xcb_intern_atom_reply(xconn, atom_cookies[i], &error);
+
+ if (reply && !error)
+ xwayland->m_atoms[i] = reply->atom;
+
+ free(reply);
+
+ if (error) {
+ spdlog::error(
+ "Interning atom {} failed with X11 error code {}",
+ atom_names[i],
+ error->error_code
+ );
+ spdlog::warn("Continuing with limited XWayland support");
+
+ free(error);
+ break;
+ }
+ }
+
+ wlr_xwayland_set_seat(
+ xwayland->mp_wlr_xwayland,
+ xwayland->mp_server->m_seat.mp_wlr_seat
+ );
+
+ struct wlr_xcursor* xcursor;
+ if ((xcursor = wlr_xcursor_manager_get_xcursor(xwayland->mp_cursor_manager, "left_ptr", 1)))
+ wlr_xwayland_set_cursor(
+ xwayland->mp_wlr_xwayland,
+ xcursor->images[0]->buffer,
+ xcursor->images[0]->width * 4,
+ xcursor->images[0]->width,
+ xcursor->images[0]->height,
+ xcursor->images[0]->hotspot_x,
+ xcursor->images[0]->hotspot_y
+ );
+
+ xcb_disconnect(xconn);
+ spdlog::info("Initiated underlying XWayland server");
+}
+
+void
+XWayland::handle_new_surface(struct wl_listener* listener, void* data)
+{
+ TRACE();
+
+}