Add pointer warping on wayland
This commit is contained in:
@@ -69,6 +69,7 @@ generated_sources = [
|
||||
generate_from_xml(
|
||||
"xdg_toplevel_icon", "#thirdparty/wayland-protocols/staging/xdg-toplevel-icon/xdg-toplevel-icon-v1.xml"
|
||||
),
|
||||
generate_from_xml("pointer_warp", "#thirdparty/wayland-protocols/staging/pointer-warp/pointer-warp-v1.xml"),
|
||||
# Unstable protocols
|
||||
generate_from_xml(
|
||||
"idle_inhibit", "#thirdparty/wayland-protocols/unstable/idle-inhibit/idle-inhibit-unstable-v1.xml"
|
||||
|
||||
@@ -450,20 +450,9 @@ bool DisplayServerWayland::mouse_is_mode_override_enabled() const {
|
||||
return mouse_mode_override_enabled;
|
||||
}
|
||||
|
||||
// NOTE: This is hacked together (and not guaranteed to work in the first place)
|
||||
// as for some reason the there's no proper way to ask the compositor to warp
|
||||
// the pointer, although, at the time of writing, there's a proposal for a
|
||||
// proper protocol for this. See:
|
||||
// https://gitlab.freedesktop.org/wayland/wayland-protocols/-/issues/158
|
||||
void DisplayServerWayland::warp_mouse(const Point2i &p_to) {
|
||||
MutexLock mutex_lock(wayland_thread.mutex);
|
||||
|
||||
WaylandThread::PointerConstraint old_constraint = wayland_thread.pointer_get_constraint();
|
||||
|
||||
wayland_thread.pointer_set_constraint(WaylandThread::PointerConstraint::LOCKED);
|
||||
wayland_thread.pointer_set_hint(p_to);
|
||||
|
||||
wayland_thread.pointer_set_constraint(old_constraint);
|
||||
wayland_thread.pointer_warp(p_to);
|
||||
}
|
||||
|
||||
Point2i DisplayServerWayland::mouse_get_position() const {
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
#include "protocol/linux_explicit_synchronization_unstable_v1.gen.h"
|
||||
#include "protocol/pointer_constraints.gen.h"
|
||||
#include "protocol/pointer_gestures.gen.h"
|
||||
#include "protocol/pointer_warp.gen.h"
|
||||
#include "protocol/primary_selection.gen.h"
|
||||
#include "protocol/relative_pointer.gen.h"
|
||||
#include "protocol/tablet.gen.h"
|
||||
@@ -451,6 +452,9 @@ class WaylandEmbedder {
|
||||
&wp_tearing_control_manager_v1_interface,
|
||||
&wp_tearing_control_v1_interface,
|
||||
|
||||
// pointer-warp-v1
|
||||
&wp_pointer_warp_v1_interface,
|
||||
|
||||
// Our custom things.
|
||||
&godot_embedding_compositor_interface,
|
||||
&godot_embedded_client_interface,
|
||||
|
||||
@@ -726,6 +726,12 @@ void WaylandThread::_wl_registry_on_global(void *data, struct wl_registry *wl_re
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(interface, wp_pointer_warp_v1_interface.name) == 0) {
|
||||
registry->wp_pointer_warp = (struct wp_pointer_warp_v1 *)wl_registry_bind(wl_registry, name, &wp_pointer_warp_v1_interface, 1);
|
||||
registry->wp_pointer_warp_name = name;
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(interface, FIFO_INTERFACE_NAME) == 0) {
|
||||
registry->wp_fifo_manager_name = name;
|
||||
}
|
||||
@@ -1097,6 +1103,17 @@ void WaylandThread::_wl_registry_on_global_remove(void *data, struct wl_registry
|
||||
return;
|
||||
}
|
||||
|
||||
if (name == registry->wp_pointer_warp_name) {
|
||||
if (registry->wp_pointer_warp) {
|
||||
wp_pointer_warp_v1_destroy(registry->wp_pointer_warp);
|
||||
registry->wp_pointer_warp = nullptr;
|
||||
}
|
||||
|
||||
registry->wp_pointer_warp_name = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
// Iterate through all of the seats to find if any got removed.
|
||||
List<struct wl_seat *>::Element *E = registry->wl_seats.front();
|
||||
@@ -3661,6 +3678,21 @@ void WaylandThread::seat_state_set_hint(SeatState *p_ss, int p_x, int p_y) {
|
||||
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));
|
||||
}
|
||||
|
||||
void WaylandThread::seat_state_warp_pointer(SeatState *p_ss, int p_x, int p_y) {
|
||||
if (registry.wp_pointer_warp == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (p_ss->pointer_data.pointed_id == DisplayServer::INVALID_WINDOW_ID) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct wl_surface *surface = window_get_wl_surface(p_ss->pointer_data.pointed_id);
|
||||
ERR_FAIL_NULL(surface);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void WaylandThread::seat_state_confine_pointer(SeatState *p_ss) {
|
||||
ERR_FAIL_NULL(p_ss);
|
||||
|
||||
@@ -4724,25 +4756,60 @@ void WaylandThread::pointer_set_hint(const Point2i &p_hint) {
|
||||
}
|
||||
|
||||
WindowState *ws = window_get_state(ss->pointer_data.pointed_id);
|
||||
|
||||
int hint_x = 0;
|
||||
int hint_y = 0;
|
||||
|
||||
if (ws) {
|
||||
// NOTE: It looks like it's not really recommended to convert from
|
||||
// "godot-space" to "wayland-space" and in general I received mixed feelings
|
||||
// discussing about this. I'm not really sure about the maths behind this but,
|
||||
// oh well, we're setting a cursor hint. ¯\_(ツ)_/¯
|
||||
// See: https://oftc.irclog.whitequark.org/wayland/2023-08-23#1692756914-1692816818
|
||||
hint_x = std::round(p_hint.x / window_state_get_scale_factor(ws));
|
||||
hint_y = std::round(p_hint.y / window_state_get_scale_factor(ws));
|
||||
if (!ws) {
|
||||
return;
|
||||
}
|
||||
|
||||
// NOTE: It looks like it's not really recommended to convert from
|
||||
// "godot-space" to "wayland-space" and in general I received mixed feelings
|
||||
// discussing about this. I'm not really sure about the maths behind this but,
|
||||
// oh well, we're setting a cursor hint. ¯\_(ツ)_/¯
|
||||
// See: https://oftc.irclog.whitequark.org/wayland/2023-08-23#1692756914-1692816818
|
||||
int hint_x = Math::round(p_hint.x / window_state_get_scale_factor(ws));
|
||||
int hint_y = Math::round(p_hint.y / window_state_get_scale_factor(ws));
|
||||
|
||||
if (ss) {
|
||||
seat_state_set_hint(ss, hint_x, hint_y);
|
||||
}
|
||||
}
|
||||
|
||||
void WaylandThread::pointer_warp(const Point2i &p_to) {
|
||||
// NOTE: This is for compositors that don't support the pointer-warp protocol.
|
||||
// It's hacked together and not guaranteed to work.
|
||||
if (registry.wp_pointer_warp == nullptr) {
|
||||
PointerConstraint old_constraint = pointer_get_constraint();
|
||||
|
||||
pointer_set_constraint(PointerConstraint::LOCKED);
|
||||
pointer_set_hint(p_to);
|
||||
|
||||
pointer_set_constraint(old_constraint);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
SeatState *ss = wl_seat_get_seat_state(wl_seat_current);
|
||||
if (!ss) {
|
||||
return;
|
||||
}
|
||||
|
||||
WindowState *ws = window_get_state(ss->pointer_data.pointed_id);
|
||||
if (!ws) {
|
||||
return;
|
||||
}
|
||||
|
||||
// NOTE: It looks like it's not really recommended to convert from
|
||||
// "godot-space" to "wayland-space" and in general I received mixed feelings
|
||||
// discussing about this. I'm not really sure about the maths behind this but,
|
||||
// oh well. ¯\_(ツ)_/¯
|
||||
// See: https://oftc.irclog.whitequark.org/wayland/2023-08-23#1692756914-1692816818
|
||||
int wl_pos_x = Math::round(p_to.x / window_state_get_scale_factor(ws));
|
||||
int wl_pos_y = Math::round(p_to.y / window_state_get_scale_factor(ws));
|
||||
|
||||
if (ss) {
|
||||
seat_state_warp_pointer(ss, wl_pos_x, wl_pos_y);
|
||||
}
|
||||
}
|
||||
|
||||
WaylandThread::PointerConstraint WaylandThread::pointer_get_constraint() const {
|
||||
return pointer_constraint;
|
||||
}
|
||||
@@ -5608,6 +5675,10 @@ void WaylandThread::destroy() {
|
||||
zwp_relative_pointer_manager_v1_destroy(registry.wp_relative_pointer_manager);
|
||||
}
|
||||
|
||||
if (registry.wp_pointer_warp) {
|
||||
wp_pointer_warp_v1_destroy(registry.wp_pointer_warp);
|
||||
}
|
||||
|
||||
if (registry.xdg_activation) {
|
||||
xdg_activation_v1_destroy(registry.xdg_activation);
|
||||
}
|
||||
|
||||
@@ -59,6 +59,7 @@
|
||||
#include "wayland/protocol/cursor_shape.gen.h"
|
||||
#include "wayland/protocol/pointer_constraints.gen.h"
|
||||
#include "wayland/protocol/pointer_gestures.gen.h"
|
||||
#include "wayland/protocol/pointer_warp.gen.h"
|
||||
#include "wayland/protocol/relative_pointer.gen.h"
|
||||
#undef pointer
|
||||
#include "wayland/protocol/fractional_scale.gen.h"
|
||||
@@ -230,6 +231,9 @@ public:
|
||||
struct zwp_text_input_manager_v3 *wp_text_input_manager = nullptr;
|
||||
uint32_t wp_text_input_manager_name = 0;
|
||||
|
||||
struct wp_pointer_warp_v1 *wp_pointer_warp = nullptr;
|
||||
uint32_t wp_pointer_warp_name = 0;
|
||||
|
||||
// We're really not meant to use this one directly but we still need to know
|
||||
// whether it's available.
|
||||
uint32_t wp_fifo_manager_name = 0;
|
||||
@@ -1085,6 +1089,7 @@ public:
|
||||
void seat_state_unlock_pointer(SeatState *p_ss);
|
||||
void seat_state_lock_pointer(SeatState *p_ss);
|
||||
void seat_state_set_hint(SeatState *p_ss, int p_x, int p_y);
|
||||
void seat_state_warp_pointer(SeatState *p_ss, int p_x, int p_y);
|
||||
void seat_state_confine_pointer(SeatState *p_ss);
|
||||
|
||||
static void seat_state_update_cursor(SeatState *p_ss);
|
||||
@@ -1145,6 +1150,7 @@ public:
|
||||
|
||||
void pointer_set_constraint(PointerConstraint p_constraint);
|
||||
void pointer_set_hint(const Point2i &p_hint);
|
||||
void pointer_warp(const Point2i &p_to);
|
||||
PointerConstraint pointer_get_constraint() const;
|
||||
DisplayServer::WindowID pointer_get_pointed_window_id() const;
|
||||
DisplayServer::WindowID pointer_get_last_pointed_window_id() const;
|
||||
|
||||
Vendored
+2
@@ -1200,6 +1200,8 @@ Files extracted from upstream source:
|
||||
- `staging/xdg-activation/README`
|
||||
- `staging/xdg-activation/xdg-activation-v1.xml`
|
||||
- `staging/xdg-system-bell/xdg-system-bell-v1.xml`
|
||||
- `staging/pointer-warp/pointer-warp-v1.xml`
|
||||
- `staging/pointer-warp/README`
|
||||
- `unstable/idle-inhibit/README`
|
||||
- `unstable/idle-inhibit/idle-inhibit-unstable-v1.xml`
|
||||
- `unstable/pointer-constraints/README`
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
pointer-warp protocol
|
||||
|
||||
Maintainers:
|
||||
Neal Gompa <neal@gompa.dev> (@Conan_Kudo)
|
||||
Xaver Hugl <xaver.hugl@kde.org> (@Zamundaaa)
|
||||
Matthias Klumpp <matthias@tenstral.net> (@mak)
|
||||
Vlad Zahorodnii <vlad.zahorodnii@kde.org> (@zzag)
|
||||
@@ -0,0 +1,72 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<protocol name="pointer_warp_v1">
|
||||
<copyright>
|
||||
Copyright © 2024 Neal Gompa
|
||||
Copyright © 2024 Xaver Hugl
|
||||
Copyright © 2024 Matthias Klumpp
|
||||
Copyright © 2024 Vlad Zahorodnii
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice (including the next
|
||||
paragraph) shall be included in all copies or substantial portions of the
|
||||
Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
</copyright>
|
||||
|
||||
<interface name="wp_pointer_warp_v1" version="1">
|
||||
<description summary="reposition the pointer to a location on a surface">
|
||||
This global interface allows applications to request the pointer to be
|
||||
moved to a position relative to a wl_surface.
|
||||
|
||||
Note that if the desired behavior is to constrain the pointer to an area
|
||||
or lock it to a position, this protocol does not provide a reliable way
|
||||
to do that. The pointer constraint and pointer lock protocols should be
|
||||
used for those use cases instead.
|
||||
|
||||
Warning! The protocol described in this file is currently in the testing
|
||||
phase. Backward compatible changes may be added together with the
|
||||
corresponding interface version bump. Backward incompatible changes can
|
||||
only be done by creating a new major version of the extension.
|
||||
</description>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="destroy the warp manager">
|
||||
Destroy the pointer warp manager.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<request name="warp_pointer">
|
||||
<description summary="reposition the pointer">
|
||||
Request the compositor to move the pointer to a surface-local position.
|
||||
Whether or not the compositor honors the request is implementation defined,
|
||||
but it should
|
||||
- honor it if the surface has pointer focus, including
|
||||
when it has an implicit pointer grab
|
||||
- reject it if the enter serial is incorrect
|
||||
- reject it if the requested position is outside of the surface
|
||||
|
||||
Note that the enter serial is valid for any surface of the client,
|
||||
and does not have to be from the surface the pointer is warped to.
|
||||
|
||||
</description>
|
||||
<arg name="surface" type="object" interface="wl_surface"
|
||||
summary="surface to position the pointer on"/>
|
||||
<arg name="pointer" type="object" interface="wl_pointer"
|
||||
summary="the pointer that should be repositioned"/>
|
||||
<arg name="x" type="fixed"/>
|
||||
<arg name="y" type="fixed"/>
|
||||
<arg name="serial" type="uint" summary="serial number of the enter event"/>
|
||||
</request>
|
||||
</interface>
|
||||
</protocol>
|
||||
Reference in New Issue
Block a user