Skip to content

Commit e95791a

Browse files
committed
Add pointer warping on wayland
1 parent 06faefc commit e95791a

File tree

7 files changed

+156
-13
lines changed

7 files changed

+156
-13
lines changed

platform/linuxbsd/wayland/SCsub

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ generated_sources = [
6969
generate_from_xml(
7070
"xdg_toplevel_icon", "#thirdparty/wayland-protocols/staging/xdg-toplevel-icon/xdg-toplevel-icon-v1.xml"
7171
),
72+
generate_from_xml("pointer_warp", "#thirdparty/wayland-protocols/staging/pointer-warp/pointer-warp-v1.xml"),
7273
# Unstable protocols
7374
generate_from_xml(
7475
"idle_inhibit", "#thirdparty/wayland-protocols/unstable/idle-inhibit/idle-inhibit-unstable-v1.xml"

platform/linuxbsd/wayland/display_server_wayland.cpp

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -449,20 +449,9 @@ bool DisplayServerWayland::mouse_is_mode_override_enabled() const {
449449
return mouse_mode_override_enabled;
450450
}
451451

452-
// NOTE: This is hacked together (and not guaranteed to work in the first place)
453-
// as for some reason the there's no proper way to ask the compositor to warp
454-
// the pointer, although, at the time of writing, there's a proposal for a
455-
// proper protocol for this. See:
456-
// https://gitlab.freedesktop.org/wayland/wayland-protocols/-/issues/158
457452
void DisplayServerWayland::warp_mouse(const Point2i &p_to) {
458453
MutexLock mutex_lock(wayland_thread.mutex);
459-
460-
WaylandThread::PointerConstraint old_constraint = wayland_thread.pointer_get_constraint();
461-
462-
wayland_thread.pointer_set_constraint(WaylandThread::PointerConstraint::LOCKED);
463-
wayland_thread.pointer_set_hint(p_to);
464-
465-
wayland_thread.pointer_set_constraint(old_constraint);
454+
wayland_thread.pointer_warp(p_to);
466455
}
467456

468457
Point2i DisplayServerWayland::mouse_get_position() const {

platform/linuxbsd/wayland/wayland_thread.cpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
#include "wayland_thread.h"
3232

3333
#include "core/config/engine.h"
34+
#include "wayland-egl-core.h"
35+
#include "wayland/protocol/pointer_warp.gen.h"
3436

3537
#ifdef WAYLAND_ENABLED
3638

@@ -659,6 +661,12 @@ void WaylandThread::_wl_registry_on_global(void *data, struct wl_registry *wl_re
659661
return;
660662
}
661663

664+
if (strcmp(interface, wp_pointer_warp_v1_interface.name) == 0) {
665+
registry->wp_pointer_warp = (struct wp_pointer_warp_v1 *)wl_registry_bind(wl_registry, name, &wp_pointer_warp_v1_interface, 1);
666+
registry->wp_pointer_warp_name = name;
667+
return;
668+
}
669+
662670
if (strcmp(interface, FIFO_INTERFACE_NAME) == 0) {
663671
registry->wp_fifo_manager_name = name;
664672
}
@@ -1023,6 +1031,17 @@ void WaylandThread::_wl_registry_on_global_remove(void *data, struct wl_registry
10231031
return;
10241032
}
10251033

1034+
if (name == registry->wp_pointer_warp_name) {
1035+
if (registry->wp_pointer_warp) {
1036+
wp_pointer_warp_v1_destroy(registry->wp_pointer_warp);
1037+
registry->wp_pointer_warp = nullptr;
1038+
}
1039+
1040+
registry->wp_pointer_warp_name = 0;
1041+
1042+
return;
1043+
}
1044+
10261045
{
10271046
// Iterate through all of the seats to find if any got removed.
10281047
List<struct wl_seat *>::Element *E = registry->wl_seats.front();
@@ -3374,6 +3393,15 @@ void WaylandThread::seat_state_set_hint(SeatState *p_ss, int p_x, int p_y) {
33743393
zwp_locked_pointer_v1_set_cursor_position_hint(p_ss->wp_locked_pointer, wl_fixed_from_int(p_x), wl_fixed_from_int(p_y));
33753394
}
33763395

3396+
void WaylandThread::seat_state_warp_pointer(SeatState *p_ss, int p_x, int p_y) {
3397+
if (registry.wp_pointer_warp == nullptr) {
3398+
return;
3399+
}
3400+
3401+
struct wl_surface *surface = window_get_wl_surface(p_ss->pointer_data.last_pointed_id);
3402+
wp_pointer_warp_v1_warp_pointer(registry.wp_pointer_warp, surface, p_ss->wl_pointer, wl_fixed_from_int(p_x), wl_fixed_from_int(p_y), p_ss->pointer_enter_serial);
3403+
}
3404+
33773405
void WaylandThread::seat_state_confine_pointer(SeatState *p_ss) {
33783406
ERR_FAIL_NULL(p_ss);
33793407

@@ -4400,6 +4428,44 @@ void WaylandThread::pointer_set_hint(const Point2i &p_hint) {
44004428
}
44014429
}
44024430

4431+
void WaylandThread::pointer_warp(const Point2i &p_to) {
4432+
// NOTE: This is for compositors that don't support the pointer-warp protocol.
4433+
// It's hacked together and not guaranteed to work.
4434+
if (registry.wp_pointer_warp == nullptr) {
4435+
PointerConstraint old_constraint = pointer_get_constraint();
4436+
4437+
pointer_set_constraint(PointerConstraint::LOCKED);
4438+
pointer_set_hint(p_to);
4439+
4440+
pointer_set_constraint(old_constraint);
4441+
4442+
return;
4443+
}
4444+
4445+
SeatState *ss = wl_seat_get_seat_state(wl_seat_current);
4446+
if (!ss) {
4447+
return;
4448+
}
4449+
4450+
WindowState *ws = window_get_state(ss->pointer_data.pointed_id);
4451+
4452+
int wl_pos_x = 0;
4453+
int wl_pos_y = 0;
4454+
4455+
if (ws) {
4456+
// NOTE: It looks like it's not really recommended to convert from
4457+
// "godot-space" to "wayland-space" and in general I received mixed feelings
4458+
// discussing about this. I'm not really sure about the maths behind this but,
4459+
// oh well, we're setting a cursor hint. ¯\_(ツ)_/¯
4460+
// See: https://oftc.irclog.whitequark.org/wayland/2023-08-23#1692756914-1692816818
4461+
wl_pos_x = std::round(p_to.x / window_state_get_scale_factor(ws));
4462+
wl_pos_y = std::round(p_to.y / window_state_get_scale_factor(ws));
4463+
}
4464+
4465+
if (ss) {
4466+
seat_state_warp_pointer(ss, wl_pos_x, wl_pos_y);
4467+
}
4468+
}
44034469
WaylandThread::PointerConstraint WaylandThread::pointer_get_constraint() const {
44044470
return pointer_constraint;
44054471
}

platform/linuxbsd/wayland/wayland_thread.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
#include "wayland/protocol/cursor_shape.gen.h"
5959
#include "wayland/protocol/pointer_constraints.gen.h"
6060
#include "wayland/protocol/pointer_gestures.gen.h"
61+
#include "wayland/protocol/pointer_warp.gen.h"
6162
#include "wayland/protocol/relative_pointer.gen.h"
6263
#undef pointer
6364
#include "wayland/protocol/fractional_scale.gen.h"
@@ -225,6 +226,9 @@ class WaylandThread {
225226
struct zwp_text_input_manager_v3 *wp_text_input_manager = nullptr;
226227
uint32_t wp_text_input_manager_name = 0;
227228

229+
struct wp_pointer_warp_v1 *wp_pointer_warp = nullptr;
230+
uint32_t wp_pointer_warp_name = 0;
231+
228232
// We're really not meant to use this one directly but we still need to know
229233
// whether it's available.
230234
uint32_t wp_fifo_manager_name = 0;
@@ -1012,6 +1016,7 @@ class WaylandThread {
10121016
void seat_state_unlock_pointer(SeatState *p_ss);
10131017
void seat_state_lock_pointer(SeatState *p_ss);
10141018
void seat_state_set_hint(SeatState *p_ss, int p_x, int p_y);
1019+
void seat_state_warp_pointer(SeatState *p_ss, int p_x, int p_y);
10151020
void seat_state_confine_pointer(SeatState *p_ss);
10161021

10171022
static void seat_state_update_cursor(SeatState *p_ss);
@@ -1070,6 +1075,7 @@ class WaylandThread {
10701075

10711076
void pointer_set_constraint(PointerConstraint p_constraint);
10721077
void pointer_set_hint(const Point2i &p_hint);
1078+
void pointer_warp(const Point2i &p_to);
10731079
PointerConstraint pointer_get_constraint() const;
10741080
DisplayServer::WindowID pointer_get_pointed_window_id() const;
10751081
DisplayServer::WindowID pointer_get_last_pointed_window_id() const;

thirdparty/README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1157,7 +1157,7 @@ Files extracted from upstream source:
11571157
# wayland-protocols
11581158

11591159
- Upstream: https://gitlab.freedesktop.org/wayland/wayland-protocols
1160-
- Version: 1.45 (54346071a5f211f2c482889f2c8ee3b5ecda63ab, 2025)
1160+
- Version: 1.45 (0091197f5c1b1f2c131f1410e99f9c95d50646be, 2025)
11611161
- License: MIT
11621162

11631163
Files extracted from upstream source:
@@ -1171,6 +1171,8 @@ Files extracted from upstream source:
11711171
- `staging/xdg-activation/README`
11721172
- `staging/xdg-activation/xdg-activation-v1.xml`
11731173
- `staging/xdg-system-bell/xdg-system-bell-v1.xml`
1174+
- `staging/pointer-warp/pointer-warp-v1.xml`
1175+
- `staging/pointer-warp/README`
11741176
- `unstable/idle-inhibit/README`
11751177
- `unstable/idle-inhibit/idle-inhibit-unstable-v1.xml`
11761178
- `unstable/pointer-constraints/README`
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
pointer-warp protocol
2+
3+
Maintainers:
4+
Neal Gompa <[email protected]> (@Conan_Kudo)
5+
Xaver Hugl <[email protected]> (@Zamundaaa)
6+
Matthias Klumpp <[email protected]> (@mak)
7+
Vlad Zahorodnii <[email protected]> (@zzag)
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<protocol name="pointer_warp_v1">
3+
<copyright>
4+
Copyright © 2024 Neal Gompa
5+
Copyright © 2024 Xaver Hugl
6+
Copyright © 2024 Matthias Klumpp
7+
Copyright © 2024 Vlad Zahorodnii
8+
9+
Permission is hereby granted, free of charge, to any person obtaining a
10+
copy of this software and associated documentation files (the "Software"),
11+
to deal in the Software without restriction, including without limitation
12+
the rights to use, copy, modify, merge, publish, distribute, sublicense,
13+
and/or sell copies of the Software, and to permit persons to whom the
14+
Software is furnished to do so, subject to the following conditions:
15+
The above copyright notice and this permission notice (including the next
16+
paragraph) shall be included in all copies or substantial portions of the
17+
Software.
18+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21+
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24+
DEALINGS IN THE SOFTWARE.
25+
</copyright>
26+
27+
<interface name="wp_pointer_warp_v1" version="1">
28+
<description summary="reposition the pointer to a location on a surface">
29+
This global interface allows applications to request the pointer to be
30+
moved to a position relative to a wl_surface.
31+
32+
Note that if the desired behavior is to constrain the pointer to an area
33+
or lock it to a position, this protocol does not provide a reliable way
34+
to do that. The pointer constraint and pointer lock protocols should be
35+
used for those use cases instead.
36+
37+
Warning! The protocol described in this file is currently in the testing
38+
phase. Backward compatible changes may be added together with the
39+
corresponding interface version bump. Backward incompatible changes can
40+
only be done by creating a new major version of the extension.
41+
</description>
42+
43+
<request name="destroy" type="destructor">
44+
<description summary="destroy the warp manager">
45+
Destroy the pointer warp manager.
46+
</description>
47+
</request>
48+
49+
<request name="warp_pointer">
50+
<description summary="reposition the pointer">
51+
Request the compositor to move the pointer to a surface-local position.
52+
Whether or not the compositor honors the request is implementation defined,
53+
but it should
54+
- honor it if the surface has pointer focus, including
55+
when it has an implicit pointer grab
56+
- reject it if the enter serial is incorrect
57+
- reject it if the requested position is outside of the surface
58+
59+
Note that the enter serial is valid for any surface of the client,
60+
and does not have to be from the surface the pointer is warped to.
61+
62+
</description>
63+
<arg name="surface" type="object" interface="wl_surface"
64+
summary="surface to position the pointer on"/>
65+
<arg name="pointer" type="object" interface="wl_pointer"
66+
summary="the pointer that should be repositioned"/>
67+
<arg name="x" type="fixed"/>
68+
<arg name="y" type="fixed"/>
69+
<arg name="serial" type="uint" summary="serial number of the enter event"/>
70+
</request>
71+
</interface>
72+
</protocol>

0 commit comments

Comments
 (0)