Skip to content

Commit c15cd3a

Browse files
committed
Wayland: Simplify cursor code and fix custom cursors
Initially the WaylandThread cursor code was supposed to be as stateless as possible but, as time went on, this wasn't possible. This expectation made the resulting API quite convoluted, so this patch aims to simplify it substantially bot in terms of API surface and, most importantly, in terms of actual implementation complexity. This patch also fixes custom cursors since I accidentally changed the mmap flags to MAP_PRIVATE some time ago. This took me hours to notice.
1 parent 74de05a commit c15cd3a

File tree

3 files changed

+59
-93
lines changed

3 files changed

+59
-93
lines changed

platform/linuxbsd/wayland/display_server_wayland.cpp

Lines changed: 7 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -327,15 +327,7 @@ void DisplayServerWayland::mouse_set_mode(MouseMode p_mode) {
327327

328328
bool show_cursor = (p_mode == MOUSE_MODE_VISIBLE || p_mode == MOUSE_MODE_CONFINED);
329329

330-
if (show_cursor) {
331-
if (custom_cursors.has(cursor_shape)) {
332-
wayland_thread.cursor_set_custom_shape(cursor_shape);
333-
} else {
334-
wayland_thread.cursor_set_shape(cursor_shape);
335-
}
336-
} else {
337-
wayland_thread.cursor_hide();
338-
}
330+
wayland_thread.cursor_set_visible(show_cursor);
339331

340332
WaylandThread::PointerConstraint constraint = WaylandThread::PointerConstraint::NONE;
341333

@@ -993,11 +985,7 @@ void DisplayServerWayland::cursor_set_shape(CursorShape p_shape) {
993985
return;
994986
}
995987

996-
if (custom_cursors.has(p_shape)) {
997-
wayland_thread.cursor_set_custom_shape(p_shape);
998-
} else {
999-
wayland_thread.cursor_set_shape(p_shape);
1000-
}
988+
wayland_thread.cursor_set_shape(p_shape);
1001989
}
1002990

1003991
DisplayServerWayland::CursorShape DisplayServerWayland::cursor_get_shape() const {
@@ -1009,18 +997,13 @@ DisplayServerWayland::CursorShape DisplayServerWayland::cursor_get_shape() const
1009997
void DisplayServerWayland::cursor_set_custom_image(const Ref<Resource> &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
1010998
MutexLock mutex_lock(wayland_thread.mutex);
1011999

1012-
bool visible = (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED);
1013-
10141000
if (p_cursor.is_valid()) {
10151001
HashMap<CursorShape, CustomCursor>::Iterator cursor_c = custom_cursors.find(p_shape);
10161002

10171003
if (cursor_c) {
10181004
if (cursor_c->value.rid == p_cursor->get_rid() && cursor_c->value.hotspot == p_hotspot) {
10191005
// We have a cached cursor. Nice.
1020-
if (visible) {
1021-
wayland_thread.cursor_set_custom_shape(p_shape);
1022-
}
1023-
1006+
wayland_thread.cursor_set_shape(p_shape);
10241007
return;
10251008
}
10261009

@@ -1039,20 +1022,18 @@ void DisplayServerWayland::cursor_set_custom_image(const Ref<Resource> &p_cursor
10391022

10401023
wayland_thread.cursor_shape_set_custom_image(p_shape, image, p_hotspot);
10411024

1042-
if (visible) {
1043-
wayland_thread.cursor_set_custom_shape(p_shape);
1044-
}
1025+
wayland_thread.cursor_set_shape(p_shape);
10451026
} else {
10461027
// Clear cache and reset to default system cursor.
1047-
if (cursor_shape == p_shape && visible) {
1028+
wayland_thread.cursor_shape_clear_custom_image(p_shape);
1029+
1030+
if (cursor_shape == p_shape) {
10481031
wayland_thread.cursor_set_shape(p_shape);
10491032
}
10501033

10511034
if (custom_cursors.has(p_shape)) {
10521035
custom_cursors.erase(p_shape);
10531036
}
1054-
1055-
wayland_thread.cursor_shape_clear_custom_image(p_shape);
10561037
}
10571038
}
10581039

platform/linuxbsd/wayland/wayland_thread.cpp

Lines changed: 49 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -265,8 +265,6 @@ bool WaylandThread::_load_cursor_theme(int p_cursor_size) {
265265
if (wl_cursor_theme) {
266266
wl_cursor_theme_destroy(wl_cursor_theme);
267267
wl_cursor_theme = nullptr;
268-
269-
current_wl_cursor = nullptr;
270268
}
271269

272270
if (cursor_theme_name.is_empty()) {
@@ -357,7 +355,12 @@ void WaylandThread::_update_scale(int p_scale) {
357355
int cursor_size = unscaled_cursor_size * p_scale;
358356

359357
if (_load_cursor_theme(cursor_size)) {
360-
cursor_set_shape(last_cursor_shape);
358+
for (struct wl_seat *wl_seat : registry.wl_seats) {
359+
SeatState *ss = wl_seat_get_seat_state(wl_seat);
360+
ERR_FAIL_NULL(ss);
361+
362+
seat_state_update_cursor(ss);
363+
}
361364
}
362365
}
363366

@@ -3074,19 +3077,25 @@ void WaylandThread::seat_state_confine_pointer(SeatState *p_ss) {
30743077

30753078
void WaylandThread::seat_state_update_cursor(SeatState *p_ss) {
30763079
ERR_FAIL_NULL(p_ss);
3080+
3081+
WaylandThread *thread = p_ss->wayland_thread;
30773082
ERR_FAIL_NULL(p_ss->wayland_thread);
30783083

3079-
if (p_ss->wl_pointer && p_ss->cursor_surface) {
3080-
// NOTE: Those values are valid by default and will hide the cursor when
3081-
// unchanged, which happens when both the current custom cursor and the
3082-
// current wl_cursor are `nullptr`.
3083-
struct wl_buffer *cursor_buffer = nullptr;
3084-
uint32_t hotspot_x = 0;
3085-
uint32_t hotspot_y = 0;
3086-
int scale = 1;
3084+
if (!p_ss->wl_pointer || !p_ss->cursor_surface) {
3085+
return;
3086+
}
3087+
3088+
// NOTE: Those values are valid by default and will hide the cursor when
3089+
// unchanged.
3090+
struct wl_buffer *cursor_buffer = nullptr;
3091+
uint32_t hotspot_x = 0;
3092+
uint32_t hotspot_y = 0;
3093+
int scale = 1;
30873094

3088-
CustomCursor *custom_cursor = p_ss->wayland_thread->current_custom_cursor;
3089-
struct wl_cursor *wl_cursor = p_ss->wayland_thread->current_wl_cursor;
3095+
if (thread->cursor_visible) {
3096+
DisplayServer::CursorShape shape = thread->cursor_shape;
3097+
3098+
struct CustomCursor *custom_cursor = thread->custom_cursors.getptr(shape);
30903099

30913100
if (custom_cursor) {
30923101
cursor_buffer = custom_cursor->wl_buffer;
@@ -3096,7 +3105,13 @@ void WaylandThread::seat_state_update_cursor(SeatState *p_ss) {
30963105
// We can't really reasonably scale custom cursors, so we'll let the
30973106
// compositor do it for us (badly).
30983107
scale = 1;
3099-
} else if (wl_cursor) {
3108+
} else {
3109+
struct wl_cursor *wl_cursor = thread->wl_cursors[shape];
3110+
3111+
if (!wl_cursor) {
3112+
return;
3113+
}
3114+
31003115
int frame_idx = 0;
31013116

31023117
if (wl_cursor->image_count > 1) {
@@ -3112,24 +3127,24 @@ void WaylandThread::seat_state_update_cursor(SeatState *p_ss) {
31123127

31133128
struct wl_cursor_image *wl_cursor_image = wl_cursor->images[frame_idx];
31143129

3115-
scale = p_ss->wayland_thread->cursor_scale;
3130+
scale = thread->cursor_scale;
31163131

31173132
cursor_buffer = wl_cursor_image_get_buffer(wl_cursor_image);
31183133

31193134
// As the surface's buffer is scaled (thus the surface is smaller) and the
31203135
// hotspot must be expressed in surface-local coordinates, we need to scale
3121-
// them down accordingly.
3136+
// it down accordingly.
31223137
hotspot_x = wl_cursor_image->hotspot_x / scale;
31233138
hotspot_y = wl_cursor_image->hotspot_y / scale;
31243139
}
3140+
}
31253141

3126-
wl_pointer_set_cursor(p_ss->wl_pointer, p_ss->pointer_enter_serial, p_ss->cursor_surface, hotspot_x, hotspot_y);
3127-
wl_surface_set_buffer_scale(p_ss->cursor_surface, scale);
3128-
wl_surface_attach(p_ss->cursor_surface, cursor_buffer, 0, 0);
3129-
wl_surface_damage_buffer(p_ss->cursor_surface, 0, 0, INT_MAX, INT_MAX);
3142+
wl_pointer_set_cursor(p_ss->wl_pointer, p_ss->pointer_enter_serial, p_ss->cursor_surface, hotspot_x, hotspot_y);
3143+
wl_surface_set_buffer_scale(p_ss->cursor_surface, scale);
3144+
wl_surface_attach(p_ss->cursor_surface, cursor_buffer, 0, 0);
3145+
wl_surface_damage_buffer(p_ss->cursor_surface, 0, 0, INT_MAX, INT_MAX);
31303146

3131-
wl_surface_commit(p_ss->cursor_surface);
3132-
}
3147+
wl_surface_commit(p_ss->cursor_surface);
31333148
}
31343149

31353150
void WaylandThread::seat_state_echo_keys(SeatState *p_ss) {
@@ -3770,49 +3785,26 @@ Error WaylandThread::init() {
37703785
return OK;
37713786
}
37723787

3773-
void WaylandThread::cursor_hide() {
3774-
current_wl_cursor = nullptr;
3775-
current_custom_cursor = nullptr;
3776-
3777-
SeatState *ss = wl_seat_get_seat_state(wl_seat_current);
3778-
ERR_FAIL_NULL(ss);
3779-
seat_state_update_cursor(ss);
3780-
}
3781-
3782-
void WaylandThread::cursor_set_shape(DisplayServer::CursorShape p_cursor_shape) {
3783-
if (!wl_cursors[p_cursor_shape]) {
3784-
return;
3785-
}
3786-
3787-
// The point of this method is make the current cursor a "plain" shape and, as
3788-
// the custom cursor overrides what gets set, we have to clear it too.
3789-
current_custom_cursor = nullptr;
3790-
3791-
current_wl_cursor = wl_cursors[p_cursor_shape];
3788+
void WaylandThread::cursor_set_visible(bool p_visible) {
3789+
cursor_visible = p_visible;
37923790

37933791
for (struct wl_seat *wl_seat : registry.wl_seats) {
37943792
SeatState *ss = wl_seat_get_seat_state(wl_seat);
37953793
ERR_FAIL_NULL(ss);
37963794

37973795
seat_state_update_cursor(ss);
37983796
}
3799-
3800-
last_cursor_shape = p_cursor_shape;
38013797
}
38023798

3803-
void WaylandThread::cursor_set_custom_shape(DisplayServer::CursorShape p_cursor_shape) {
3804-
ERR_FAIL_COND(!custom_cursors.has(p_cursor_shape));
3805-
3806-
current_custom_cursor = &custom_cursors[p_cursor_shape];
3799+
void WaylandThread::cursor_set_shape(DisplayServer::CursorShape p_cursor_shape) {
3800+
cursor_shape = p_cursor_shape;
38073801

38083802
for (struct wl_seat *wl_seat : registry.wl_seats) {
38093803
SeatState *ss = wl_seat_get_seat_state(wl_seat);
38103804
ERR_FAIL_NULL(ss);
38113805

38123806
seat_state_update_cursor(ss);
38133807
}
3814-
3815-
last_cursor_shape = p_cursor_shape;
38163808
}
38173809

38183810
void WaylandThread::cursor_shape_set_custom_image(DisplayServer::CursorShape p_cursor_shape, Ref<Image> p_image, const Point2i &p_hotspot) {
@@ -3832,23 +3824,21 @@ void WaylandThread::cursor_shape_set_custom_image(DisplayServer::CursorShape p_c
38323824
CustomCursor &cursor = custom_cursors[p_cursor_shape];
38333825
cursor.hotspot = p_hotspot;
38343826

3827+
if (cursor.wl_buffer) {
3828+
// Clean up the old Wayland buffer.
3829+
wl_buffer_destroy(cursor.wl_buffer);
3830+
}
3831+
38353832
if (cursor.buffer_data) {
38363833
// Clean up the old buffer data.
38373834
munmap(cursor.buffer_data, cursor.buffer_data_size);
38383835
}
38393836

3840-
// NOTE: From `wl_keyboard`s of version 7 or later, the spec requires the mmap
3841-
// operation to be done with MAP_PRIVATE, as "MAP_SHARED may fail". We'll do it
3842-
// regardless of global version.
3843-
cursor.buffer_data = (uint32_t *)mmap(nullptr, data_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
3844-
3845-
if (cursor.wl_buffer) {
3846-
// Clean up the old Wayland buffer.
3847-
wl_buffer_destroy(cursor.wl_buffer);
3848-
}
3837+
cursor.buffer_data = (uint32_t *)mmap(nullptr, data_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
3838+
cursor.buffer_data_size = data_size;
38493839

38503840
// Create the Wayland buffer.
3851-
struct wl_shm_pool *wl_shm_pool = wl_shm_create_pool(registry.wl_shm, fd, image_size.height * data_size);
3841+
struct wl_shm_pool *wl_shm_pool = wl_shm_create_pool(registry.wl_shm, fd, data_size);
38523842
// TODO: Make sure that WL_SHM_FORMAT_ARGB8888 format is supported. It
38533843
// technically isn't garaunteed to be supported, but I think that'd be a
38543844
// pretty unlikely thing to stumble upon.
@@ -3876,8 +3866,6 @@ void WaylandThread::cursor_shape_clear_custom_image(DisplayServer::CursorShape p
38763866
CustomCursor cursor = custom_cursors[p_cursor_shape];
38773867
custom_cursors.erase(p_cursor_shape);
38783868

3879-
current_custom_cursor = nullptr;
3880-
38813869
if (cursor.wl_buffer) {
38823870
wl_buffer_destroy(cursor.wl_buffer);
38833871
}

platform/linuxbsd/wayland/wayland_thread.h

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,6 @@ class WaylandThread {
469469
uint32_t *buffer_data = nullptr;
470470
uint32_t buffer_data_size = 0;
471471

472-
RID rid;
473472
Point2i hotspot;
474473
};
475474

@@ -506,10 +505,8 @@ class WaylandThread {
506505

507506
HashMap<DisplayServer::CursorShape, CustomCursor> custom_cursors;
508507

509-
struct wl_cursor *current_wl_cursor = nullptr;
510-
struct CustomCursor *current_custom_cursor = nullptr;
511-
512-
DisplayServer::CursorShape last_cursor_shape = DisplayServer::CURSOR_ARROW;
508+
DisplayServer::CursorShape cursor_shape = DisplayServer::CURSOR_ARROW;
509+
bool cursor_visible = true;
513510

514511
PointerConstraint pointer_constraint = PointerConstraint::NONE;
515512

@@ -962,7 +959,7 @@ class WaylandThread {
962959
DisplayServer::WindowID pointer_get_pointed_window_id() const;
963960
BitField<MouseButtonMask> pointer_get_button_mask() const;
964961

965-
void cursor_hide();
962+
void cursor_set_visible(bool p_visible);
966963
void cursor_set_shape(DisplayServer::CursorShape p_cursor_shape);
967964

968965
void cursor_set_custom_shape(DisplayServer::CursorShape p_cursor_shape);

0 commit comments

Comments
 (0)