From d7f7b68f494eadbe2245155f0ecdb6ab3501c1e7 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 4 Jan 2026 18:24:18 +0100 Subject: [PATCH] xcursor: introduce wlr_xcursor_image_get_buffer() This makes it so callers no longer need to juggle with raw pixel pointers anymore, and only need a single wlr_buffer-based codepath. Additionally, cursors can be unloaded without risking use-after-free. --- include/wlr/xcursor.h | 9 +++++++++ xcursor/wlr_xcursor.c | 25 ++++++++++++++++++++++--- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/include/wlr/xcursor.h b/include/wlr/xcursor.h index bb75119b5..7cf333d70 100644 --- a/include/wlr/xcursor.h +++ b/include/wlr/xcursor.h @@ -56,6 +56,10 @@ struct wlr_xcursor_image { uint32_t hotspot_y; /* hot-spot y (must be inside image) */ uint32_t delay; /* animation delay to next frame (ms) */ uint8_t *buffer; /* pixel data */ + + struct { + struct wlr_readonly_data_buffer *readonly_buffer; + } WLR_PRIVATE; }; /** @@ -119,6 +123,11 @@ struct wlr_xcursor *wlr_xcursor_theme_get_cursor( */ int wlr_xcursor_frame(struct wlr_xcursor *cursor, uint32_t time); +/** + * Get a struct wlr_buffer from a cursor image. + */ +struct wlr_buffer *wlr_xcursor_image_get_buffer(struct wlr_xcursor_image *image); + /** * Get the name of the resize cursor for the given edges. */ diff --git a/xcursor/wlr_xcursor.c b/xcursor/wlr_xcursor.c index 163ba3dec..3b4d25cff 100644 --- a/xcursor/wlr_xcursor.c +++ b/xcursor/wlr_xcursor.c @@ -23,18 +23,21 @@ * SOFTWARE. */ +#include #include #include #include #include #include #include +#include "types/wlr_buffer.h" #include "xcursor/xcursor.h" #include "xcursor/cursor_data.h" static void xcursor_destroy(struct wlr_xcursor *cursor) { for (size_t i = 0; i < cursor->image_count; i++) { + readonly_data_buffer_drop(cursor->images[i]->readonly_buffer); free(cursor->images[i]->buffer); free(cursor->images[i]); } @@ -57,16 +60,28 @@ static struct wlr_xcursor_image *xcursor_image_create(uint32_t width, uint32_t h image->hotspot_y = hotspot_y; image->delay = delay; - size_t size = width * height * sizeof(uint32_t); + size_t stride = width * sizeof(uint32_t); + size_t size = stride * height; image->buffer = malloc(size); if (image->buffer == NULL) { - free(image); - return NULL; + goto err_image; } memcpy(image->buffer, buffer, size); + image->readonly_buffer = readonly_data_buffer_create(DRM_FORMAT_ARGB8888, + stride, width, height, image->buffer); + if (image->readonly_buffer == NULL) { + goto err_buffer; + } + return image; + +err_buffer: + free(image->buffer); +err_image: + free(image); + return NULL; } static struct wlr_xcursor *xcursor_create_from_data( @@ -330,6 +345,10 @@ int wlr_xcursor_frame(struct wlr_xcursor *_cursor, uint32_t time) { return xcursor_frame_and_duration(_cursor, time, NULL); } +struct wlr_buffer *wlr_xcursor_image_get_buffer(struct wlr_xcursor_image *image) { + return &image->readonly_buffer->base; +} + const char *wlr_xcursor_get_resize_name(enum wlr_edges edges) { if (edges & WLR_EDGE_TOP) { if (edges & WLR_EDGE_RIGHT) {