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 0ffbb14925dd93a4e977141311e9d233e7958468
parent bc69f6b67c67d48358266f754d823cb48e460528
Author: deurzen <m.deurzen@tum.de>
Date:   Wed, 18 May 2022 12:14:38 +0200

adds initial event handling framework

Diffstat:
Minclude/kranewl/server.hh | 5++++-
Minclude/version.hh | 4++--
Msrc/kranewl/server.cc | 306++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
3 files changed, 294 insertions(+), 21 deletions(-)

diff --git a/include/kranewl/server.hh b/include/kranewl/server.hh @@ -3,6 +3,7 @@ extern "C" { #include <wlr/backend.h> #include <wlr/util/box.h> +#include <xkbcommon/xkbcommon.h> } #include <cstdint> @@ -41,6 +42,7 @@ private: static void keyboard_handle_modifiers(struct wl_listener*, void*); static void keyboard_handle_key(struct wl_listener*, void*); + static bool keyboard_handle_keybinding(Server*, xkb_keysym_t); static void seat_request_cursor(struct wl_listener*, void*); static void seat_request_set_selection(struct wl_listener*, void*); @@ -54,6 +56,7 @@ private: static void xdg_toplevel_destroy(struct wl_listener*, void*); static void xdg_toplevel_request_move(struct wl_listener*, void*); static void xdg_toplevel_request_resize(struct wl_listener*, void*); + static void xdg_toplevel_handle_moveresize(View*, CursorMode, uint32_t); struct wl_display* m_display; struct wlr_backend* m_backend; @@ -79,7 +82,7 @@ private: struct wl_listener m_request_set_selection; struct wl_list m_keyboards; CursorMode m_cursor_mode; - struct tinywl_view* m_grabbed_view; + View* m_grabbed_view; double m_grab_x, m_grab_y; struct wlr_box m_grab_geobox; uint32_t m_resize_edges; diff --git a/include/version.hh b/include/version.hh @@ -1 +1 @@ -#define VERSION "master/dfeb751+" -\ No newline at end of file +#define VERSION "master/bc69f6b+" +\ No newline at end of file diff --git a/src/kranewl/server.cc b/src/kranewl/server.cc @@ -82,7 +82,7 @@ Server::Server() m_cursor_mgr = wlr_xcursor_manager_create(NULL, 24); wlr_xcursor_manager_load(m_cursor_mgr, 1); - { // sets up cursor signals + { // set up cursor signals m_cursor_motion.notify = Server::cursor_motion; wl_signal_add(&m_cursor->events.motion, &m_cursor_motion); m_cursor_motion_absolute.notify = Server::cursor_motion_absolute; @@ -95,7 +95,7 @@ Server::Server() wl_signal_add(&m_cursor->events.frame, &m_cursor_frame); } - { // sets up keyboard signals + { // set up keyboard signals wl_list_init(&m_keyboards); m_new_input.notify = Server::new_input; wl_signal_add(&m_backend->events.new_input, &m_new_input); @@ -139,6 +139,7 @@ void Server::new_output(struct wl_listener* listener, void* data) { Server* server = wl_container_of(listener, server, m_new_output); + struct wlr_output* wlr_output = reinterpret_cast<struct wlr_output*>(data); wlr_output_init_render(wlr_output, server->m_allocator, server->m_renderer); @@ -166,6 +167,7 @@ void Server::new_xdg_surface(struct wl_listener* listener, void* data) { Server* server = wl_container_of(listener, server, m_new_xdg_surface); + struct wlr_xdg_surface* xdg_surface = reinterpret_cast<struct wlr_xdg_surface*>(data); if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { @@ -288,6 +290,7 @@ void Server::cursor_button(struct wl_listener* listener, void* data) { Server* server = wl_container_of(listener, server, m_cursor_button); + struct wlr_event_pointer_button* event = reinterpret_cast<wlr_event_pointer_button*>(data); @@ -298,9 +301,9 @@ Server::cursor_button(struct wl_listener* listener, void* data) event->state ); - double sx, sy; struct wlr_surface* surface = NULL; + double sx, sy; View* view = desktop_view_at( server, server->m_cursor->x, @@ -320,7 +323,9 @@ void Server::cursor_axis(struct wl_listener* listener, void* data) { Server* server = wl_container_of(listener, server, m_cursor_axis); - struct wlr_event_pointer_axis* event = reinterpret_cast<wlr_event_pointer_axis*>(data); + + struct wlr_event_pointer_axis* event + = reinterpret_cast<wlr_event_pointer_axis*>(data); wlr_seat_pointer_notify_axis( server->m_seat, @@ -336,6 +341,7 @@ void Server::cursor_frame(struct wl_listener* listener, void* data) { Server* server = wl_container_of(listener, server, m_cursor_frame); + wlr_seat_pointer_notify_frame(server->m_seat); } @@ -345,12 +351,13 @@ Server::cursor_process_motion(Server* server, uint32_t time) switch (server->m_cursor_mode) { case Server::CursorMode::Move: cursor_process_move(server, time); return; case Server::CursorMode::Resize: cursor_process_resize(server, time); return; - default: return; + default: break; } - double sx, sy; struct wlr_seat* seat = server->m_seat; struct wlr_surface* surface = NULL; + + double sx, sy; View* view = desktop_view_at( server, server->m_cursor->x, @@ -376,31 +383,179 @@ Server::cursor_process_motion(Server* server, uint32_t time) void Server::cursor_process_move(Server* server, uint32_t time) -{} +{ + View* view = server->m_grabbed_view; + + view->x = server->m_cursor->x - server->m_grab_x; + view->y = server->m_cursor->y - server->m_grab_y; + + wlr_scene_node_set_position(view->scene_node, view->x, view->y); +} void Server::cursor_process_resize(Server* server, uint32_t time) -{} +{ + View* view = server->m_grabbed_view; + + double border_x = server->m_cursor->x - server->m_grab_x; + double border_y = server->m_cursor->y - server->m_grab_y; + + int new_left = server->m_grab_geobox.x; + int new_right = server->m_grab_geobox.x + server->m_grab_geobox.width; + int new_top = server->m_grab_geobox.y; + int new_bottom = server->m_grab_geobox.y + server->m_grab_geobox.height; + + if (server->m_resize_edges & WLR_EDGE_TOP) { + new_top = border_y; + + if (new_top >= new_bottom) + new_top = new_bottom - 1; + } else if (server->m_resize_edges & WLR_EDGE_BOTTOM) { + new_bottom = border_y; + + if (new_bottom <= new_top) + new_bottom = new_top + 1; + } + + if (server->m_resize_edges & WLR_EDGE_LEFT) { + new_left = border_x; + + if (new_left >= new_right) + new_left = new_right - 1; + } else if (server->m_resize_edges & WLR_EDGE_RIGHT) { + new_right = border_x; + + if (new_right <= new_left) + new_right = new_left + 1; + } + + struct wlr_box geo_box; + wlr_xdg_surface_get_geometry(view->xdg_surface, &geo_box); + view->x = new_left - geo_box.x; + view->y = new_top - geo_box.y; + wlr_scene_node_set_position(view->scene_node, view->x, view->y); + + int new_width = new_right - new_left; + int new_height = new_bottom - new_top; + wlr_xdg_toplevel_set_size(view->xdg_surface, new_width, new_height); +} void Server::keyboard_handle_modifiers(struct wl_listener* listener, void* data) -{} +{ + Keyboard* keyboard = wl_container_of(listener, keyboard, modifiers); + + wlr_seat_set_keyboard(keyboard->server->m_seat, keyboard->device); + wlr_seat_keyboard_notify_modifiers( + keyboard->server->m_seat, + &keyboard->device->keyboard->modifiers + ); +} void Server::keyboard_handle_key(struct wl_listener* listener, void* data) -{} +{ + Keyboard* keyboard = wl_container_of(listener, keyboard, key); + Server* server = keyboard->server; + + struct wlr_event_keyboard_key* event + = reinterpret_cast<struct wlr_event_keyboard_key*>(data); + struct wlr_seat* seat = server->m_seat; + + uint32_t keycode = event->keycode + 8; + const xkb_keysym_t* syms; + + int nsyms = xkb_state_key_get_syms( + keyboard->device->keyboard->xkb_state, + keycode, + &syms + ); + + bool handled = false; + uint32_t modifiers = wlr_keyboard_get_modifiers(keyboard->device->keyboard); + + if ((modifiers & WLR_MODIFIER_ALT) && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { + for (int i = 0; i < nsyms; i++) + handled = keyboard_handle_keybinding(server, syms[i]); + } + + if (!handled) { + wlr_seat_set_keyboard(seat, keyboard->device); + wlr_seat_keyboard_notify_key( + seat, + event->time_msec, + event->keycode, + event->state + ); + } +} + +bool +Server::keyboard_handle_keybinding(Server* server, xkb_keysym_t sym) +{ + switch (sym) { + case XKB_KEY_Escape: + wl_display_terminate(server->m_display); + break; + case XKB_KEY_F1: + { + if (wl_list_length(&server->m_views) < 2) + break; + + View* next_view = wl_container_of(server->m_views.prev, next_view, link); + focus_view(next_view, next_view->xdg_surface->surface); + } + break; + default: return false; + } + + return true; +} void Server::seat_request_cursor(struct wl_listener* listener, void* data) -{} +{ + Server* server = wl_container_of(listener, server, m_request_cursor); + + struct wlr_seat_pointer_request_set_cursor_event* event + = reinterpret_cast<struct wlr_seat_pointer_request_set_cursor_event*>(data); + struct wlr_seat_client* focused_client = server->m_seat->pointer_state.focused_client; + + if (focused_client == event->seat_client) + wlr_cursor_set_surface( + server->m_cursor, + event->surface, + event->hotspot_x, + event->hotspot_y + ); +} void Server::seat_request_set_selection(struct wl_listener* listener, void* data) -{} +{ + Server* server = wl_container_of(listener, server, m_request_set_selection); + + struct wlr_seat_request_set_selection_event* event + = reinterpret_cast<struct wlr_seat_request_set_selection_event*>(data); + + wlr_seat_set_selection(server->m_seat, event->source, event->serial); +} void Server::output_frame(struct wl_listener* listener, void* data) -{} +{ + Output* output = wl_container_of(listener, output, frame); + struct wlr_scene* scene = output->server->m_scene; + + struct wlr_scene_output* scene_output + = wlr_scene_get_scene_output(scene, output->wlr_output); + + wlr_scene_output_commit(scene_output); + + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + wlr_scene_output_send_frame_done(scene_output, &now); +} View* Server::desktop_view_at( @@ -412,31 +567,146 @@ Server::desktop_view_at( double* sy ) { + struct wlr_scene_node* node = wlr_scene_node_at( + &server->m_scene->node, + lx, ly, + sx, sy + ); + + if (!node || 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*>(node->data); } void Server::focus_view(View* view, struct wlr_surface* surface) { + if (!view) + return; + + Server* server = view->server; + struct wlr_seat* seat = server->m_seat; + struct wlr_surface* prev_surface = seat->keyboard_state.focused_surface; + + if (prev_surface == surface) + return; + + if (prev_surface) + wlr_xdg_toplevel_set_activated( + wlr_xdg_surface_from_wlr_surface( + seat->keyboard_state.focused_surface + ), + false + ); + struct wlr_keyboard* keyboard = wlr_seat_get_keyboard(seat); + + wlr_scene_node_raise_to_top(view->scene_node); + wl_list_remove(&view->link); + wl_list_insert(&server->m_views, &view->link); + wlr_xdg_toplevel_set_activated(view->xdg_surface, true); + wlr_seat_keyboard_notify_enter( + seat, + view->xdg_surface->surface, + keyboard->keycodes, + keyboard->num_keycodes, + &keyboard->modifiers + ); } void Server::xdg_toplevel_map(struct wl_listener* listener, void* data) -{} +{ + View* view = wl_container_of(listener, view, map); + + wl_list_insert(&view->server->m_views, &view->link); + focus_view(view, view->xdg_surface->surface); +} void Server::xdg_toplevel_unmap(struct wl_listener* listener, void* data) -{} +{ + View* view = wl_container_of(listener, view, unmap); + wl_list_remove(&view->link); +} void Server::xdg_toplevel_destroy(struct wl_listener* listener, void* data) -{} +{ + View* view = wl_container_of(listener, view, destroy); + + wl_list_remove(&view->map.link); + wl_list_remove(&view->unmap.link); + wl_list_remove(&view->destroy.link); + wl_list_remove(&view->request_move.link); + wl_list_remove(&view->request_resize.link); + + free(view); +} void Server::xdg_toplevel_request_move(struct wl_listener* listener, void* data) -{} +{ + View* view = wl_container_of(listener, view, request_move); + xdg_toplevel_handle_moveresize(view, Server::CursorMode::Move, 0); +} void Server::xdg_toplevel_request_resize(struct wl_listener* listener, void* data) -{} +{ + struct wlr_xdg_toplevel_resize_event* event + = reinterpret_cast<struct wlr_xdg_toplevel_resize_event*>(data); + + View* view = wl_container_of(listener, view, request_resize); + xdg_toplevel_handle_moveresize(view, Server::CursorMode::Resize, event->edges); +} + +void +Server::xdg_toplevel_handle_moveresize(View* view, Server::CursorMode mode, uint32_t edges) +{ + Server* server = view->server; + + if (view->xdg_surface->surface + != wlr_surface_get_root_surface(server->m_seat->pointer_state.focused_surface)) + { + return; + } + + server->m_grabbed_view = view; + server->m_cursor_mode = mode; + + switch (mode) { + case Server::CursorMode::Move: + server->m_grab_x = server->m_cursor->x - view->x; + server->m_grab_y = server->m_cursor->y - view->y; + return; + case Server::CursorMode::Resize: + { + struct wlr_box geo_box; + wlr_xdg_surface_get_geometry(view->xdg_surface, &geo_box); + + double border_x = (view->x + geo_box.x) + + ((edges & WLR_EDGE_RIGHT) ? geo_box.width : 0); + + double border_y = (view->y + geo_box.y) + + ((edges & WLR_EDGE_BOTTOM) ? geo_box.height : 0); + + server->m_grab_x = server->m_cursor->x - border_x; + server->m_grab_y = server->m_cursor->y - border_y; + + server->m_grab_geobox = geo_box; + server->m_grab_geobox.x += view->x; + server->m_grab_geobox.y += view->y; + + server->m_resize_edges = edges; + } + return; + default: return; + } +}