mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2026-04-18 06:47:31 -04:00
Merge branch 'tinywl-remove-wlr-cursor' into 'master'
proposal: Reafactor tinywl to not use wlr_cursor Closes #3436 See merge request wlroots/wlroots!4070
This commit is contained in:
commit
01f3691749
4 changed files with 386 additions and 119 deletions
|
|
@ -33,6 +33,7 @@ struct wlr_xdg_surface;
|
||||||
struct wlr_layer_surface_v1;
|
struct wlr_layer_surface_v1;
|
||||||
struct wlr_drag_icon;
|
struct wlr_drag_icon;
|
||||||
struct wlr_surface;
|
struct wlr_surface;
|
||||||
|
struct wlr_xcursor_manager;
|
||||||
|
|
||||||
struct wlr_scene_node;
|
struct wlr_scene_node;
|
||||||
struct wlr_scene_buffer;
|
struct wlr_scene_buffer;
|
||||||
|
|
@ -538,4 +539,10 @@ void wlr_scene_layer_surface_v1_configure(
|
||||||
struct wlr_scene_tree *wlr_scene_drag_icon_create(
|
struct wlr_scene_tree *wlr_scene_drag_icon_create(
|
||||||
struct wlr_scene_tree *parent, struct wlr_drag_icon *drag_icon);
|
struct wlr_scene_tree *parent, struct wlr_drag_icon *drag_icon);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a node displaying an xcursor to the scene-graph.
|
||||||
|
*/
|
||||||
|
struct wlr_scene_tree *wlr_scene_xcursor_create(struct wlr_scene_tree *parent,
|
||||||
|
struct wlr_xcursor_manager *manager, const char *name);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
293
tinywl/tinywl.c
293
tinywl/tinywl.c
|
|
@ -10,7 +10,6 @@
|
||||||
#include <wlr/backend.h>
|
#include <wlr/backend.h>
|
||||||
#include <wlr/render/allocator.h>
|
#include <wlr/render/allocator.h>
|
||||||
#include <wlr/render/wlr_renderer.h>
|
#include <wlr/render/wlr_renderer.h>
|
||||||
#include <wlr/types/wlr_cursor.h>
|
|
||||||
#include <wlr/types/wlr_compositor.h>
|
#include <wlr/types/wlr_compositor.h>
|
||||||
#include <wlr/types/wlr_data_device.h>
|
#include <wlr/types/wlr_data_device.h>
|
||||||
#include <wlr/types/wlr_input_device.h>
|
#include <wlr/types/wlr_input_device.h>
|
||||||
|
|
@ -39,25 +38,28 @@ struct tinywl_server {
|
||||||
struct wlr_renderer *renderer;
|
struct wlr_renderer *renderer;
|
||||||
struct wlr_allocator *allocator;
|
struct wlr_allocator *allocator;
|
||||||
struct wlr_scene *scene;
|
struct wlr_scene *scene;
|
||||||
|
struct wlr_scene_tree *desktop;
|
||||||
|
|
||||||
struct wlr_xdg_shell *xdg_shell;
|
struct wlr_xdg_shell *xdg_shell;
|
||||||
struct wl_listener new_xdg_surface;
|
struct wl_listener new_xdg_surface;
|
||||||
struct wl_list views;
|
struct wl_list views;
|
||||||
|
|
||||||
struct wlr_cursor *cursor;
|
|
||||||
struct wlr_xcursor_manager *cursor_mgr;
|
struct wlr_xcursor_manager *cursor_mgr;
|
||||||
struct wl_listener cursor_motion;
|
struct {
|
||||||
struct wl_listener cursor_motion_absolute;
|
struct wl_list devices;
|
||||||
struct wl_listener cursor_button;
|
enum tinywl_cursor_mode mode;
|
||||||
struct wl_listener cursor_axis;
|
struct wlr_scene_tree *tree;
|
||||||
struct wl_listener cursor_frame;
|
struct wlr_scene_node *cursor_node;
|
||||||
|
struct wlr_scene_tree *default_cursor;
|
||||||
|
|
||||||
|
double x, y;
|
||||||
|
} cursor;
|
||||||
|
|
||||||
struct wlr_seat *seat;
|
struct wlr_seat *seat;
|
||||||
struct wl_listener new_input;
|
struct wl_listener new_input;
|
||||||
struct wl_listener request_cursor;
|
struct wl_listener request_cursor;
|
||||||
struct wl_listener request_set_selection;
|
struct wl_listener request_set_selection;
|
||||||
struct wl_list keyboards;
|
struct wl_list keyboards;
|
||||||
enum tinywl_cursor_mode cursor_mode;
|
|
||||||
struct tinywl_view *grabbed_view;
|
struct tinywl_view *grabbed_view;
|
||||||
double grab_x, grab_y;
|
double grab_x, grab_y;
|
||||||
struct wlr_box grab_geobox;
|
struct wlr_box grab_geobox;
|
||||||
|
|
@ -101,6 +103,18 @@ struct tinywl_keyboard {
|
||||||
struct wl_listener destroy;
|
struct wl_listener destroy;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct tinywl_pointer_device {
|
||||||
|
struct wl_list link;
|
||||||
|
struct wlr_pointer *wlr_pointer;
|
||||||
|
struct tinywl_server *server;
|
||||||
|
|
||||||
|
struct wl_listener cursor_motion;
|
||||||
|
struct wl_listener cursor_motion_absolute;
|
||||||
|
struct wl_listener cursor_button;
|
||||||
|
struct wl_listener cursor_axis;
|
||||||
|
struct wl_listener cursor_destroy;
|
||||||
|
};
|
||||||
|
|
||||||
static void focus_view(struct tinywl_view *view, struct wlr_surface *surface) {
|
static void focus_view(struct tinywl_view *view, struct wlr_surface *surface) {
|
||||||
/* Note: this function only deals with keyboard focus. */
|
/* Note: this function only deals with keyboard focus. */
|
||||||
if (view == NULL) {
|
if (view == NULL) {
|
||||||
|
|
@ -270,41 +284,6 @@ static void server_new_keyboard(struct tinywl_server *server,
|
||||||
wl_list_insert(&server->keyboards, &keyboard->link);
|
wl_list_insert(&server->keyboards, &keyboard->link);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void server_new_pointer(struct tinywl_server *server,
|
|
||||||
struct wlr_input_device *device) {
|
|
||||||
/* We don't do anything special with pointers. All of our pointer handling
|
|
||||||
* is proxied through wlr_cursor. On another compositor, you might take this
|
|
||||||
* opportunity to do libinput configuration on the device to set
|
|
||||||
* acceleration, etc. */
|
|
||||||
wlr_cursor_attach_input_device(server->cursor, device);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void server_new_input(struct wl_listener *listener, void *data) {
|
|
||||||
/* This event is raised by the backend when a new input device becomes
|
|
||||||
* available. */
|
|
||||||
struct tinywl_server *server =
|
|
||||||
wl_container_of(listener, server, new_input);
|
|
||||||
struct wlr_input_device *device = data;
|
|
||||||
switch (device->type) {
|
|
||||||
case WLR_INPUT_DEVICE_KEYBOARD:
|
|
||||||
server_new_keyboard(server, device);
|
|
||||||
break;
|
|
||||||
case WLR_INPUT_DEVICE_POINTER:
|
|
||||||
server_new_pointer(server, device);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* We need to let the wlr_seat know what our capabilities are, which is
|
|
||||||
* communiciated to the client. In TinyWL we always have a cursor, even if
|
|
||||||
* there are no pointer devices, so we always include that capability. */
|
|
||||||
uint32_t caps = WL_SEAT_CAPABILITY_POINTER;
|
|
||||||
if (!wl_list_empty(&server->keyboards)) {
|
|
||||||
caps |= WL_SEAT_CAPABILITY_KEYBOARD;
|
|
||||||
}
|
|
||||||
wlr_seat_set_capabilities(server->seat, caps);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void seat_request_cursor(struct wl_listener *listener, void *data) {
|
static void seat_request_cursor(struct wl_listener *listener, void *data) {
|
||||||
struct tinywl_server *server = wl_container_of(
|
struct tinywl_server *server = wl_container_of(
|
||||||
listener, server, request_cursor);
|
listener, server, request_cursor);
|
||||||
|
|
@ -319,8 +298,25 @@ static void seat_request_cursor(struct wl_listener *listener, void *data) {
|
||||||
* provided surface as the cursor image. It will set the hardware cursor
|
* provided surface as the cursor image. It will set the hardware cursor
|
||||||
* on the output that it's currently on and continue to do so as the
|
* on the output that it's currently on and continue to do so as the
|
||||||
* cursor moves between outputs. */
|
* cursor moves between outputs. */
|
||||||
wlr_cursor_set_surface(server->cursor, event->surface,
|
|
||||||
event->hotspot_x, event->hotspot_y);
|
if (server->cursor.cursor_node) {
|
||||||
|
wlr_scene_node_destroy(server->cursor.cursor_node);
|
||||||
|
server->cursor.cursor_node = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event->surface) {
|
||||||
|
struct wlr_scene_tree *tree = wlr_scene_tree_create(server->cursor.tree);
|
||||||
|
if (!tree) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wlr_scene_node_set_enabled(&server->cursor.default_cursor->node, false);
|
||||||
|
wlr_scene_subsurface_tree_create(tree, event->surface);
|
||||||
|
wlr_scene_node_set_position(&tree->node,
|
||||||
|
-event->hotspot_x, -event->hotspot_y);
|
||||||
|
|
||||||
|
server->cursor.cursor_node = &tree->node;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -342,7 +338,7 @@ static struct tinywl_view *desktop_view_at(
|
||||||
* we only care about surface nodes as we are specifically looking for a
|
* we only care about surface nodes as we are specifically looking for a
|
||||||
* surface in the surface tree of a tinywl_view. */
|
* surface in the surface tree of a tinywl_view. */
|
||||||
struct wlr_scene_node *node = wlr_scene_node_at(
|
struct wlr_scene_node *node = wlr_scene_node_at(
|
||||||
&server->scene->tree.node, lx, ly, sx, sy);
|
&server->desktop->node, lx, ly, sx, sy);
|
||||||
if (node == NULL || node->type != WLR_SCENE_NODE_BUFFER) {
|
if (node == NULL || node->type != WLR_SCENE_NODE_BUFFER) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -365,7 +361,7 @@ static struct tinywl_view *desktop_view_at(
|
||||||
|
|
||||||
static void reset_cursor_mode(struct tinywl_server *server) {
|
static void reset_cursor_mode(struct tinywl_server *server) {
|
||||||
/* Reset the cursor mode to passthrough. */
|
/* Reset the cursor mode to passthrough. */
|
||||||
server->cursor_mode = TINYWL_CURSOR_PASSTHROUGH;
|
server->cursor.mode = TINYWL_CURSOR_PASSTHROUGH;
|
||||||
server->grabbed_view = NULL;
|
server->grabbed_view = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -373,8 +369,8 @@ static void process_cursor_move(struct tinywl_server *server, uint32_t time) {
|
||||||
/* Move the grabbed view to the new position. */
|
/* Move the grabbed view to the new position. */
|
||||||
struct tinywl_view *view = server->grabbed_view;
|
struct tinywl_view *view = server->grabbed_view;
|
||||||
wlr_scene_node_set_position(&view->scene_tree->node,
|
wlr_scene_node_set_position(&view->scene_tree->node,
|
||||||
server->cursor->x - server->grab_x,
|
server->cursor.x - server->grab_x,
|
||||||
server->cursor->y - server->grab_y);
|
server->cursor.y - server->grab_y);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void process_cursor_resize(struct tinywl_server *server, uint32_t time) {
|
static void process_cursor_resize(struct tinywl_server *server, uint32_t time) {
|
||||||
|
|
@ -389,8 +385,8 @@ static void process_cursor_resize(struct tinywl_server *server, uint32_t time) {
|
||||||
* commit any movement that was prepared.
|
* commit any movement that was prepared.
|
||||||
*/
|
*/
|
||||||
struct tinywl_view *view = server->grabbed_view;
|
struct tinywl_view *view = server->grabbed_view;
|
||||||
double border_x = server->cursor->x - server->grab_x;
|
double border_x = server->cursor.x - server->grab_x;
|
||||||
double border_y = server->cursor->y - server->grab_y;
|
double border_y = server->cursor.y - server->grab_y;
|
||||||
int new_left = server->grab_geobox.x;
|
int new_left = server->grab_geobox.x;
|
||||||
int new_right = server->grab_geobox.x + server->grab_geobox.width;
|
int new_right = server->grab_geobox.x + server->grab_geobox.width;
|
||||||
int new_top = server->grab_geobox.y;
|
int new_top = server->grab_geobox.y;
|
||||||
|
|
@ -430,11 +426,14 @@ static void process_cursor_resize(struct tinywl_server *server, uint32_t time) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void process_cursor_motion(struct tinywl_server *server, uint32_t time) {
|
static void process_cursor_motion(struct tinywl_server *server, uint32_t time) {
|
||||||
|
wlr_scene_node_set_position(&server->cursor.tree->node,
|
||||||
|
server->cursor.x, server->cursor.y);
|
||||||
|
|
||||||
/* If the mode is non-passthrough, delegate to those functions. */
|
/* If the mode is non-passthrough, delegate to those functions. */
|
||||||
if (server->cursor_mode == TINYWL_CURSOR_MOVE) {
|
if (server->cursor.mode == TINYWL_CURSOR_MOVE) {
|
||||||
process_cursor_move(server, time);
|
process_cursor_move(server, time);
|
||||||
return;
|
return;
|
||||||
} else if (server->cursor_mode == TINYWL_CURSOR_RESIZE) {
|
} else if (server->cursor.mode == TINYWL_CURSOR_RESIZE) {
|
||||||
process_cursor_resize(server, time);
|
process_cursor_resize(server, time);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -444,13 +443,17 @@ static void process_cursor_motion(struct tinywl_server *server, uint32_t time) {
|
||||||
struct wlr_seat *seat = server->seat;
|
struct wlr_seat *seat = server->seat;
|
||||||
struct wlr_surface *surface = NULL;
|
struct wlr_surface *surface = NULL;
|
||||||
struct tinywl_view *view = desktop_view_at(server,
|
struct tinywl_view *view = desktop_view_at(server,
|
||||||
server->cursor->x, server->cursor->y, &surface, &sx, &sy);
|
server->cursor.x, server->cursor.y, &surface, &sx, &sy);
|
||||||
if (!view) {
|
if (!view) {
|
||||||
/* If there's no view under the cursor, set the cursor image to a
|
/* If there's no view under the cursor, set the cursor image to a
|
||||||
* default. This is what makes the cursor image appear when you move it
|
* default. This is what makes the cursor image appear when you move it
|
||||||
* around the screen, not over any views. */
|
* around the screen, not over any views. */
|
||||||
wlr_xcursor_manager_set_cursor_image(
|
if (server->cursor.cursor_node) {
|
||||||
server->cursor_mgr, "default", server->cursor);
|
wlr_scene_node_destroy(server->cursor.cursor_node);
|
||||||
|
server->cursor.cursor_node = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
wlr_scene_node_set_enabled(&server->cursor.default_cursor->node, true);
|
||||||
}
|
}
|
||||||
if (surface) {
|
if (surface) {
|
||||||
/*
|
/*
|
||||||
|
|
@ -476,17 +479,23 @@ static void process_cursor_motion(struct tinywl_server *server, uint32_t time) {
|
||||||
static void server_cursor_motion(struct wl_listener *listener, void *data) {
|
static void server_cursor_motion(struct wl_listener *listener, void *data) {
|
||||||
/* This event is forwarded by the cursor when a pointer emits a _relative_
|
/* This event is forwarded by the cursor when a pointer emits a _relative_
|
||||||
* pointer motion event (i.e. a delta) */
|
* pointer motion event (i.e. a delta) */
|
||||||
struct tinywl_server *server =
|
struct tinywl_pointer_device *pointer =
|
||||||
wl_container_of(listener, server, cursor_motion);
|
wl_container_of(listener, pointer, cursor_motion);
|
||||||
struct wlr_pointer_motion_event *event = data;
|
struct wlr_pointer_motion_event *event = data;
|
||||||
/* The cursor doesn't move unless we tell it to. The cursor automatically
|
/* The cursor doesn't move unless we tell it to. The cursor automatically
|
||||||
* handles constraining the motion to the output layout, as well as any
|
* handles constraining the motion to the output layout, as well as any
|
||||||
* special configuration applied for the specific input device which
|
* special configuration applied for the specific input device which
|
||||||
* generated the event. You can pass NULL for the device if you want to move
|
* generated the event. You can pass NULL for the device if you want to move
|
||||||
* the cursor around without any input. */
|
* the cursor around without any input. */
|
||||||
wlr_cursor_move(server->cursor, &event->pointer->base,
|
|
||||||
event->delta_x, event->delta_y);
|
double lx = pointer->server->cursor.x + event->delta_x;
|
||||||
process_cursor_motion(server, event->time_msec);
|
double ly = pointer->server->cursor.y + event->delta_y;
|
||||||
|
wlr_output_layout_closest_point(pointer->server->output_layout, NULL,
|
||||||
|
lx, ly, &lx, &ly);
|
||||||
|
|
||||||
|
pointer->server->cursor.x = lx;
|
||||||
|
pointer->server->cursor.y = lx;
|
||||||
|
process_cursor_motion(pointer->server, event->time_msec);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void server_cursor_motion_absolute(
|
static void server_cursor_motion_absolute(
|
||||||
|
|
@ -497,30 +506,34 @@ static void server_cursor_motion_absolute(
|
||||||
* move the mouse over the window. You could enter the window from any edge,
|
* move the mouse over the window. You could enter the window from any edge,
|
||||||
* so we have to warp the mouse there. There is also some hardware which
|
* so we have to warp the mouse there. There is also some hardware which
|
||||||
* emits these events. */
|
* emits these events. */
|
||||||
struct tinywl_server *server =
|
struct tinywl_pointer_device *pointer =
|
||||||
wl_container_of(listener, server, cursor_motion_absolute);
|
wl_container_of(listener, pointer, cursor_motion_absolute);
|
||||||
struct wlr_pointer_motion_absolute_event *event = data;
|
struct wlr_pointer_motion_absolute_event *event = data;
|
||||||
wlr_cursor_warp_absolute(server->cursor, &event->pointer->base, event->x,
|
|
||||||
event->y);
|
struct wlr_box mapping;
|
||||||
process_cursor_motion(server, event->time_msec);
|
wlr_output_layout_get_box(pointer->server->output_layout, NULL, &mapping);
|
||||||
|
|
||||||
|
pointer->server->cursor.x = event->x * mapping.width + mapping.x;
|
||||||
|
pointer->server->cursor.y = event->y * mapping.height + mapping.y;
|
||||||
|
process_cursor_motion(pointer->server, event->time_msec);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void server_cursor_button(struct wl_listener *listener, void *data) {
|
static void server_cursor_button(struct wl_listener *listener, void *data) {
|
||||||
/* This event is forwarded by the cursor when a pointer emits a button
|
/* This event is forwarded by the cursor when a pointer emits a button
|
||||||
* event. */
|
* event. */
|
||||||
struct tinywl_server *server =
|
struct tinywl_pointer_device *pointer =
|
||||||
wl_container_of(listener, server, cursor_button);
|
wl_container_of(listener, pointer, cursor_button);
|
||||||
struct wlr_pointer_button_event *event = data;
|
struct wlr_pointer_button_event *event = data;
|
||||||
/* Notify the client with pointer focus that a button press has occurred */
|
/* Notify the client with pointer focus that a button press has occurred */
|
||||||
wlr_seat_pointer_notify_button(server->seat,
|
wlr_seat_pointer_notify_button(pointer->server->seat,
|
||||||
event->time_msec, event->button, event->state);
|
event->time_msec, event->button, event->state);
|
||||||
double sx, sy;
|
double sx, sy;
|
||||||
struct wlr_surface *surface = NULL;
|
struct wlr_surface *surface = NULL;
|
||||||
struct tinywl_view *view = desktop_view_at(server,
|
struct tinywl_view *view = desktop_view_at(pointer->server,
|
||||||
server->cursor->x, server->cursor->y, &surface, &sx, &sy);
|
pointer->server->cursor.x, pointer->server->cursor.y, &surface, &sx, &sy);
|
||||||
if (event->state == WLR_BUTTON_RELEASED) {
|
if (event->state == WLR_BUTTON_RELEASED) {
|
||||||
/* If you released any buttons, we exit interactive move/resize mode. */
|
/* If you released any buttons, we exit interactive move/resize mode. */
|
||||||
reset_cursor_mode(server);
|
reset_cursor_mode(pointer->server);
|
||||||
} else {
|
} else {
|
||||||
/* Focus that client if the button was _pressed_ */
|
/* Focus that client if the button was _pressed_ */
|
||||||
focus_view(view, surface);
|
focus_view(view, surface);
|
||||||
|
|
@ -530,24 +543,77 @@ static void server_cursor_button(struct wl_listener *listener, void *data) {
|
||||||
static void server_cursor_axis(struct wl_listener *listener, void *data) {
|
static void server_cursor_axis(struct wl_listener *listener, void *data) {
|
||||||
/* This event is forwarded by the cursor when a pointer emits an axis event,
|
/* This event is forwarded by the cursor when a pointer emits an axis event,
|
||||||
* for example when you move the scroll wheel. */
|
* for example when you move the scroll wheel. */
|
||||||
struct tinywl_server *server =
|
struct tinywl_pointer_device *pointer =
|
||||||
wl_container_of(listener, server, cursor_axis);
|
wl_container_of(listener, pointer, cursor_axis);
|
||||||
struct wlr_pointer_axis_event *event = data;
|
struct wlr_pointer_axis_event *event = data;
|
||||||
/* Notify the client with pointer focus of the axis event. */
|
/* Notify the client with pointer focus of the axis event. */
|
||||||
wlr_seat_pointer_notify_axis(server->seat,
|
wlr_seat_pointer_notify_axis(pointer->server->seat,
|
||||||
event->time_msec, event->orientation, event->delta,
|
event->time_msec, event->orientation, event->delta,
|
||||||
event->delta_discrete, event->source);
|
event->delta_discrete, event->source);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void server_cursor_frame(struct wl_listener *listener, void *data) {
|
static void server_cursor_destroy(struct wl_listener *listener, void *data) {
|
||||||
/* This event is forwarded by the cursor when a pointer emits an frame
|
struct tinywl_pointer_device *pointer =
|
||||||
* event. Frame events are sent after regular pointer events to group
|
wl_container_of(listener, pointer, cursor_destroy);
|
||||||
* multiple events together. For instance, two axis events may happen at the
|
|
||||||
* same time, in which case a frame event won't be sent in between. */
|
wl_list_remove(&pointer->cursor_motion.link);
|
||||||
|
wl_list_remove(&pointer->cursor_motion_absolute.link);
|
||||||
|
wl_list_remove(&pointer->cursor_button.link);
|
||||||
|
wl_list_remove(&pointer->cursor_axis.link);
|
||||||
|
wl_list_remove(&pointer->cursor_destroy.link);
|
||||||
|
|
||||||
|
wl_list_remove(&pointer->link);
|
||||||
|
free(pointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void server_new_pointer(struct tinywl_server *server,
|
||||||
|
struct wlr_input_device *device) {
|
||||||
|
struct wlr_pointer *wlr_pointer = wlr_pointer_from_input_device(device);
|
||||||
|
|
||||||
|
struct tinywl_pointer_device *pointer =
|
||||||
|
calloc(1, sizeof(struct tinywl_pointer_device));
|
||||||
|
|
||||||
|
pointer->server = server;
|
||||||
|
pointer->wlr_pointer = wlr_pointer;
|
||||||
|
|
||||||
|
pointer->cursor_motion.notify = server_cursor_motion;
|
||||||
|
wl_signal_add(&wlr_pointer->events.motion, &pointer->cursor_motion);
|
||||||
|
pointer->cursor_motion_absolute.notify = server_cursor_motion_absolute;
|
||||||
|
wl_signal_add(&wlr_pointer->events.motion_absolute, &pointer->cursor_motion_absolute);
|
||||||
|
pointer->cursor_button.notify = server_cursor_button;
|
||||||
|
wl_signal_add(&wlr_pointer->events.button, &pointer->cursor_button);
|
||||||
|
pointer->cursor_axis.notify = server_cursor_axis;
|
||||||
|
wl_signal_add(&wlr_pointer->events.axis, &pointer->cursor_axis);
|
||||||
|
pointer->cursor_destroy.notify = server_cursor_destroy;
|
||||||
|
wl_signal_add(&device->events.destroy, &pointer->cursor_destroy);
|
||||||
|
|
||||||
|
wl_list_insert(&server->cursor.devices, &pointer->link);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void server_new_input(struct wl_listener *listener, void *data) {
|
||||||
|
/* This event is raised by the backend when a new input device becomes
|
||||||
|
* available. */
|
||||||
struct tinywl_server *server =
|
struct tinywl_server *server =
|
||||||
wl_container_of(listener, server, cursor_frame);
|
wl_container_of(listener, server, new_input);
|
||||||
/* Notify the client with pointer focus of the frame event. */
|
struct wlr_input_device *device = data;
|
||||||
wlr_seat_pointer_notify_frame(server->seat);
|
switch (device->type) {
|
||||||
|
case WLR_INPUT_DEVICE_KEYBOARD:
|
||||||
|
server_new_keyboard(server, device);
|
||||||
|
break;
|
||||||
|
case WLR_INPUT_DEVICE_POINTER:
|
||||||
|
server_new_pointer(server, device);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* We need to let the wlr_seat know what our capabilities are, which is
|
||||||
|
* communiciated to the client. In TinyWL we always have a cursor, even if
|
||||||
|
* there are no pointer devices, so we always include that capability. */
|
||||||
|
uint32_t caps = WL_SEAT_CAPABILITY_POINTER;
|
||||||
|
if (!wl_list_empty(&server->keyboards)) {
|
||||||
|
caps |= WL_SEAT_CAPABILITY_KEYBOARD;
|
||||||
|
}
|
||||||
|
wlr_seat_set_capabilities(server->seat, caps);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void output_frame(struct wl_listener *listener, void *data) {
|
static void output_frame(struct wl_listener *listener, void *data) {
|
||||||
|
|
@ -696,11 +762,11 @@ static void begin_interactive(struct tinywl_view *view,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
server->grabbed_view = view;
|
server->grabbed_view = view;
|
||||||
server->cursor_mode = mode;
|
server->cursor.mode = mode;
|
||||||
|
|
||||||
if (mode == TINYWL_CURSOR_MOVE) {
|
if (mode == TINYWL_CURSOR_MOVE) {
|
||||||
server->grab_x = server->cursor->x - view->scene_tree->node.x;
|
server->grab_x = server->cursor.x - view->scene_tree->node.x;
|
||||||
server->grab_y = server->cursor->y - view->scene_tree->node.y;
|
server->grab_y = server->cursor.y - view->scene_tree->node.y;
|
||||||
} else {
|
} else {
|
||||||
struct wlr_box geo_box;
|
struct wlr_box geo_box;
|
||||||
wlr_xdg_surface_get_geometry(view->xdg_toplevel->base, &geo_box);
|
wlr_xdg_surface_get_geometry(view->xdg_toplevel->base, &geo_box);
|
||||||
|
|
@ -709,8 +775,8 @@ static void begin_interactive(struct tinywl_view *view,
|
||||||
((edges & WLR_EDGE_RIGHT) ? geo_box.width : 0);
|
((edges & WLR_EDGE_RIGHT) ? geo_box.width : 0);
|
||||||
double border_y = (view->scene_tree->node.y + geo_box.y) +
|
double border_y = (view->scene_tree->node.y + geo_box.y) +
|
||||||
((edges & WLR_EDGE_BOTTOM) ? geo_box.height : 0);
|
((edges & WLR_EDGE_BOTTOM) ? geo_box.height : 0);
|
||||||
server->grab_x = server->cursor->x - border_x;
|
server->grab_x = server->cursor.x - border_x;
|
||||||
server->grab_y = server->cursor->y - border_y;
|
server->grab_y = server->cursor.y - border_y;
|
||||||
|
|
||||||
server->grab_geobox = geo_box;
|
server->grab_geobox = geo_box;
|
||||||
server->grab_geobox.x += view->scene_tree->node.x;
|
server->grab_geobox.x += view->scene_tree->node.x;
|
||||||
|
|
@ -792,7 +858,7 @@ static void server_new_xdg_surface(struct wl_listener *listener, void *data) {
|
||||||
view->server = server;
|
view->server = server;
|
||||||
view->xdg_toplevel = xdg_surface->toplevel;
|
view->xdg_toplevel = xdg_surface->toplevel;
|
||||||
view->scene_tree = wlr_scene_xdg_surface_create(
|
view->scene_tree = wlr_scene_xdg_surface_create(
|
||||||
&view->server->scene->tree, view->xdg_toplevel->base);
|
view->server->desktop, view->xdg_toplevel->base);
|
||||||
view->scene_tree->node.data = view;
|
view->scene_tree->node.data = view;
|
||||||
xdg_surface->data = view->scene_tree;
|
xdg_surface->data = view->scene_tree;
|
||||||
|
|
||||||
|
|
@ -905,6 +971,8 @@ int main(int argc, char *argv[]) {
|
||||||
server.scene = wlr_scene_create();
|
server.scene = wlr_scene_create();
|
||||||
wlr_scene_attach_output_layout(server.scene, server.output_layout);
|
wlr_scene_attach_output_layout(server.scene, server.output_layout);
|
||||||
|
|
||||||
|
server.desktop = wlr_scene_tree_create(&server.scene->tree);
|
||||||
|
|
||||||
/* Set up xdg-shell version 3. The xdg-shell is a Wayland protocol which is
|
/* Set up xdg-shell version 3. The xdg-shell is a Wayland protocol which is
|
||||||
* used for application windows. For more detail on shells, refer to my
|
* used for application windows. For more detail on shells, refer to my
|
||||||
* article:
|
* article:
|
||||||
|
|
@ -917,44 +985,31 @@ int main(int argc, char *argv[]) {
|
||||||
wl_signal_add(&server.xdg_shell->events.new_surface,
|
wl_signal_add(&server.xdg_shell->events.new_surface,
|
||||||
&server.new_xdg_surface);
|
&server.new_xdg_surface);
|
||||||
|
|
||||||
/*
|
|
||||||
* Creates a cursor, which is a wlroots utility for tracking the cursor
|
|
||||||
* image shown on screen.
|
|
||||||
*/
|
|
||||||
server.cursor = wlr_cursor_create();
|
|
||||||
wlr_cursor_attach_output_layout(server.cursor, server.output_layout);
|
|
||||||
|
|
||||||
/* Creates an xcursor manager, another wlroots utility which loads up
|
/* Creates an xcursor manager, another wlroots utility which loads up
|
||||||
* Xcursor themes to source cursor images from and makes sure that cursor
|
* Xcursor themes to source cursor images from and makes sure that cursor
|
||||||
* images are available at all scale factors on the screen (necessary for
|
* images are available at all scale factors on the screen (necessary for
|
||||||
* HiDPI support). We add a cursor theme at scale factor 1 to begin with. */
|
* HiDPI support). We add a cursor theme at scale factor 1 to begin with. */
|
||||||
server.cursor_mgr = wlr_xcursor_manager_create(NULL, 24);
|
server.cursor_mgr = wlr_xcursor_manager_create(NULL, 24);
|
||||||
wlr_xcursor_manager_load(server.cursor_mgr, 1);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* wlr_cursor *only* displays an image on screen. It does not move around
|
* Initialize all the state for the cursor
|
||||||
* when the pointer moves. However, we can attach input devices to it, and
|
|
||||||
* it will generate aggregate events for all of them. In these events, we
|
|
||||||
* can choose how we want to process them, forwarding them to clients and
|
|
||||||
* moving the cursor around. More detail on this process is described in my
|
|
||||||
* input handling blog post:
|
|
||||||
*
|
|
||||||
* https://drewdevault.com/2018/07/17/Input-handling-in-wlroots.html
|
|
||||||
*
|
|
||||||
* And more comments are sprinkled throughout the notify functions above.
|
|
||||||
*/
|
*/
|
||||||
server.cursor_mode = TINYWL_CURSOR_PASSTHROUGH;
|
server.cursor.mode = TINYWL_CURSOR_PASSTHROUGH;
|
||||||
server.cursor_motion.notify = server_cursor_motion;
|
server.cursor.tree = wlr_scene_tree_create(&server.scene->tree);
|
||||||
wl_signal_add(&server.cursor->events.motion, &server.cursor_motion);
|
if (!server.cursor.tree) {
|
||||||
server.cursor_motion_absolute.notify = server_cursor_motion_absolute;
|
wlr_backend_destroy(server.backend);
|
||||||
wl_signal_add(&server.cursor->events.motion_absolute,
|
return 1;
|
||||||
&server.cursor_motion_absolute);
|
}
|
||||||
server.cursor_button.notify = server_cursor_button;
|
|
||||||
wl_signal_add(&server.cursor->events.button, &server.cursor_button);
|
wl_list_init(&server.cursor.devices);
|
||||||
server.cursor_axis.notify = server_cursor_axis;
|
|
||||||
wl_signal_add(&server.cursor->events.axis, &server.cursor_axis);
|
server.cursor.default_cursor = wlr_scene_xcursor_create(server.cursor.tree,
|
||||||
server.cursor_frame.notify = server_cursor_frame;
|
server.cursor_mgr, "default");
|
||||||
wl_signal_add(&server.cursor->events.frame, &server.cursor_frame);
|
if (!server.cursor.default_cursor) {
|
||||||
|
wlr_backend_destroy(server.backend);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Configures a seat, which is a single "seat" at which a user sits and
|
* Configures a seat, which is a single "seat" at which a user sits and
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ wlr_files += files(
|
||||||
'scene/surface.c',
|
'scene/surface.c',
|
||||||
'scene/wlr_scene.c',
|
'scene/wlr_scene.c',
|
||||||
'scene/output_layout.c',
|
'scene/output_layout.c',
|
||||||
|
'scene/xcursor.c',
|
||||||
'scene/xdg_shell.c',
|
'scene/xdg_shell.c',
|
||||||
'scene/layer_shell_v1.c',
|
'scene/layer_shell_v1.c',
|
||||||
'seat/wlr_seat_keyboard.c',
|
'seat/wlr_seat_keyboard.c',
|
||||||
|
|
|
||||||
204
types/scene/xcursor.c
Normal file
204
types/scene/xcursor.c
Normal file
|
|
@ -0,0 +1,204 @@
|
||||||
|
#define _POSIX_C_SOURCE 200809L
|
||||||
|
#include <drm_fourcc.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <wlr/types/wlr_scene.h>
|
||||||
|
#include <wlr/types/wlr_xcursor_manager.h>
|
||||||
|
#include <wlr/interfaces/wlr_buffer.h>
|
||||||
|
|
||||||
|
struct xcursor_buffer {
|
||||||
|
struct wlr_buffer base;
|
||||||
|
struct wlr_xcursor_image image;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void xcursor_buffer_handle_destroy(struct wlr_buffer *wlr_buffer) {
|
||||||
|
struct xcursor_buffer *buffer = wl_container_of(wlr_buffer, buffer, base);
|
||||||
|
free(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool xcursor_buffer_handle_begin_data_ptr_access(struct wlr_buffer *wlr_buffer,
|
||||||
|
uint32_t flags, void **data, uint32_t *format, size_t *stride) {
|
||||||
|
struct xcursor_buffer *buffer = wl_container_of(wlr_buffer, buffer, base);
|
||||||
|
*data = buffer->image.buffer;
|
||||||
|
*stride = buffer->image.width * 4;
|
||||||
|
*format = DRM_FORMAT_ARGB8888;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void xcursor_buffer_handle_end_data_ptr_access(struct wlr_buffer *wlr_buffer) {
|
||||||
|
// This space is intentionally left blank
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct wlr_buffer_impl xcursor_buffer_impl = {
|
||||||
|
.destroy = xcursor_buffer_handle_destroy,
|
||||||
|
.begin_data_ptr_access = xcursor_buffer_handle_begin_data_ptr_access,
|
||||||
|
.end_data_ptr_access = xcursor_buffer_handle_end_data_ptr_access,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wlr_scene_xcursor {
|
||||||
|
struct wlr_scene_tree *tree;
|
||||||
|
struct wlr_scene_buffer *buffer;
|
||||||
|
struct wlr_xcursor_manager *manager;
|
||||||
|
char *name;
|
||||||
|
float scale;
|
||||||
|
|
||||||
|
struct wl_list outputs; // struct wlr_scene_xcursor_output.link
|
||||||
|
|
||||||
|
struct wl_listener output_enter;
|
||||||
|
struct wl_listener output_leave;
|
||||||
|
struct wl_listener tree_destroy;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wlr_scene_xcursor_output {
|
||||||
|
struct wlr_scene_xcursor *xcursor;
|
||||||
|
struct wlr_output *output;
|
||||||
|
struct wl_list link;
|
||||||
|
struct wl_listener commit;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void scene_xcursor_update_cursor(struct wlr_scene_xcursor *cursor) {
|
||||||
|
float scale = 1;
|
||||||
|
struct wlr_scene_xcursor_output *output;
|
||||||
|
wl_list_for_each(output, &cursor->outputs, link) {
|
||||||
|
if (output->output->scale > scale) {
|
||||||
|
output->output->scale = scale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scale == cursor->scale) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor->scale = scale;
|
||||||
|
|
||||||
|
if (!wlr_xcursor_manager_load(cursor->manager, scale)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_xcursor *xcursor =
|
||||||
|
wlr_xcursor_manager_get_xcursor(cursor->manager, cursor->name, scale);
|
||||||
|
if (!xcursor) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_xcursor_image *image = xcursor->images[0];
|
||||||
|
|
||||||
|
struct xcursor_buffer *xcursor_buffer = calloc(1, sizeof(*xcursor_buffer));
|
||||||
|
if (!xcursor_buffer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wlr_buffer_init(&xcursor_buffer->base, &xcursor_buffer_impl, image->width, image->height);
|
||||||
|
xcursor_buffer->image = *image;
|
||||||
|
|
||||||
|
wlr_scene_node_set_position(&cursor->buffer->node,
|
||||||
|
-image->hotspot_x, -image->hotspot_y);
|
||||||
|
wlr_scene_buffer_set_dest_size(cursor->buffer,
|
||||||
|
image->width / scale, image->height / scale);
|
||||||
|
wlr_scene_buffer_set_buffer(cursor->buffer, &xcursor_buffer->base);
|
||||||
|
|
||||||
|
wlr_buffer_drop(&xcursor_buffer->base);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_output_commit(struct wl_listener *listener, void *data) {
|
||||||
|
struct wlr_scene_xcursor_output *output = wl_container_of(listener, output, commit);
|
||||||
|
struct wlr_output_event_commit *event = data;
|
||||||
|
|
||||||
|
if (event->committed & WLR_OUTPUT_STATE_SCALE) {
|
||||||
|
scene_xcursor_update_cursor(output->xcursor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_output_enter(struct wl_listener *listener, void *data) {
|
||||||
|
struct wlr_scene_xcursor *cursor = wl_container_of(listener, cursor, output_enter);
|
||||||
|
struct wlr_scene_output *scene_output = data;
|
||||||
|
|
||||||
|
struct wlr_scene_xcursor_output *output = calloc(1, sizeof(*output));
|
||||||
|
if (!output) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
output->output = scene_output->output;
|
||||||
|
output->xcursor = cursor;
|
||||||
|
|
||||||
|
output->commit.notify = handle_output_commit;
|
||||||
|
wl_signal_add(&output->output->events.commit, &output->commit);
|
||||||
|
|
||||||
|
wl_list_insert(&cursor->outputs, &output->link);
|
||||||
|
scene_xcursor_update_cursor(cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void output_destroy(struct wlr_scene_xcursor_output *output) {
|
||||||
|
wl_list_remove(&output->link);
|
||||||
|
wl_list_remove(&output->commit.link);
|
||||||
|
free(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_output_leave(struct wl_listener *listener, void *data) {
|
||||||
|
struct wlr_scene_xcursor *cursor = wl_container_of(listener, cursor, output_leave);
|
||||||
|
struct wlr_scene_output *scene_output = data;
|
||||||
|
|
||||||
|
struct wlr_scene_xcursor_output *output, *tmp_output;
|
||||||
|
wl_list_for_each_safe(output, tmp_output, &cursor->outputs, link) {
|
||||||
|
if (output->output == scene_output->output) {
|
||||||
|
output_destroy(output);
|
||||||
|
scene_xcursor_update_cursor(cursor);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void scene_xcursor_handle_tree_destroy(struct wl_listener *listener, void *data) {
|
||||||
|
struct wlr_scene_xcursor *cursor = wl_container_of(listener, cursor, tree_destroy);
|
||||||
|
|
||||||
|
struct wlr_scene_xcursor_output *output, *tmp_output;
|
||||||
|
wl_list_for_each_safe(output, tmp_output, &cursor->outputs, link) {
|
||||||
|
output_destroy(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_list_remove(&cursor->tree_destroy.link);
|
||||||
|
free(cursor->name);
|
||||||
|
free(cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_scene_tree *wlr_scene_xcursor_create(struct wlr_scene_tree *parent,
|
||||||
|
struct wlr_xcursor_manager *manager, const char *name) {
|
||||||
|
struct wlr_scene_xcursor *cursor = calloc(1, sizeof(*cursor));
|
||||||
|
if (!cursor) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor->tree = wlr_scene_tree_create(parent);
|
||||||
|
if (!cursor->tree) {
|
||||||
|
free(cursor);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor->buffer = wlr_scene_buffer_create(cursor->tree, NULL);
|
||||||
|
if (!cursor->buffer) {
|
||||||
|
wlr_scene_node_destroy(&cursor->tree->node);
|
||||||
|
free(cursor);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor->name = strdup(name);
|
||||||
|
if (!cursor->name) {
|
||||||
|
wlr_scene_node_destroy(&cursor->tree->node);
|
||||||
|
free(cursor);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_list_init(&cursor->outputs);
|
||||||
|
cursor->manager = manager;
|
||||||
|
|
||||||
|
cursor->output_enter.notify = handle_output_enter;
|
||||||
|
wl_signal_add(&cursor->buffer->events.output_enter, &cursor->output_enter);
|
||||||
|
cursor->output_leave.notify = handle_output_leave;
|
||||||
|
wl_signal_add(&cursor->buffer->events.output_leave, &cursor->output_leave);
|
||||||
|
cursor->tree_destroy.notify = scene_xcursor_handle_tree_destroy;
|
||||||
|
wl_signal_add(&cursor->tree->node.events.destroy, &cursor->tree_destroy);
|
||||||
|
|
||||||
|
scene_xcursor_update_cursor(cursor);
|
||||||
|
|
||||||
|
return cursor->tree;
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue