Add basic cursor handling (including focusing clients)
This commit is contained in:
parent
2f4c865afc
commit
06debf11db
9 changed files with 222 additions and 24 deletions
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue