From da04b066ea037be0fdc5d79ac6b214fea6f2d3c5 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 5 Jun 2023 15:31:57 +0200 Subject: [PATCH] cursor: add wlr_cursor_set_xcursor() This keeps track of the last set XCursor. If it hasn't changed, skip the texture upload. In the future, support for animated XCursors can be added. Closes: https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/3436 --- include/wlr/types/wlr_cursor.h | 9 +++++++++ include/wlr/types/wlr_xcursor_manager.h | 2 ++ tinywl/tinywl.c | 6 ++---- types/wlr_cursor.c | 27 +++++++++++++++++++++++++ 4 files changed, 40 insertions(+), 4 deletions(-) diff --git a/include/wlr/types/wlr_cursor.h b/include/wlr/types/wlr_cursor.h index 06ae2f1f..f3c7e970 100644 --- a/include/wlr/types/wlr_cursor.h +++ b/include/wlr/types/wlr_cursor.h @@ -14,6 +14,7 @@ #include struct wlr_input_device; +struct wlr_xcursor_manager; /** * wlr_cursor implements the behavior of the "cursor", that is, the image on the @@ -146,6 +147,14 @@ void wlr_cursor_set_image(struct wlr_cursor *cur, const uint8_t *pixels, int32_t stride, uint32_t width, uint32_t height, int32_t hotspot_x, int32_t hotspot_y, float scale); +/** + * Set the cursor image from an XCursor theme. + * + * The image will be loaded from the struct wlr_xcursor_manager. + */ +void wlr_cursor_set_xcursor(struct wlr_cursor *cur, + struct wlr_xcursor_manager *manager, const char *name); + /** * Set the cursor surface. The surface can be committed to update the cursor * image. The surface position is subtracted from the hotspot. A NULL surface diff --git a/include/wlr/types/wlr_xcursor_manager.h b/include/wlr/types/wlr_xcursor_manager.h index f7781ca6..7d7b19ab 100644 --- a/include/wlr/types/wlr_xcursor_manager.h +++ b/include/wlr/types/wlr_xcursor_manager.h @@ -62,6 +62,8 @@ struct wlr_xcursor *wlr_xcursor_manager_get_xcursor( * scale factors. struct wlr_cursor will take over from this point and ensure * the correct cursor is used on each output, assuming a * struct wlr_output_layout is attached to it. + * + * Deprecated: wlr_cursor_set_xcursor() should be used instead. */ void wlr_xcursor_manager_set_cursor_image(struct wlr_xcursor_manager *manager, const char *name, struct wlr_cursor *cursor); diff --git a/tinywl/tinywl.c b/tinywl/tinywl.c index bfabac6e..e6e3ceee 100644 --- a/tinywl/tinywl.c +++ b/tinywl/tinywl.c @@ -449,8 +449,7 @@ static void process_cursor_motion(struct tinywl_server *server, uint32_t time) { /* 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 * around the screen, not over any views. */ - wlr_xcursor_manager_set_cursor_image( - server->cursor_mgr, "default", server->cursor); + wlr_cursor_set_xcursor(server->cursor, server->cursor_mgr, "default"); } if (surface) { /* @@ -927,9 +926,8 @@ int main(int argc, char *argv[]) { /* Creates an xcursor manager, another wlroots utility which loads up * Xcursor themes to source cursor images from and makes sure that cursor * 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). */ 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 diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c index 3d5c8b22..cce37e81 100644 --- a/types/wlr_cursor.c +++ b/types/wlr_cursor.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include "types/wlr_output.h" @@ -65,6 +66,9 @@ struct wlr_cursor_output_cursor { struct wl_listener surface_commit; struct wl_listener surface_destroy; struct wl_listener output_commit; + + // only when using an XCursor as the cursor image + struct wlr_xcursor *xcursor; }; struct wlr_cursor_state { @@ -380,6 +384,8 @@ static void cursor_output_cursor_reset_image( wl_list_init(&output_cursor->surface_commit.link); wl_list_init(&output_cursor->output_commit.link); output_cursor->surface = NULL; + + output_cursor->xcursor = NULL; } static void output_cursor_output_commit_surface( @@ -419,6 +425,27 @@ void wlr_cursor_set_image(struct wlr_cursor *cur, const uint8_t *pixels, } } +void wlr_cursor_set_xcursor(struct wlr_cursor *cur, + struct wlr_xcursor_manager *manager, const char *name) { + struct wlr_cursor_output_cursor *output_cursor; + wl_list_for_each(output_cursor, &cur->state->output_cursors, link) { + float scale = output_cursor->output_cursor->output->scale; + wlr_xcursor_manager_load(manager, scale); + struct wlr_xcursor *xcursor = wlr_xcursor_manager_get_xcursor(manager, name, scale); + if (xcursor == NULL || output_cursor->xcursor == xcursor) { + continue; + } + + cursor_output_cursor_reset_image(output_cursor); + output_cursor->xcursor = xcursor; + + struct wlr_xcursor_image *image = xcursor->images[0]; + wlr_output_cursor_set_image(output_cursor->output_cursor, + image->buffer, 4 * image->width, image->width, image->height, + image->hotspot_x, image->hotspot_y); + } +} + static void output_cursor_output_handle_surface_destroy( struct wl_listener *listener, void *data) { struct wlr_cursor_output_cursor *output_cursor =