kranewl

A wlroots-based dynamic Wayland compositor, written in C++, configurable with Lua
git clone git://git.deurzen.net/kranewl
Log | Files | Refs | LICENSE

commit c9bd0ea004f240e3e4babcfd3686e897e73db3ef
parent 99c5c6058b30e11dbdfd313190a75835a9186e29
Author: deurzen <max@deurzen.net>
Date:   Mon, 30 May 2022 20:52:45 +0200

provides xwayland subsystem establishment

Diffstat:
Minclude/kranewl/model.hh | 3++-
Minclude/kranewl/server.hh | 11+++--------
Minclude/kranewl/tree/xwayland_view.hh | 12+++++++++---
Ainclude/kranewl/xwayland.hh | 48++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/kranewl/input/cursor.cc | 2+-
Msrc/kranewl/model.cc | 6++++--
Msrc/kranewl/server.cc | 58++++------------------------------------------------------
Msrc/kranewl/tree/xwayland_view.cc | 12+++++++++---
Asrc/kranewl/xwayland.cc | 142+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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(); + +}