From 71c87ff4b8b6a4bf080273255a25685270389fd6 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 23 Jun 2023 20:03:58 +0200 Subject: [PATCH] cursor: add wlr_cursor_set_buffer() A saner replacement for wlr_cursor_set_image(): - Takes a wlr_buffer instead of numerous parameters and a hardcoded format. - The scale is not used to filter outputs. - A ref to the buffer is kept to apply it to new outputs. --- include/wlr/types/wlr_cursor.h | 9 ++++++ types/wlr_cursor.c | 57 ++++++++++++++++++++++++++++++++-- 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/include/wlr/types/wlr_cursor.h b/include/wlr/types/wlr_cursor.h index a4c2e731..96059255 100644 --- a/include/wlr/types/wlr_cursor.h +++ b/include/wlr/types/wlr_cursor.h @@ -147,6 +147,15 @@ 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 buffer. + * + * The buffer is used on all outputs and is scaled accordingly. The hotspot is + * expressed in logical coordinates. A NULL buffer hides the cursor. + */ +void wlr_cursor_set_buffer(struct wlr_cursor *cur, struct wlr_buffer *buffer, + int32_t hotspot_x, int32_t hotspot_y, float scale); + /** * Hide the cursor image. */ diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c index f00593c2..d5ad634b 100644 --- a/types/wlr_cursor.c +++ b/types/wlr_cursor.c @@ -81,6 +81,13 @@ struct wlr_cursor_state { struct wl_listener layout_change; struct wl_listener layout_destroy; + // only when using a buffer as the cursor image + struct wlr_buffer *buffer; + struct { + int32_t x, y; + } buffer_hotspot; + float buffer_scale; + // only when using a surface as the cursor image struct wlr_surface *surface; struct { @@ -207,6 +214,9 @@ static void cursor_device_destroy(struct wlr_cursor_device *c_device) { } static void cursor_reset_image(struct wlr_cursor *cur) { + wlr_buffer_unlock(cur->state->buffer); + cur->state->buffer = NULL; + if (cur->state->surface != NULL) { struct wlr_cursor_output_cursor *output_cursor; wl_list_for_each(output_cursor, &cur->state->output_cursors, link) { @@ -430,6 +440,27 @@ void wlr_cursor_set_image(struct wlr_cursor *cur, const uint8_t *pixels, static void cursor_update_outputs(struct wlr_cursor *cur); +void wlr_cursor_set_buffer(struct wlr_cursor *cur, struct wlr_buffer *buffer, + int32_t hotspot_x, int32_t hotspot_y, float scale) { + if (buffer == cur->state->buffer && + hotspot_x == cur->state->buffer_hotspot.x && + hotspot_y == cur->state->buffer_hotspot.y && + scale == cur->state->buffer_scale) { + return; + } + + cursor_reset_image(cur); + + if (buffer != NULL) { + cur->state->buffer = wlr_buffer_lock(buffer); + cur->state->buffer_hotspot.x = hotspot_x; + cur->state->buffer_hotspot.y = hotspot_y; + cur->state->buffer_scale = scale; + } + + cursor_update_outputs(cur); +} + void wlr_cursor_unset_image(struct wlr_cursor *cur) { cursor_reset_image(cur); cursor_update_outputs(cur); @@ -489,8 +520,30 @@ static void cursor_output_cursor_update(struct wlr_cursor_output_cursor *output_ cursor_output_cursor_reset_image(output_cursor); - struct wlr_surface *surface = cur->state->surface; - if (surface != NULL) { + if (cur->state->buffer != NULL) { + struct wlr_renderer *renderer = output_cursor->output_cursor->output->renderer; + if (!renderer) { + return; + } + + struct wlr_buffer *buffer = cur->state->buffer; + int32_t hotspot_x = cur->state->buffer_hotspot.x; + int32_t hotspot_y = cur->state->buffer_hotspot.y; + float scale = cur->state->buffer_scale; + + struct wlr_texture *texture = NULL; + if (buffer != NULL) { + texture = wlr_texture_from_buffer(renderer, buffer); + if (texture == NULL) { + return; + } + } + + output_cursor_set_texture(output_cursor->output_cursor, texture, true, + scale, WL_OUTPUT_TRANSFORM_NORMAL, hotspot_x, hotspot_y); + } else if (cur->state->surface != NULL) { + struct wlr_surface *surface = cur->state->surface; + wl_signal_add(&output_cursor->output_cursor->output->events.commit, &output_cursor->output_commit); output_cursor->output_commit.notify = output_cursor_output_handle_output_commit;