Add basic cursor handling (including focusing clients)

This commit is contained in:
buffet 2019-12-26 20:55:10 +00:00
parent 2f4c865afc
commit 06debf11db
9 changed files with 222 additions and 24 deletions

View file

@ -17,6 +17,7 @@ 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 kiwmi_view *focused_view;
struct wl_list views; // struct kiwmi_view::link
struct wl_listener xdg_shell_new_surface;

View file

@ -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 */

View file

@ -12,12 +12,16 @@
#include <wlr/types/wlr_output_layout.h>
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 */

View file

@ -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);

View file

@ -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);

View file

@ -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,

View file

@ -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
@ -33,6 +33,11 @@ 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_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);

View file

@ -13,20 +13,59 @@
#include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_pointer.h>
#include <wlr/types/wlr_seat.h>
#include <wlr/types/wlr_xcursor_manager.h>
#include <wlr/util/log.h>
#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;
}

View file

@ -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;