diff --git a/include/types/wlr_output.h b/include/types/wlr_output.h index 253f116a4..58b547810 100644 --- a/include/types/wlr_output.h +++ b/include/types/wlr_output.h @@ -17,6 +17,9 @@ bool output_ensure_buffer(struct wlr_output *output, bool output_cursor_set_texture(struct wlr_output_cursor *cursor, struct wlr_texture *texture, bool own_texture, float scale, enum wl_output_transform transform, int32_t hotspot_x, int32_t hotspot_y); +bool output_get_cursor_layer_state(struct wlr_output *output, + struct wlr_buffer *buffer, int x, int y, int hotspot_x, int hotspot_y, + struct wlr_output_layer_state *out); struct wlr_output_layer_state *output_state_get_cursor_layer( const struct wlr_output_state *state); diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index f3ed7c105..1d0ecdff8 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -189,6 +189,8 @@ struct wlr_output { struct wlr_swapchain *cursor_swapchain; struct wlr_buffer *cursor_front_buffer; int software_cursor_locks; // number of locks forcing software cursors + struct wlr_output_layer *cursor_layer; + bool cursor_layer_changed; struct wl_list layers; // wlr_output_layer.link diff --git a/types/output/cursor.c b/types/output/cursor.c index eb6ac6f2c..aed7d5ccb 100644 --- a/types/output/cursor.c +++ b/types/output/cursor.c @@ -6,19 +6,72 @@ #include #include #include +#include #include #include #include "render/allocator/allocator.h" #include "types/wlr_buffer.h" #include "types/wlr_output.h" -static bool output_set_hardware_cursor(struct wlr_output *output, +bool output_get_cursor_layer_state(struct wlr_output *output, + struct wlr_buffer *buffer, int x, int y, int hotspot_x, int hotspot_y, + struct wlr_output_layer_state *out) { + if (output->cursor_layer == NULL) { + output->cursor_layer = wlr_output_layer_create(output); + if (output->cursor_layer == NULL) { + return false; + } + output->cursor_layer->cursor = true; + } + + *out = (struct wlr_output_layer_state){ + .layer = output->cursor_layer, + .buffer = buffer, + .dst_box = { + .x = x, + .y = y, + .width = buffer->width, + .height = buffer->height, + }, + .cursor_hotspot = { + .x = hotspot_x, + .y = hotspot_y, + }, + }; + return true; +} + +static bool output_test_hardware_cursor_layer(struct wlr_output *output, struct wlr_buffer *buffer, int hotspot_x, int hotspot_y) { - if (!output->impl->set_cursor) { + if (buffer == NULL) { + return true; + } + if (!output->impl->test) { return false; } - if (!output->impl->set_cursor(output, buffer, hotspot_x, hotspot_y)) { + struct wlr_output_layer_state layer_state = {0}; + if (!output_get_cursor_layer_state(output, buffer, 0, 0, hotspot_x, hotspot_y, &layer_state)) { + return false; + } + + struct wlr_output_state output_state = { + .committed = WLR_OUTPUT_STATE_LAYERS, + .layers = &layer_state, + .layers_len = 1, + }; + return output->impl->test(output, &output_state) && layer_state.accepted; +} + +static bool output_set_hardware_cursor(struct wlr_output *output, + struct wlr_buffer *buffer, int hotspot_x, int hotspot_y) { + bool ok; + if (!output->impl->set_cursor) { + ok = output_test_hardware_cursor_layer(output, buffer, hotspot_x, hotspot_y); + } else { + ok = output->impl->set_cursor(output, buffer, hotspot_x, hotspot_y); + } + if (!ok) { return false; } @@ -29,6 +82,11 @@ static bool output_set_hardware_cursor(struct wlr_output *output, output->cursor_front_buffer = wlr_buffer_lock(buffer); } + if (!output->impl->set_cursor) { + output->cursor_layer_changed = true; + wlr_output_update_needs_frame(output); + } + return true; } @@ -348,8 +406,7 @@ static struct wlr_buffer *render_cursor_buffer(struct wlr_output_cursor *cursor) static bool output_cursor_attempt_hardware(struct wlr_output_cursor *cursor) { struct wlr_output *output = cursor->output; - if (!output->impl->set_cursor || - output->software_cursor_locks > 0) { + if (output->software_cursor_locks > 0) { return false; } @@ -362,8 +419,9 @@ static bool output_cursor_attempt_hardware(struct wlr_output_cursor *cursor) { // If the cursor was hidden or was a software cursor, the hardware // cursor position is outdated - output->impl->move_cursor(cursor->output, - (int)cursor->x, (int)cursor->y); + if (output->impl->move_cursor) { + output->impl->move_cursor(cursor->output, (int)cursor->x, (int)cursor->y); + } struct wlr_buffer *buffer = NULL; if (texture != NULL) { @@ -485,7 +543,11 @@ bool wlr_output_cursor_move(struct wlr_output_cursor *cursor, return true; } - assert(cursor->output->impl->move_cursor); + if (!cursor->output->impl->move_cursor) { + cursor->output->cursor_layer_changed = true; + wlr_output_update_needs_frame(cursor->output); + return true; + } return cursor->output->impl->move_cursor(cursor->output, (int)x, (int)y); } diff --git a/types/output/output.c b/types/output/output.c index 7ec05fcd4..59f139dd3 100644 --- a/types/output/output.c +++ b/types/output/output.c @@ -660,11 +660,28 @@ static bool output_basic_test(struct wlr_output *output, } static bool output_prepare_state(struct wlr_output *output, - struct wlr_output_state *state, bool *new_buffer) { + struct wlr_output_state *state, bool *new_buffer, + struct wlr_output_layer_state *cursor_state) { if (!output_ensure_buffer(output, state, new_buffer)) { return false; } + if (output->hardware_cursor != NULL && output->impl->set_cursor == NULL && + output->cursor_layer_changed) { + assert(output->cursor_layer != NULL); + + struct wlr_output_cursor *cursor = output->hardware_cursor; + if (!output_get_cursor_layer_state(output, output->cursor_front_buffer, + cursor->x, cursor->y, cursor->hotspot_x, cursor->hotspot_y, cursor_state)) { + return false; + } + + assert((state->committed & WLR_OUTPUT_STATE_LAYERS) == 0); + state->committed |= WLR_OUTPUT_STATE_LAYERS; + state->layers = cursor_state; + state->layers_len = 1; + } + return true; } @@ -685,7 +702,8 @@ bool wlr_output_test_state(struct wlr_output *output, } bool new_back_buffer = false; - if (!output_prepare_state(output, ©, &new_back_buffer)) { + struct wlr_output_layer_state cursor_state; + if (!output_prepare_state(output, ©, &new_back_buffer, &cursor_state)) { return false; } @@ -723,7 +741,8 @@ bool wlr_output_commit_state(struct wlr_output *output, } bool new_back_buffer = false; - if (!output_prepare_state(output, &pending, &new_back_buffer)) { + struct wlr_output_layer_state cursor_state; + if (!output_prepare_state(output, &pending, &new_back_buffer, &cursor_state)) { return false; } @@ -837,6 +856,8 @@ bool wlr_output_commit_state(struct wlr_output *output, } } + output->cursor_layer_changed = false; + struct wlr_output_event_commit event = { .output = output, .committed = pending.committed,