From 06debf11db47422e4afabbdf6f49d5fc556c1f70 Mon Sep 17 00:00:00 2001 From: Charlotte Meyer Date: Thu, 26 Dec 2019 20:55:10 +0000 Subject: [PATCH] Add basic cursor handling (including focusing clients) --- include/desktop/desktop.h | 3 +- include/desktop/view.h | 32 +++++++++++++-- include/input/cursor.h | 6 ++- kiwmi/desktop/desktop.c | 2 + kiwmi/desktop/output.c | 2 +- kiwmi/desktop/view.c | 84 +++++++++++++++++++++++++++++++++----- kiwmi/desktop/xdg_shell.c | 29 ++++++++++++- kiwmi/input/cursor.c | 86 ++++++++++++++++++++++++++++++++++++--- kiwmi/input/input.c | 2 +- 9 files changed, 222 insertions(+), 24 deletions(-) diff --git a/include/desktop/desktop.h b/include/desktop/desktop.h index 19a1c6d..f798b17 100644 --- a/include/desktop/desktop.h +++ b/include/desktop/desktop.h @@ -17,7 +17,8 @@ struct kiwmi_desktop { struct wlr_data_device_manager *data_device_manager; struct wlr_output_layout *output_layout; struct wl_list outputs; // struct kiwmi_output::link - struct wl_list views; // struct kiwmi_view::link + struct kiwmi_view *focused_view; + struct wl_list views; // struct kiwmi_view::link struct wl_listener xdg_shell_new_surface; struct wl_listener new_output; diff --git a/include/desktop/view.h b/include/desktop/view.h index 51de2ac..d561512 100644 --- a/include/desktop/view.h +++ b/include/desktop/view.h @@ -30,6 +30,8 @@ struct kiwmi_view { struct wlr_xdg_surface *xdg_surface; }; + struct wlr_surface *wlr_surface; + struct wl_listener map; struct wl_listener unmap; struct wl_listener destroy; @@ -45,14 +47,38 @@ struct kiwmi_view_impl { struct kiwmi_view *view, wlr_surface_iterator_func_t iterator, void *user_data); + void (*set_activated)(struct kiwmi_view *view, bool activated); + struct wlr_surface *(*surface_at)( + struct kiwmi_view *view, + double sx, + double sy, + double *sub_x, + double *sub_y); }; -void kiwmi_view_for_each_surface( +void view_for_each_surface( struct kiwmi_view *view, wlr_surface_iterator_func_t iterator, void *user_data); +void view_set_activated(struct kiwmi_view *view, bool activated); +struct wlr_surface *view_surface_at( + struct kiwmi_view *view, + double sx, + double sy, + double *sub_x, + double *sub_y); -void focus_view(struct kiwmi_view *view, struct wlr_surface *surface); -struct kiwmi_view *view_create(struct kiwmi_desktop *desktop, enum kiwmi_view_type type, const struct kiwmi_view_impl *impl); +void focus_view(struct kiwmi_view *view); +struct kiwmi_view *view_at( + struct kiwmi_desktop *desktop, + double lx, + double ly, + struct wlr_surface **surface, + double *sx, + double *sy); +struct kiwmi_view *view_create( + struct kiwmi_desktop *desktop, + enum kiwmi_view_type type, + const struct kiwmi_view_impl *impl); #endif /* KIWMI_DESKTOP_VIEW_H */ diff --git a/include/input/cursor.h b/include/input/cursor.h index 25dddd0..3c0feda 100644 --- a/include/input/cursor.h +++ b/include/input/cursor.h @@ -12,12 +12,16 @@ #include struct kiwmi_cursor { + struct kiwmi_server *server; struct wlr_cursor *cursor; struct wlr_xcursor_manager *xcursor_manager; struct wl_listener cursor_motion; struct wl_listener cursor_motion_absolute; + struct wl_listener cursor_button; }; -struct kiwmi_cursor *cursor_create(struct wlr_output_layout *output_layout); +struct kiwmi_cursor *cursor_create( + struct kiwmi_server *server, + struct wlr_output_layout *output_layout); #endif /* KIWMI_INPUT_CURSOR_H */ diff --git a/kiwmi/desktop/desktop.c b/kiwmi/desktop/desktop.c index 7be0712..92fd5dd 100644 --- a/kiwmi/desktop/desktop.c +++ b/kiwmi/desktop/desktop.c @@ -41,6 +41,8 @@ desktop_init(struct kiwmi_desktop *desktop, struct wlr_renderer *renderer) &desktop->xdg_shell->events.new_surface, &desktop->xdg_shell_new_surface); + desktop->focused_view = NULL; + wl_list_init(&desktop->outputs); wl_list_init(&desktop->views); diff --git a/kiwmi/desktop/output.c b/kiwmi/desktop/output.c index 8905dfb..aa138cd 100644 --- a/kiwmi/desktop/output.c +++ b/kiwmi/desktop/output.c @@ -109,7 +109,7 @@ output_frame_notify(struct wl_listener *listener, void *data) .when = &now, }; - kiwmi_view_for_each_surface(view, render_surface, &rdata); + view_for_each_surface(view, render_surface, &rdata); } wlr_output_render_software_cursors(wlr_output, NULL); diff --git a/kiwmi/desktop/view.c b/kiwmi/desktop/view.c index 648d994..397cdf4 100644 --- a/kiwmi/desktop/view.c +++ b/kiwmi/desktop/view.c @@ -13,7 +13,7 @@ #include "server.h" void -kiwmi_view_for_each_surface( +view_for_each_surface( struct kiwmi_view *view, wlr_surface_iterator_func_t iterator, void *user_data) @@ -24,7 +24,28 @@ kiwmi_view_for_each_surface( } void -focus_view(struct kiwmi_view *view, struct wlr_surface *surface) +view_set_activated(struct kiwmi_view *view, bool activated) +{ + if (view->impl->set_activated) { + view->impl->set_activated(view, activated); + } +} + +struct wlr_surface * +view_surface_at( + struct kiwmi_view *view, + double sx, + double sy, + double *sub_x, + double *sub_y) +{ + if (view->impl->surface_at) { + return view->impl->surface_at(view, sx, sy, sub_x, sub_y); + } +} + +void +focus_view(struct kiwmi_view *view) { if (!view) { return; @@ -33,16 +54,13 @@ focus_view(struct kiwmi_view *view, struct wlr_surface *surface) struct kiwmi_desktop *desktop = view->desktop; struct kiwmi_server *server = wl_container_of(desktop, server, desktop); struct wlr_seat *seat = server->input.seat; - struct wlr_surface *prev_surface = seat->keyboard_state.focused_surface; - if (prev_surface == surface) { + if (view == desktop->focused_view) { return; } - if (prev_surface) { - struct wlr_xdg_surface *previous = wlr_xdg_surface_from_wlr_surface( - seat->keyboard_state.focused_surface); - wlr_xdg_toplevel_set_activated(previous, false); + if (desktop->focused_view) { + view_set_activated(desktop->focused_view, false); } struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat); @@ -51,15 +69,61 @@ focus_view(struct kiwmi_view *view, struct wlr_surface *surface) wl_list_remove(&view->link); wl_list_insert(&desktop->views, &view->link); - wlr_xdg_toplevel_set_activated(view->xdg_surface, true); + view_set_activated(view, true); wlr_seat_keyboard_notify_enter( seat, - view->xdg_surface->surface, + view->wlr_surface, keyboard->keycodes, keyboard->num_keycodes, &keyboard->modifiers); } +static bool +surface_at( + struct kiwmi_view *view, + struct wlr_surface **surface, + double lx, + double ly, + double *sx, + double *sy) +{ + double view_sx = lx - view->x; + double view_sy = ly - view->y; + + double _sx, _sy; + struct wlr_surface *_surface = NULL; + _surface = view_surface_at(view, view_sx, view_sy, &_sx, &_sy); + + if (_surface != NULL) { + *sx = _sx; + *sy = _sy; + *surface = _surface; + return true; + } + + return false; +} + +struct kiwmi_view * +view_at( + struct kiwmi_desktop *desktop, + double lx, + double ly, + struct wlr_surface **surface, + double *sx, + double *sy) +{ + struct kiwmi_view *view; + wl_list_for_each(view, &desktop->views, link) + { + if (surface_at(view, surface, lx, ly, sx, sy)) { + return view; + } + } + + return NULL; +} + struct kiwmi_view * view_create( struct kiwmi_desktop *desktop, diff --git a/kiwmi/desktop/xdg_shell.c b/kiwmi/desktop/xdg_shell.c index 474eaca..2375b1d 100644 --- a/kiwmi/desktop/xdg_shell.c +++ b/kiwmi/desktop/xdg_shell.c @@ -19,7 +19,7 @@ xdg_surface_map_notify(struct wl_listener *listener, void *UNUSED(data)) { struct kiwmi_view *view = wl_container_of(listener, view, map); view->mapped = true; - focus_view(view, view->xdg_surface->surface); + focus_view(view); } static void @@ -32,7 +32,12 @@ xdg_surface_unmap_notify(struct wl_listener *listener, void *UNUSED(data)) static void xdg_surface_destroy_notify(struct wl_listener *listener, void *UNUSED(data)) { - struct kiwmi_view *view = wl_container_of(listener, view, destroy); + struct kiwmi_view *view = wl_container_of(listener, view, destroy); + struct kiwmi_desktop *desktop = view->desktop; + + if (desktop->focused_view == view) { + desktop->focused_view = NULL; + } wl_list_remove(&view->link); wl_list_remove(&view->map.link); @@ -51,8 +56,27 @@ xdg_shell_view_for_each_surface( wlr_xdg_surface_for_each_surface(view->xdg_surface, iterator, user_data); } +static void +xdg_shell_view_set_activated(struct kiwmi_view *view, bool activated) +{ + wlr_xdg_toplevel_set_activated(view->xdg_surface, activated); +} + +struct wlr_surface * +xdg_shell_view_surface_at( + struct kiwmi_view *view, + double sx, + double sy, + double *sub_x, + double *sub_y) +{ + return wlr_xdg_surface_surface_at(view->xdg_surface, sx, sy, sub_x, sub_y); +} + static const struct kiwmi_view_impl xdg_shell_view_impl = { .for_each_surface = xdg_shell_view_for_each_surface, + .set_activated = xdg_shell_view_set_activated, + .surface_at = xdg_shell_view_surface_at, }; void @@ -82,6 +106,7 @@ xdg_shell_new_surface_notify(struct wl_listener *listener, void *data) } view->xdg_surface = xdg_surface; + view->wlr_surface = xdg_surface->surface; view->map.notify = xdg_surface_map_notify; wl_signal_add(&xdg_surface->events.map, &view->map); diff --git a/kiwmi/input/cursor.c b/kiwmi/input/cursor.c index 2d00e08..4cd466b 100644 --- a/kiwmi/input/cursor.c +++ b/kiwmi/input/cursor.c @@ -13,20 +13,59 @@ #include #include #include +#include #include #include +#include "desktop/desktop.h" +#include "desktop/view.h" +#include "server.h" + +static void +process_cursor_motion(struct kiwmi_server *server, uint32_t time) +{ + struct kiwmi_desktop *desktop = &server->desktop; + struct kiwmi_input *input = &server->input; + struct kiwmi_cursor *cursor = input->cursor; + struct wlr_seat *seat = input->seat; + + struct wlr_surface *surface = NULL; + double sx; + double sy; + + struct kiwmi_view *view = view_at( + desktop, cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); + + if (!view) { + wlr_xcursor_manager_set_cursor_image( + cursor->xcursor_manager, "left_ptr", cursor->cursor); + } + + if (surface) { + bool focus_changed = surface != seat->pointer_state.focused_surface; + + wlr_seat_pointer_notify_enter(seat, surface, sx, sy); + + if (!focus_changed) { + wlr_seat_pointer_notify_motion(seat, time, sx, sy); + } + } else { + wlr_seat_pointer_clear_focus(seat); + } +} + static void cursor_motion_notify(struct wl_listener *listener, void *data) { struct kiwmi_cursor *cursor = wl_container_of(listener, cursor, cursor_motion); + struct kiwmi_server *server = cursor->server; struct wlr_event_pointer_motion *event = data; - wlr_xcursor_manager_set_cursor_image( - cursor->xcursor_manager, "left_ptr", cursor->cursor); wlr_cursor_move( cursor->cursor, event->device, event->delta_x, event->delta_y); + + process_cursor_motion(server, event->time_msec); } static void @@ -34,15 +73,47 @@ cursor_motion_absolute_notify(struct wl_listener *listener, void *data) { struct kiwmi_cursor *cursor = wl_container_of(listener, cursor, cursor_motion_absolute); + struct kiwmi_server *server = cursor->server; struct wlr_event_pointer_motion_absolute *event = data; - wlr_xcursor_manager_set_cursor_image( - cursor->xcursor_manager, "left_ptr", cursor->cursor); wlr_cursor_warp_absolute(cursor->cursor, event->device, event->x, event->y); + + process_cursor_motion(server, event->time_msec); +} + +static void +cursor_button_notify(struct wl_listener *listener, void *data) +{ + struct kiwmi_cursor *cursor = + wl_container_of(listener, cursor, cursor_button); + struct kiwmi_server *server = cursor->server; + struct kiwmi_input *input = &server->input; + struct wlr_event_pointer_button *event = data; + + wlr_seat_pointer_notify_button( + input->seat, event->time_msec, event->button, event->state); + + double sx; + double sy; + struct wlr_surface *surface; + + struct kiwmi_view *view = view_at( + &server->desktop, + cursor->cursor->x, + cursor->cursor->y, + &surface, + &sx, + &sy); + + if (event->state == WLR_BUTTON_PRESSED) { + focus_view(view); + } } struct kiwmi_cursor * -cursor_create(struct wlr_output_layout *output_layout) +cursor_create( + struct kiwmi_server *server, + struct wlr_output_layout *output_layout) { wlr_log(WLR_DEBUG, "Creating cursor"); @@ -52,6 +123,8 @@ cursor_create(struct wlr_output_layout *output_layout) return NULL; } + cursor->server = server; + cursor->cursor = wlr_cursor_create(); if (!cursor->cursor) { wlr_log(WLR_ERROR, "Failed to create cursor"); @@ -71,5 +144,8 @@ cursor_create(struct wlr_output_layout *output_layout) &cursor->cursor->events.motion_absolute, &cursor->cursor_motion_absolute); + cursor->cursor_button.notify = cursor_button_notify; + wl_signal_add(&cursor->cursor->events.button, &cursor->cursor_button); + return cursor; } diff --git a/kiwmi/input/input.c b/kiwmi/input/input.c index 22455ed..07dfc30 100644 --- a/kiwmi/input/input.c +++ b/kiwmi/input/input.c @@ -71,7 +71,7 @@ input_init(struct kiwmi_input *input) { struct kiwmi_server *server = wl_container_of(input, server, input); - input->cursor = cursor_create(server->desktop.output_layout); + input->cursor = cursor_create(server, server->desktop.output_layout); if (!input->cursor) { wlr_log(WLR_ERROR, "Failed to create cursor"); return false;