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 e73b155aca6afe3d710bf3841a4804ece9ce5b10
parent 23eef476404d2a2b1456cb09bf45c37c8f8c2bf0
Author: deurzen <max@deurzen.net>
Date:   Sat, 28 May 2022 18:46:25 +0200

provides client cursor handoff

Diffstat:
Minclude/kranewl/input/mouse.hh | 84++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Minclude/kranewl/input/seat.hh | 46+++-------------------------------------------
Asrc/kranewl/input/mouse.cc | 256+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/kranewl/input/seat.cc | 147++++++++-----------------------------------------------------------------------
Msrc/kranewl/model.cc | 7++++---
Msrc/kranewl/server.cc | 10++++++----
6 files changed, 364 insertions(+), 186 deletions(-)

diff --git a/include/kranewl/input/mouse.hh b/include/kranewl/input/mouse.hh @@ -1,13 +1,91 @@ #pragma once +#include <kranewl/geometry.hh> + +extern "C" { +#include <wlr/backend.h> +#include <xkbcommon/xkbcommon.h> +} + #include <cstdint> #include <unordered_set> struct MouseInput { - uint32_t mod; unsigned button; + uint32_t modifiers; }; +typedef class Server* Server_ptr; +typedef class Seat* Seat_ptr; +typedef struct View* View_ptr; + +typedef struct Mouse { + enum class CursorMode { + Passthrough, + Move, + Resize, + }; + + enum class CursorButton { + Left = 272, + Right = 273, + Middle = 274, + }; + + Mouse( + Server_ptr, + Seat_ptr, + struct wlr_cursor*, + struct wlr_pointer_constraints_v1*, + struct wlr_relative_pointer_manager_v1*, + struct wlr_virtual_pointer_manager_v1* + ); + ~Mouse(); + + static void handle_cursor_motion(struct wl_listener*, void*); + static void handle_cursor_motion_absolute(struct wl_listener*, void*); + static void handle_cursor_button(struct wl_listener*, void*); + static void handle_cursor_axis(struct wl_listener*, void*); + static void handle_cursor_frame(struct wl_listener*, void*); + static void handle_request_start_drag(struct wl_listener*, void*); + static void handle_start_drag(struct wl_listener*, void*); + static void handle_request_set_cursor(struct wl_listener*, void*); + + Server_ptr mp_server; + Seat_ptr mp_seat; + + CursorMode m_cursor_mode; + struct wlr_cursor* mp_cursor; + struct wlr_xcursor_manager* mp_cursor_manager; + struct wlr_pointer_constraints_v1* mp_pointer_constraints; + struct wlr_relative_pointer_manager_v1* mp_relative_pointer_manager; + struct wlr_virtual_pointer_manager_v1* mp_virtual_pointer_manager; + + struct { + View_ptr client; + double x, y; + Region region; + uint32_t resize_edges; + } m_grab_state; + + struct wl_listener ml_cursor_motion; + struct wl_listener ml_cursor_motion_absolute; + struct wl_listener ml_cursor_button; + struct wl_listener ml_cursor_axis; + struct wl_listener ml_cursor_frame; + struct wl_listener ml_request_start_drag; + struct wl_listener ml_start_drag; + struct wl_listener ml_request_set_cursor; + +}* Mouse_ptr; + +inline bool +operator==(MouseInput const& lhs, MouseInput const& rhs) +{ + return lhs.button == rhs.button + && lhs.modifiers == rhs.modifiers; +} + namespace std { template <> @@ -15,10 +93,10 @@ namespace std std::size_t operator()(MouseInput const& input) const { - std::size_t mod_hash = std::hash<uint32_t>()(input.mod); + std::size_t modifiers_hash = std::hash<uint32_t>()(input.modifiers); std::size_t button_hash = std::hash<unsigned>()(input.button); - return mod_hash ^ button_hash; + return modifiers_hash ^ button_hash; } }; } diff --git a/include/kranewl/input/seat.hh b/include/kranewl/input/seat.hh @@ -12,23 +12,11 @@ extern "C" { typedef class Server* Server_ptr; typedef class Model* Model_ptr; -typedef class Keyboard* Keyboard_ptr; -typedef class Client* Client_ptr; +typedef struct Keyboard* Keyboard_ptr; +typedef struct Mouse* Mouse_ptr; typedef class Seat final { public: - enum class CursorMode { - Passthrough, - Move, - Resize, - }; - - enum class CursorButton { - Left = 272, - Right = 273, - Middle = 274, - }; - Seat( Server_ptr, Model_ptr, @@ -50,14 +38,6 @@ public: void unregister_keyboard(Keyboard_ptr); static void handle_destroy(struct wl_listener*, void*); - static void handle_cursor_motion(struct wl_listener*, void*); - static void handle_cursor_motion_absolute(struct wl_listener*, void*); - static void handle_cursor_button(struct wl_listener*, void*); - static void handle_cursor_axis(struct wl_listener*, void*); - static void handle_cursor_frame(struct wl_listener*, void*); - static void handle_request_start_drag(struct wl_listener*, void*); - static void handle_start_drag(struct wl_listener*, void*); - static void handle_request_set_cursor(struct wl_listener*, void*); static void handle_request_set_selection(struct wl_listener*, void*); static void handle_request_set_primary_selection(struct wl_listener*, void*); static void handle_inhibit_manager_new_inhibitor(struct wl_listener*, void*); @@ -70,37 +50,17 @@ public: struct wlr_seat* mp_wlr_seat; struct wlr_idle* mp_idle; - struct wlr_cursor* mp_cursor; - struct wlr_xcursor_manager* mp_cursor_manager; struct wlr_input_inhibit_manager* mp_input_inhibit_manager; struct wlr_idle_inhibit_manager_v1* mp_idle_inhibit_manager; - struct wlr_pointer_constraints_v1* mp_pointer_constraints; - struct wlr_relative_pointer_manager_v1* mp_relative_pointer_manager; - struct wlr_virtual_pointer_manager_v1* mp_virtual_pointer_manager; struct wlr_virtual_keyboard_manager_v1* mp_virtual_keyboard_manager; struct wlr_keyboard_shortcuts_inhibit_manager_v1* mp_keyboard_shortcuts_inhibit_manager; - CursorMode m_cursor_mode; + Mouse_ptr mp_mouse; std::vector<Keyboard_ptr> m_keyboards; - struct { - Client_ptr client; - double x, y; - Region region; - uint32_t resize_edges; - } m_grab_state; - struct wl_client* mp_exclusive_client; struct wl_listener ml_destroy; - struct wl_listener ml_cursor_motion; - struct wl_listener ml_cursor_motion_absolute; - struct wl_listener ml_cursor_button; - struct wl_listener ml_cursor_axis; - struct wl_listener ml_cursor_frame; - struct wl_listener ml_request_start_drag; - struct wl_listener ml_start_drag; - struct wl_listener ml_request_set_cursor; struct wl_listener ml_request_set_selection; struct wl_listener ml_request_set_primary_selection; struct wl_listener ml_inhibit_manager_new_inhibitor; diff --git a/src/kranewl/input/mouse.cc b/src/kranewl/input/mouse.cc @@ -0,0 +1,256 @@ +#include <trace.hh> + +#include <kranewl/input/mouse.hh> + +#include <kranewl/input/seat.hh> +#include <kranewl/layers.hh> +#include <kranewl/server.hh> +#include <kranewl/tree/view.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_data_device.h> +#include <wlr/types/wlr_scene.h> +#include <wlr/types/wlr_seat.h> +#include <wlr/types/wlr_xcursor_manager.h> +} +#undef static +#undef class +#undef namespace + +Mouse::Mouse( + Server_ptr server, + Seat_ptr seat, + struct wlr_cursor* cursor, + struct wlr_pointer_constraints_v1* pointer_constraints, + struct wlr_relative_pointer_manager_v1* relative_pointer_manager, + struct wlr_virtual_pointer_manager_v1* virtual_pointer_manager +) + : mp_server(server), + mp_seat(seat), + mp_cursor(cursor), + mp_cursor_manager(wlr_xcursor_manager_create(nullptr, 24)), + mp_pointer_constraints(pointer_constraints), + mp_relative_pointer_manager(relative_pointer_manager), + mp_virtual_pointer_manager(virtual_pointer_manager), + ml_cursor_motion({ .notify = Mouse::handle_cursor_motion }), + ml_cursor_motion_absolute({ .notify = Mouse::handle_cursor_motion_absolute }), + ml_cursor_button({ .notify = Mouse::handle_cursor_button }), + ml_cursor_axis({ .notify = Mouse::handle_cursor_axis }), + ml_cursor_frame({ .notify = Mouse::handle_cursor_frame }), + ml_request_start_drag({ .notify = Mouse::handle_request_start_drag }), + ml_start_drag({ .notify = Mouse::handle_start_drag }), + ml_request_set_cursor({ .notify = Mouse::handle_request_set_cursor }) +{ + TRACE(); + + wlr_xcursor_manager_load(mp_cursor_manager, 1); + + wl_signal_add(&cursor->events.motion, &ml_cursor_motion); + wl_signal_add(&cursor->events.motion_absolute, &ml_cursor_motion_absolute); + wl_signal_add(&cursor->events.button, &ml_cursor_button); + wl_signal_add(&cursor->events.axis, &ml_cursor_axis); + wl_signal_add(&cursor->events.frame, &ml_cursor_frame); + wl_signal_add(&mp_seat->mp_wlr_seat->events.request_start_drag, &ml_request_start_drag); + wl_signal_add(&mp_seat->mp_wlr_seat->events.start_drag, &ml_start_drag); + wl_signal_add(&mp_seat->mp_wlr_seat->events.request_set_cursor, &ml_request_set_cursor); +} + +Mouse::~Mouse() +{ + TRACE(); + +} + +static inline void +process_cursor_move(Mouse_ptr mouse, uint32_t time) +{ + TRACE(); + +} + +static inline void +process_cursor_resize(Mouse_ptr mouse, uint32_t time) +{ + TRACE(); + +} + +static inline View_ptr +view_at( + Server_ptr server, + double lx, double ly, + struct wlr_surface** surface, + double* sx, double* sy +) +{ + static std::vector<Layer::type> focus_order = { + Layer::Overlay, + Layer::Top, + Layer::Free, + Layer::Tile, + Layer::Bottom, + }; + + struct wlr_scene_node** layers = server->m_layers; + struct wlr_scene_node* node; + + for (auto const& layer : focus_order) { + if ((node = wlr_scene_node_at(layers[layer], lx, ly, sx, sy))) { + if (node->type != WLR_SCENE_NODE_SURFACE) + return nullptr; + + *surface = wlr_scene_surface_from_node(node)->surface; + + while (node && !node->data) + node = node->parent; + + return reinterpret_cast<View_ptr>(node->data); + } + } + + return nullptr; +} + +static inline void +cursor_set_focus( + Mouse_ptr mouse, + View_ptr view, + struct wlr_surface* surface, + double sx, double sy, + uint32_t time +) +{ + if (true /* TODO: focus_follows_mouse */ && time && view && view->managed()) + mouse->mp_seat->mp_model->focus_view(view); + + if (!surface) { + wlr_seat_pointer_notify_clear_focus(mouse->mp_seat->mp_wlr_seat); + return; + } + + if (!time) { + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + time = now.tv_sec * 1000 + now.tv_nsec / 1000000; + } + + wlr_seat_pointer_notify_enter(mouse->mp_seat->mp_wlr_seat, surface, sx, sy); + wlr_seat_pointer_notify_motion(mouse->mp_seat->mp_wlr_seat, time, sx, sy); +} + +static inline void +process_cursor_motion(Mouse_ptr mouse, uint32_t time) +{ + TRACE(); + + struct wlr_drag_icon* icon; + if (mouse->mp_seat->mp_wlr_seat->drag && (icon = mouse->mp_seat->mp_wlr_seat->drag->icon)) + wlr_scene_node_set_position( + reinterpret_cast<struct wlr_scene_node*>(icon->data), + mouse->mp_cursor->x + icon->surface->sx, + mouse->mp_cursor->y + icon->surface->sy + ); + + switch (mouse->m_cursor_mode) { + case Mouse::CursorMode::Move: process_cursor_move(mouse, time); return; + case Mouse::CursorMode::Resize: process_cursor_resize(mouse, time); return; + case Mouse::CursorMode::Passthrough: // fallthrough + default: break; + } + + double sx, sy; + struct wlr_surface* surface = nullptr; + View_ptr view = view_at( + mouse->mp_server, + mouse->mp_cursor->x, + mouse->mp_cursor->y, + &surface, + &sx, &sy + ); + + if (!view && time) { + wlr_xcursor_manager_set_cursor_image( + mouse->mp_cursor_manager, + "left_ptr", + mouse->mp_cursor + ); + } + + cursor_set_focus(mouse, view, surface, sx, sy, time); +} + +void +Mouse::handle_cursor_motion(struct wl_listener* listener, void* data) +{ + TRACE(); + + Mouse_ptr mouse = wl_container_of(listener, mouse, ml_cursor_motion); + struct wlr_event_pointer_motion* event + = reinterpret_cast<struct wlr_event_pointer_motion*>(data); + + wlr_cursor_move(mouse->mp_cursor, event->device, event->delta_x, event->delta_y); + process_cursor_motion(mouse, event->time_msec); +} + +void +Mouse::handle_cursor_motion_absolute(struct wl_listener* listener, void* data) +{ + TRACE(); + + Mouse_ptr mouse = wl_container_of(listener, mouse, ml_cursor_motion_absolute); + struct wlr_event_pointer_motion_absolute* event + = reinterpret_cast<struct wlr_event_pointer_motion_absolute*>(data); + + wlr_cursor_warp_absolute(mouse->mp_cursor, event->device, event->x, event->y); + process_cursor_motion(mouse, event->time_msec); +} + +void +Mouse::handle_cursor_button(struct wl_listener* listener, void* data) +{ + TRACE(); + +} + +void +Mouse::handle_cursor_axis(struct wl_listener*, void*) +{ + TRACE(); + +} + +void +Mouse::handle_cursor_frame(struct wl_listener* listener, void*) +{ + TRACE(); + + Mouse_ptr mouse = wl_container_of(listener, mouse, ml_cursor_frame); + wlr_seat_pointer_notify_frame(mouse->mp_seat->mp_wlr_seat); +} + +void +Mouse::handle_request_start_drag(struct wl_listener*, void*) +{ + TRACE(); + +} + +void +Mouse::handle_start_drag(struct wl_listener*, void*) +{ + TRACE(); + +} + +void +Mouse::handle_request_set_cursor(struct wl_listener*, void*) +{ + TRACE(); + +} diff --git a/src/kranewl/input/seat.cc b/src/kranewl/input/seat.cc @@ -1,6 +1,7 @@ #include <trace.hh> #include <kranewl/input/keyboard.hh> +#include <kranewl/input/mouse.hh> #include <kranewl/input/seat.hh> #include <kranewl/util.hh> @@ -30,24 +31,20 @@ Seat::Seat( mp_model(model), mp_wlr_seat(seat), mp_idle(idle), - mp_cursor(cursor), - mp_cursor_manager(wlr_xcursor_manager_create(nullptr, 24)), mp_input_inhibit_manager(input_inhibit_manager), mp_idle_inhibit_manager(idle_inhibit_manager), - mp_pointer_constraints(pointer_constraints), - mp_relative_pointer_manager(relative_pointer_manager), - mp_virtual_pointer_manager(virtual_pointer_manager), mp_virtual_keyboard_manager(virtual_keyboard_manager), mp_keyboard_shortcuts_inhibit_manager(keyboard_shortcuts_inhibit_manager), + mp_mouse(new Mouse( + server, + this, + cursor, + pointer_constraints, + relative_pointer_manager, + virtual_pointer_manager + )), + m_keyboards(), ml_destroy({ .notify = Seat::handle_destroy }), - ml_cursor_motion({ .notify = Seat::handle_cursor_motion }), - ml_cursor_motion_absolute({ .notify = Seat::handle_cursor_motion_absolute }), - ml_cursor_button({ .notify = Seat::handle_cursor_button }), - ml_cursor_axis({ .notify = Seat::handle_cursor_axis }), - ml_cursor_frame({ .notify = Seat::handle_cursor_frame }), - ml_request_start_drag({ .notify = Seat::handle_request_start_drag }), - ml_start_drag({ .notify = Seat::handle_start_drag }), - ml_request_set_cursor({ .notify = Seat::handle_request_set_cursor }), ml_request_set_selection({ .notify = Seat::handle_request_set_selection }), ml_request_set_primary_selection({ .notify = Seat::handle_request_set_primary_selection }), ml_inhibit_manager_new_inhibitor({ .notify = Seat::handle_inhibit_manager_new_inhibitor }), @@ -56,17 +53,7 @@ Seat::Seat( { TRACE(); - wlr_xcursor_manager_load(mp_cursor_manager, 1); - wl_signal_add(&seat->events.destroy, &ml_destroy); - wl_signal_add(&cursor->events.motion, &ml_cursor_motion); - wl_signal_add(&cursor->events.motion_absolute, &ml_cursor_motion_absolute); - wl_signal_add(&cursor->events.button, &ml_cursor_button); - wl_signal_add(&cursor->events.axis, &ml_cursor_axis); - wl_signal_add(&cursor->events.frame, &ml_cursor_frame); - wl_signal_add(&seat->events.request_start_drag, &ml_request_start_drag); - wl_signal_add(&seat->events.start_drag, &ml_start_drag); - wl_signal_add(&seat->events.request_set_cursor, &ml_request_set_cursor); wl_signal_add(&seat->events.request_set_selection, &ml_request_set_selection); wl_signal_add(&seat->events.request_set_primary_selection, &ml_request_set_primary_selection); wl_signal_add(&mp_idle_inhibit_manager->events.new_inhibitor, &ml_inhibit_manager_new_inhibitor); @@ -78,47 +65,11 @@ Seat::~Seat() { TRACE(); -} - -static inline void -process_cursor_move(Seat_ptr seat, uint32_t time) -{ - -} - -static inline void -process_cursor_resize(Seat_ptr seat, uint32_t time) -{ - -} + delete mp_mouse; + for (Keyboard_ptr keyboard : m_keyboards) + delete keyboard; -static inline void -process_cursor_motion(Seat_ptr seat, uint32_t time) -{ - switch (seat->m_cursor_mode) { - case Seat::CursorMode::Move: process_cursor_move(seat, time); return; - case Seat::CursorMode::Resize: process_cursor_resize(seat, time); return; - case Seat::CursorMode::Passthrough: // fallthrough - default: break; - } - - double sx, sy; - struct wlr_surface* surface = nullptr; - // TODO: get client under cursor - - if (true /* no client under cursor? */) { - wlr_xcursor_manager_set_cursor_image( - seat->mp_cursor_manager, - "left_ptr", - seat->mp_cursor - ); - } - - if (surface) { - wlr_seat_pointer_notify_enter(seat->mp_wlr_seat, surface, sx, sy); - wlr_seat_pointer_notify_motion(seat->mp_wlr_seat, time, sx, sy); - } else - wlr_seat_pointer_clear_focus(seat->mp_wlr_seat); + m_keyboards.clear(); } Keyboard_ptr @@ -149,76 +100,6 @@ Seat::handle_destroy(struct wl_listener*, void*) } void -Seat::handle_cursor_motion(struct wl_listener* listener, void* data) -{ - TRACE(); - - Seat_ptr seat = wl_container_of(listener, seat, ml_cursor_motion); - struct wlr_event_pointer_motion* event - = reinterpret_cast<struct wlr_event_pointer_motion*>(data); - - wlr_cursor_move(seat->mp_cursor, event->device, event->delta_x, event->delta_y); - process_cursor_motion(seat, event->time_msec); -} - -void -Seat::handle_cursor_motion_absolute(struct wl_listener* listener, void* data) -{ - TRACE(); - - Seat_ptr seat = wl_container_of(listener, seat, ml_cursor_motion_absolute); - struct wlr_event_pointer_motion_absolute* event - = reinterpret_cast<struct wlr_event_pointer_motion_absolute*>(data); - - wlr_cursor_warp_absolute(seat->mp_cursor, event->device, event->x, event->y); - process_cursor_motion(seat, event->time_msec); -} - -void -Seat::handle_cursor_button(struct wl_listener*, void*) -{ - TRACE(); - -} - -void -Seat::handle_cursor_axis(struct wl_listener*, void*) -{ - TRACE(); - -} - -void -Seat::handle_cursor_frame(struct wl_listener* listener, void*) -{ - TRACE(); - - Seat_ptr seat = wl_container_of(listener, seat, ml_cursor_frame); - wlr_seat_pointer_notify_frame(seat->mp_wlr_seat); -} - -void -Seat::handle_request_start_drag(struct wl_listener*, void*) -{ - TRACE(); - -} - -void -Seat::handle_start_drag(struct wl_listener*, void*) -{ - TRACE(); - -} - -void -Seat::handle_request_set_cursor(struct wl_listener*, void*) -{ - TRACE(); - -} - -void Seat::handle_request_set_selection(struct wl_listener*, void*) { TRACE(); diff --git a/src/kranewl/model.cc b/src/kranewl/model.cc @@ -224,7 +224,7 @@ Model::focus_view(View_ptr view) Output_ptr output = view->mp_context->output(); - if (!output) + if (!output || mp_focus == view) return; if (!view->sticky()) { @@ -232,9 +232,10 @@ Model::focus_view(View_ptr view) mp_workspace->activate_view(view); } - if (mp_focus && mp_focus != view) - unfocus_view(mp_focus); + if (mp_focus) + mp_focus->focus(Toggle::Off); + view->focus(Toggle::On); view->set_urgent(false); mp_focus = view; diff --git a/src/kranewl/server.cc b/src/kranewl/server.cc @@ -15,15 +15,14 @@ #include <spdlog/spdlog.h> -#include <wayland-server-core.h> -#include <wayland-util.h> - // https://github.com/swaywm/wlroots/issues/682 #include <pthread.h> #define class class_ #define namespace namespace_ #define static extern "C" { +#include <wayland-server-core.h> +#include <wayland-util.h> #include <wlr/backend.h> #include <wlr/backend/multi.h> #include <wlr/render/allocator.h> @@ -454,7 +453,10 @@ Server::handle_new_input(struct wl_listener* listener, void* data) } case WLR_INPUT_DEVICE_POINTER: { - wlr_cursor_attach_input_device(server->m_seat.mp_cursor, device); + wlr_cursor_attach_input_device( + server->m_seat.mp_mouse->mp_cursor, + device + ); break; } default: break;