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 fd7b531812ae33edf1ff4c102040a1d15d536280
parent b610179a4d714cfefb7af519dc8be3349f80954e
Author: deurzen <max@deurzen.net>
Date:   Tue, 31 May 2022 12:20:43 +0200

implements x11 client event handling

Diffstat:
Minclude/kranewl/model.hh | 2++
Minclude/kranewl/tree/xwayland-view.hh | 14++++++++++++++
Msrc/kranewl/model.cc | 13+++++++++++++
Msrc/kranewl/tree/xwayland-view.cc | 266+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
Msrc/kranewl/xwayland.cc | 17++++++++++++-----
5 files changed, 273 insertions(+), 39 deletions(-)

diff --git a/include/kranewl/model.hh b/include/kranewl/model.hh @@ -66,6 +66,8 @@ public: Seat_ptr, XWayland_ptr ); + + void destroy_unmanaged(XWaylandUnmanaged_ptr); #endif void register_view(View_ptr, Workspace_ptr); void unregister_view(View_ptr); diff --git a/include/kranewl/tree/xwayland-view.hh b/include/kranewl/tree/xwayland-view.hh @@ -91,6 +91,8 @@ typedef struct XWaylandUnmanaged final : public Node { void format_uid() override; + pid_t pid(); + static void handle_map(struct wl_listener*, void*); static void handle_unmap(struct wl_listener*, void*); static void handle_commit(struct wl_listener*, void*); @@ -111,8 +113,20 @@ typedef struct XWaylandUnmanaged final : public Node { Region m_region; + std::string m_title; + std::string m_title_formatted; + std::string m_app_id; + std::string m_class; + std::string m_instance; + struct wlr_xwayland_surface* mp_wlr_xwayland_surface; + struct wlr_surface* mp_wlr_surface; + struct wlr_scene_node* mp_scene; + struct wlr_scene_node* mp_scene_surface; + + pid_t m_pid; + struct wl_listener ml_map; struct wl_listener ml_unmap; struct wl_listener ml_commit; diff --git a/src/kranewl/model.cc b/src/kranewl/model.cc @@ -280,6 +280,7 @@ Model::refocus() mp_workspace->activate_view(mp_focus); } + mp_focus->focus(Toggle::Off); mp_focus->focus(Toggle::On); mp_focus->set_urgent(false); @@ -1861,9 +1862,21 @@ Model::create_xwayland_unmanaged( ); m_unmanaged_map[node->uid()] = node; + spdlog::info("Created unmanaged X client {}", node->uid_formatted()); return node; } + +void +Model::destroy_unmanaged(XWaylandUnmanaged_ptr unmanaged) +{ + TRACE(); + + m_unmanaged_map.erase(unmanaged->uid()); + spdlog::info("Destroyed unmanaged X client {}", unmanaged->uid_formatted()); + + delete unmanaged; +} #endif void diff --git a/src/kranewl/tree/xwayland-view.cc b/src/kranewl/tree/xwayland-view.cc @@ -45,7 +45,6 @@ XWaylandView::XWaylandView( mp_wlr_xwayland_surface(wlr_xwayland_surface), ml_map({ .notify = XWaylandView::handle_map }), ml_unmap({ .notify = XWaylandView::handle_unmap }), - ml_commit({ .notify = XWaylandView::handle_commit }), ml_request_activate({ .notify = XWaylandView::handle_request_activate }), ml_request_configure({ .notify = XWaylandView::handle_request_configure }), ml_request_fullscreen({ .notify = XWaylandView::handle_request_fullscreen }), @@ -91,18 +90,18 @@ XWaylandView::format_uid() m_uid_formatted = uid_ss.str(); } -Region -XWaylandView::constraints() +pid_t +XWaylandView::pid() { TRACE(); - + return mp_wlr_xwayland_surface->pid; } -pid_t -XWaylandView::pid() +Region +XWaylandView::constraints() { TRACE(); - return mp_wlr_xwayland_surface->pid; + } bool @@ -210,7 +209,7 @@ XWaylandView::activate(Toggle toggle) ); wlr_xwayland_surface_activate(mp_wlr_xwayland_surface, true); - wlr_xwayland_surface_restack( + wlr_xwayland_surface_restack( mp_wlr_xwayland_surface, nullptr, XCB_STACK_MODE_ABOVE @@ -365,8 +364,6 @@ XWaylandView::handle_map(struct wl_listener* listener, void* data) wlr_scene_node_lower_to_bottom(&view->m_protrusions[i]->node); } - wl_signal_add(&xwayland_surface->surface->events.commit, &view->ml_commit); - Workspace_ptr workspace = model->mp_workspace; view->set_mapped(true); @@ -381,8 +378,6 @@ XWaylandView::handle_unmap(struct wl_listener* listener, void*) XWaylandView_ptr view = wl_container_of(listener, view, ml_unmap); - wl_list_remove(&view->ml_commit.link); - view->activate(Toggle::Off); view->mp_model->unregister_view(view); @@ -395,13 +390,6 @@ XWaylandView::handle_unmap(struct wl_listener* listener, void*) } void -XWaylandView::handle_commit(struct wl_listener*, void*) -{ - TRACE(); - -} - -void XWaylandView::handle_request_activate(struct wl_listener* listener, void*) { TRACE(); @@ -534,9 +522,9 @@ XWaylandView::handle_set_override_redirect(struct wl_listener* listener, void* d = reinterpret_cast<struct wlr_xwayland_surface*>(data); if (xwayland_surface->mapped) - handle_unmap(&view->ml_unmap, nullptr); + XWaylandView::handle_unmap(&view->ml_unmap, nullptr); - handle_destroy(&view->ml_destroy, view); + XWaylandView::handle_destroy(&view->ml_destroy, view); xwayland_surface->data = nullptr; XWaylandUnmanaged_ptr unmanaged = view->mp_model->create_xwayland_unmanaged( @@ -635,9 +623,10 @@ XWaylandUnmanaged::XWaylandUnmanaged( mp_output(nullptr), mp_xwayland(xwayland), m_region({}), + mp_wlr_surface(wlr_xwayland_surface->surface), + m_pid(0), ml_map({ .notify = handle_map }), ml_unmap({ .notify = handle_unmap }), - ml_commit({ .notify = handle_commit }), ml_set_override_redirect({ .notify = handle_set_override_redirect }), ml_set_geometry({ .notify = handle_set_geometry }), ml_request_activate({ .notify = handle_request_activate }), @@ -648,7 +637,6 @@ XWaylandUnmanaged::XWaylandUnmanaged( wl_signal_add(&mp_wlr_xwayland_surface->events.map, &ml_map); wl_signal_add(&mp_wlr_xwayland_surface->events.unmap, &ml_unmap); wl_signal_add(&mp_wlr_xwayland_surface->events.set_override_redirect, &ml_set_override_redirect); - wl_signal_add(&mp_wlr_xwayland_surface->events.set_geometry, &ml_set_geometry); wl_signal_add(&mp_wlr_xwayland_surface->events.request_activate, &ml_request_activate); wl_signal_add(&mp_wlr_xwayland_surface->events.request_configure, &ml_request_configure); wl_signal_add(&mp_wlr_xwayland_surface->events.request_fullscreen, &ml_request_fullscreen); @@ -663,70 +651,280 @@ XWaylandUnmanaged::format_uid() { std::stringstream uid_ss; uid_ss << "0x" << std::hex << uid() << std::dec; + uid_ss << " [" << m_pid << "]"; uid_ss << " (XU)"; m_uid_formatted = uid_ss.str(); } -void -XWaylandUnmanaged::handle_map(struct wl_listener*, void*) +pid_t +XWaylandUnmanaged::pid() { TRACE(); - + return mp_wlr_xwayland_surface->pid; } void -XWaylandUnmanaged::handle_unmap(struct wl_listener*, void*) +XWaylandUnmanaged::handle_map(struct wl_listener* listener, void* data) { TRACE(); + XWaylandUnmanaged_ptr unmanaged = wl_container_of(listener, unmanaged, ml_map); + Server_ptr server = unmanaged->mp_server; + Model_ptr model = unmanaged->mp_model; + + unmanaged->m_pid = unmanaged->pid(); + unmanaged->format_uid(); + + struct wlr_xwayland_surface* xwayland_surface + = reinterpret_cast<struct wlr_xwayland_surface*>(data); + unmanaged->mp_wlr_surface = xwayland_surface->surface; + + unmanaged->m_region = Region{ + .pos = Pos{ + .x = xwayland_surface->x, + .y = xwayland_surface->y, + }, + .dim = Dim{ + .w = xwayland_surface->width, + .h = xwayland_surface->height, + } + }; + + unmanaged->m_app_id = unmanaged->m_class = xwayland_surface->class_ + ? xwayland_surface->class_ + : "N/a"; + unmanaged->m_instance = xwayland_surface->instance + ? xwayland_surface->instance + : "N/a"; + unmanaged->m_title = xwayland_surface->title + ? xwayland_surface->title + : "N/a"; + unmanaged->m_title_formatted = unmanaged->m_title; // TODO: format title + + unmanaged->mp_scene = &wlr_scene_tree_create( + server->m_scene_layers[SCENE_LAYER_TILE] + )->node; + + unmanaged->mp_wlr_surface->data = unmanaged->mp_scene_surface = wlr_scene_subsurface_tree_create( + unmanaged->mp_scene, + unmanaged->mp_wlr_surface + ); + unmanaged->mp_scene_surface->data = unmanaged; + + wlr_scene_node_reparent( + unmanaged->mp_scene, + unmanaged->mp_server->m_scene_layers[SCENE_LAYER_FREE] + ); + + wlr_scene_node_set_position( + unmanaged->mp_scene, + unmanaged->m_region.pos.x, + unmanaged->m_region.pos.y + ); + + wl_signal_add(&xwayland_surface->events.set_geometry, &unmanaged->ml_set_geometry); + + struct wlr_seat* wlr_seat = unmanaged->mp_seat->mp_wlr_seat; + + if (wlr_xwayland_or_surface_wants_focus(xwayland_surface)) { + wlr_xwayland_set_seat(unmanaged->mp_xwayland->mp_wlr_xwayland, wlr_seat); + + struct wlr_keyboard* keyboard = wlr_seat_get_keyboard(wlr_seat); + if (!keyboard) { + wlr_seat_keyboard_notify_enter( + wlr_seat, + xwayland_surface->surface, + nullptr, + 0, + nullptr + ); + + return; + } + + wlr_seat_keyboard_notify_enter( + wlr_seat, + xwayland_surface->surface, + keyboard->keycodes, + keyboard->num_keycodes, + &keyboard->modifiers + ); + } } void -XWaylandUnmanaged::handle_commit(struct wl_listener*, void*) +XWaylandUnmanaged::handle_unmap(struct wl_listener* listener, void*) { TRACE(); + XWaylandUnmanaged_ptr unmanaged = wl_container_of(listener, unmanaged, ml_unmap); + struct wlr_xwayland_surface* xwayland_surface = unmanaged->mp_wlr_xwayland_surface; + struct wlr_seat* wlr_seat = unmanaged->mp_seat->mp_wlr_seat; + + wl_list_remove(&unmanaged->ml_set_geometry.link); + + if (wlr_seat->keyboard_state.focused_surface == xwayland_surface->surface) { + if (xwayland_surface->parent && xwayland_surface->parent->surface + && wlr_xwayland_or_surface_wants_focus(xwayland_surface->parent)) + { + struct wlr_keyboard* keyboard = wlr_seat_get_keyboard(wlr_seat); + if (!keyboard) { + wlr_seat_keyboard_notify_enter( + wlr_seat, + xwayland_surface->parent->surface, + nullptr, + 0, + nullptr + ); + + return; + } + + wlr_seat_keyboard_notify_enter( + wlr_seat, + xwayland_surface->parent->surface, + keyboard->keycodes, + keyboard->num_keycodes, + &keyboard->modifiers + ); + + return; + } + + unmanaged->mp_model->refocus(); + } } void -XWaylandUnmanaged::handle_set_override_redirect(struct wl_listener*, void*) +XWaylandUnmanaged::handle_set_override_redirect(struct wl_listener* listener, void* data) { TRACE(); + XWaylandUnmanaged_ptr unmanaged = wl_container_of(listener, unmanaged, ml_set_override_redirect); + struct wlr_xwayland_surface* xwayland_surface + = reinterpret_cast<struct wlr_xwayland_surface*>(data); + + if (xwayland_surface->mapped) + XWaylandUnmanaged::handle_unmap(&unmanaged->ml_unmap, nullptr); + + XWaylandUnmanaged::handle_destroy(&unmanaged->ml_destroy, unmanaged); + xwayland_surface->data = nullptr; + + XWaylandView_ptr view = unmanaged->mp_model->create_xwayland_view( + xwayland_surface, + unmanaged->mp_seat, + unmanaged->mp_xwayland + ); + + if (xwayland_surface->mapped) + XWaylandView::handle_map(&view->ml_map, xwayland_surface); } void -XWaylandUnmanaged::handle_set_geometry(struct wl_listener*, void*) +XWaylandUnmanaged::handle_set_geometry(struct wl_listener* listener, void*) { TRACE(); + XWaylandUnmanaged_ptr unmanaged = wl_container_of(listener, unmanaged, ml_set_geometry); + struct wlr_xwayland_surface* xwayland_surface = unmanaged->mp_wlr_xwayland_surface; + + Pos new_pos = Pos{ + .x = xwayland_surface->x, + .y = xwayland_surface->y, + }; + + + if (unmanaged->m_region.pos != new_pos) + { + unmanaged->m_region.pos = new_pos; + wlr_scene_node_set_position( + unmanaged->mp_scene, + unmanaged->m_region.pos.x, + unmanaged->m_region.pos.y + ); + } } void -XWaylandUnmanaged::handle_request_activate(struct wl_listener*, void*) +XWaylandUnmanaged::handle_request_activate(struct wl_listener* listener, void* data) { TRACE(); + XWaylandUnmanaged_ptr unmanaged = wl_container_of(listener, unmanaged, ml_request_activate); + struct wlr_xwayland_surface* xwayland_surface + = reinterpret_cast<struct wlr_xwayland_surface*>(data); + + if (!xwayland_surface->mapped) + return; + + struct wlr_seat* wlr_seat = unmanaged->mp_seat->mp_wlr_seat; + + if (wlr_xwayland_or_surface_wants_focus(xwayland_surface)) { + wlr_xwayland_set_seat(unmanaged->mp_xwayland->mp_wlr_xwayland, wlr_seat); + + struct wlr_keyboard* keyboard = wlr_seat_get_keyboard(wlr_seat); + if (!keyboard) { + wlr_seat_keyboard_notify_enter( + wlr_seat, + xwayland_surface->surface, + nullptr, + 0, + nullptr + ); + + return; + } + + wlr_seat_keyboard_notify_enter( + wlr_seat, + xwayland_surface->surface, + keyboard->keycodes, + keyboard->num_keycodes, + &keyboard->modifiers + ); + } } void -XWaylandUnmanaged::handle_request_configure(struct wl_listener*, void*) +XWaylandUnmanaged::handle_request_configure(struct wl_listener* listener, void* data) { TRACE(); + XWaylandUnmanaged_ptr unmanaged = wl_container_of(listener, unmanaged, ml_request_configure); + struct wlr_xwayland_surface_configure_event* event + = reinterpret_cast<struct wlr_xwayland_surface_configure_event*>(data); + + wlr_xwayland_surface_configure( + unmanaged->mp_wlr_xwayland_surface, + event->x, + event->y, + event->width, + event->height + ); } void XWaylandUnmanaged::handle_request_fullscreen(struct wl_listener*, void*) { TRACE(); - + // TODO } void -XWaylandUnmanaged::handle_destroy(struct wl_listener*, void*) +XWaylandUnmanaged::handle_destroy(struct wl_listener* listener, void*) { TRACE(); + XWaylandUnmanaged_ptr unmanaged = wl_container_of(listener, unmanaged, ml_destroy); + + wl_list_remove(&unmanaged->ml_map.link); + wl_list_remove(&unmanaged->ml_unmap.link); + wl_list_remove(&unmanaged->ml_set_override_redirect.link); + wl_list_remove(&unmanaged->ml_request_activate.link); + wl_list_remove(&unmanaged->ml_request_configure.link); + wl_list_remove(&unmanaged->ml_request_fullscreen.link); + wl_list_remove(&unmanaged->ml_destroy.link); + + unmanaged->mp_model->destroy_unmanaged(unmanaged); } #endif diff --git a/src/kranewl/xwayland.cc b/src/kranewl/xwayland.cc @@ -152,9 +152,16 @@ XWayland::handle_new_surface(struct wl_listener* listener, void* data) struct wlr_xwayland_surface* xwayland_surface = reinterpret_cast<struct wlr_xwayland_surface*>(data); - XWaylandView_ptr xwayland_view = xwayland->mp_model->create_xwayland_view( - xwayland_surface, - xwayland->mp_seat, - xwayland - ); + if (xwayland_surface->override_redirect) + xwayland->mp_model->create_xwayland_unmanaged( + xwayland_surface, + xwayland->mp_seat, + xwayland + ); + else + xwayland->mp_model->create_xwayland_view( + xwayland_surface, + xwayland->mp_seat, + xwayland + ); }