mirror of
https://github.com/libsdl-org/SDL.git
synced 2025-09-06 03:18:13 +00:00
wayland: Enable relative pointer mode based on the window flag
This can be toggled per-window, so use the individual window flags instead of the global toggle to selectively enable it only for the relevant window in a multi-seat scenario, as is already done with keyboard and pointer grabs.
This commit is contained in:
@@ -1314,8 +1314,9 @@ static void SDL_MaybeEnableWarpEmulation(SDL_Window *window, float x, float y)
|
|||||||
// Require two consecutive warps to the center within a certain timespan to enter warp emulation mode.
|
// Require two consecutive warps to the center within a certain timespan to enter warp emulation mode.
|
||||||
const Uint64 now = SDL_GetTicksNS();
|
const Uint64 now = SDL_GetTicksNS();
|
||||||
if (now - mouse->last_center_warp_time_ns < WARP_EMULATION_THRESHOLD_NS) {
|
if (now - mouse->last_center_warp_time_ns < WARP_EMULATION_THRESHOLD_NS) {
|
||||||
if (SDL_SetRelativeMouseMode(true)) {
|
|
||||||
mouse->warp_emulation_active = true;
|
mouse->warp_emulation_active = true;
|
||||||
|
if (!SDL_SetRelativeMouseMode(true)) {
|
||||||
|
mouse->warp_emulation_active = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -912,7 +912,7 @@ static void pointer_handle_button_common(SDL_WaylandSeat *seat, uint32_t serial,
|
|||||||
*
|
*
|
||||||
* The mouse is not captured in relative mode.
|
* The mouse is not captured in relative mode.
|
||||||
*/
|
*/
|
||||||
if (!seat->display->relative_mode_enabled || !Wayland_SeatHasRelativePointerFocus(seat)) {
|
if (!seat->pointer.relative_pointer) {
|
||||||
if (seat->pointer.buttons_pressed != 0) {
|
if (seat->pointer.buttons_pressed != 0) {
|
||||||
window->sdlwindow->flags |= SDL_WINDOW_MOUSE_CAPTURE;
|
window->sdlwindow->flags |= SDL_WINDOW_MOUSE_CAPTURE;
|
||||||
} else {
|
} else {
|
||||||
@@ -1164,12 +1164,7 @@ static void relative_pointer_handle_relative_motion(void *data,
|
|||||||
wl_fixed_t dy_unaccel_w)
|
wl_fixed_t dy_unaccel_w)
|
||||||
{
|
{
|
||||||
SDL_WaylandSeat *seat = data;
|
SDL_WaylandSeat *seat = data;
|
||||||
|
|
||||||
if (seat->display->relative_mode_enabled) {
|
|
||||||
SDL_WindowData *window = seat->pointer.focus;
|
SDL_WindowData *window = seat->pointer.focus;
|
||||||
|
|
||||||
// Relative motion follows keyboard focus.
|
|
||||||
if (Wayland_SeatHasRelativePointerFocus(seat)) {
|
|
||||||
SDL_Mouse *mouse = SDL_GetMouse();
|
SDL_Mouse *mouse = SDL_GetMouse();
|
||||||
|
|
||||||
// Relative pointer event times are in microsecond granularity.
|
// Relative pointer event times are in microsecond granularity.
|
||||||
@@ -1187,8 +1182,6 @@ static void relative_pointer_handle_relative_motion(void *data,
|
|||||||
|
|
||||||
SDL_SendMouseMotion(timestamp, window->sdlwindow, seat->pointer.sdl_id, true, (float)dx, (float)dy);
|
SDL_SendMouseMotion(timestamp, window->sdlwindow, seat->pointer.sdl_id, true, (float)dx, (float)dy);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct zwp_relative_pointer_v1_listener relative_pointer_listener = {
|
static const struct zwp_relative_pointer_v1_listener relative_pointer_listener = {
|
||||||
relative_pointer_handle_relative_motion,
|
relative_pointer_handle_relative_motion,
|
||||||
@@ -2077,26 +2070,6 @@ static const struct wl_keyboard_listener keyboard_listener = {
|
|||||||
keyboard_handle_repeat_info, // Version 4
|
keyboard_handle_repeat_info, // Version 4
|
||||||
};
|
};
|
||||||
|
|
||||||
static void Wayland_SeatCreateRelativePointer(SDL_WaylandSeat *seat)
|
|
||||||
{
|
|
||||||
if (seat->display->relative_pointer_manager) {
|
|
||||||
if (seat->pointer.wl_pointer && !seat->pointer.relative_pointer) {
|
|
||||||
seat->pointer.relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(seat->display->relative_pointer_manager, seat->pointer.wl_pointer);
|
|
||||||
zwp_relative_pointer_v1_add_listener(seat->pointer.relative_pointer,
|
|
||||||
&relative_pointer_listener,
|
|
||||||
seat);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Wayland_DisplayInitRelativePointerManager(SDL_VideoData *display)
|
|
||||||
{
|
|
||||||
SDL_WaylandSeat *seat;
|
|
||||||
wl_list_for_each(seat, &display->seat_list, link) {
|
|
||||||
Wayland_SeatCreateRelativePointer(seat);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Wayland_SeatDestroyPointer(SDL_WaylandSeat *seat, bool send_event)
|
static void Wayland_SeatDestroyPointer(SDL_WaylandSeat *seat, bool send_event)
|
||||||
{
|
{
|
||||||
// Make sure focus is removed from a surface before the pointer is destroyed.
|
// Make sure focus is removed from a surface before the pointer is destroyed.
|
||||||
@@ -2239,8 +2212,6 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, enum w
|
|||||||
wl_pointer_set_user_data(seat->pointer.wl_pointer, seat);
|
wl_pointer_set_user_data(seat->pointer.wl_pointer, seat);
|
||||||
wl_pointer_add_listener(seat->pointer.wl_pointer, &pointer_listener, seat);
|
wl_pointer_add_listener(seat->pointer.wl_pointer, &pointer_listener, seat);
|
||||||
|
|
||||||
Wayland_SeatCreateRelativePointer(seat);
|
|
||||||
|
|
||||||
seat->pointer.sdl_id = SDL_GetNextObjectID();
|
seat->pointer.sdl_id = SDL_GetNextObjectID();
|
||||||
|
|
||||||
if (seat->name) {
|
if (seat->name) {
|
||||||
@@ -3490,16 +3461,36 @@ void Wayland_SeatDestroy(SDL_WaylandSeat *seat, bool send_events)
|
|||||||
SDL_free(seat);
|
SDL_free(seat);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Wayland_SeatHasRelativePointerFocus(SDL_WaylandSeat *seat)
|
static void Wayland_SeatUpdateRelativePointer(SDL_WaylandSeat *seat)
|
||||||
{
|
{
|
||||||
|
if (seat->display->relative_pointer_manager) {
|
||||||
|
bool relative_focus = false;
|
||||||
|
|
||||||
|
if (seat->pointer.focus) {
|
||||||
/* If a seat has both keyboard and pointer capabilities, relative focus will follow the keyboard
|
/* If a seat has both keyboard and pointer capabilities, relative focus will follow the keyboard
|
||||||
* attached to that seat. Otherwise, relative focus will be gained if any other seat has keyboard
|
* attached to that seat. Otherwise, relative focus will be gained if any other seat has keyboard
|
||||||
* focus on the window with pointer focus.
|
* focus on the window with pointer focus.
|
||||||
*/
|
*/
|
||||||
|
if (seat->pointer.focus->sdlwindow->flags & SDL_WINDOW_MOUSE_RELATIVE_MODE) {
|
||||||
if (seat->keyboard.wl_keyboard) {
|
if (seat->keyboard.wl_keyboard) {
|
||||||
return seat->keyboard.focus && seat->keyboard.focus == seat->pointer.focus;
|
relative_focus = seat->keyboard.focus == seat->pointer.focus;
|
||||||
} else {
|
} else {
|
||||||
return seat->pointer.focus && seat->pointer.focus->keyboard_focus_count != 0;
|
relative_focus = seat->pointer.focus->keyboard_focus_count != 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
relative_focus = SDL_GetMouse()->warp_emulation_active;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (relative_focus) {
|
||||||
|
if (!seat->pointer.relative_pointer) {
|
||||||
|
seat->pointer.relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(seat->display->relative_pointer_manager, seat->pointer.wl_pointer);
|
||||||
|
zwp_relative_pointer_v1_add_listener(seat->pointer.relative_pointer, &relative_pointer_listener, seat);
|
||||||
|
}
|
||||||
|
} else if (seat->pointer.relative_pointer) {
|
||||||
|
zwp_relative_pointer_v1_destroy(seat->pointer.relative_pointer);
|
||||||
|
seat->pointer.relative_pointer = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3532,11 +3523,10 @@ static void Wayland_SeatUpdateKeyboardGrab(SDL_WaylandSeat *seat)
|
|||||||
void Wayland_SeatUpdatePointerGrab(SDL_WaylandSeat *seat)
|
void Wayland_SeatUpdatePointerGrab(SDL_WaylandSeat *seat)
|
||||||
{
|
{
|
||||||
SDL_VideoData *display = seat->display;
|
SDL_VideoData *display = seat->display;
|
||||||
|
Wayland_SeatUpdateRelativePointer(seat);
|
||||||
|
|
||||||
if (display->pointer_constraints) {
|
if (display->pointer_constraints) {
|
||||||
const bool has_relative_focus = Wayland_SeatHasRelativePointerFocus(seat);
|
if (seat->pointer.locked_pointer && !seat->pointer.relative_pointer) {
|
||||||
|
|
||||||
if (seat->pointer.locked_pointer && (!display->relative_mode_enabled || !has_relative_focus)) {
|
|
||||||
zwp_locked_pointer_v1_destroy(seat->pointer.locked_pointer);
|
zwp_locked_pointer_v1_destroy(seat->pointer.locked_pointer);
|
||||||
seat->pointer.locked_pointer = NULL;
|
seat->pointer.locked_pointer = NULL;
|
||||||
|
|
||||||
@@ -3546,7 +3536,7 @@ void Wayland_SeatUpdatePointerGrab(SDL_WaylandSeat *seat)
|
|||||||
|
|
||||||
if (seat->pointer.wl_pointer) {
|
if (seat->pointer.wl_pointer) {
|
||||||
// If relative mode is active, and the pointer focus matches the keyboard focus, lock it.
|
// If relative mode is active, and the pointer focus matches the keyboard focus, lock it.
|
||||||
if (seat->display->relative_mode_enabled && has_relative_focus) {
|
if (seat->pointer.relative_pointer) {
|
||||||
if (!seat->pointer.locked_pointer) {
|
if (!seat->pointer.locked_pointer) {
|
||||||
// Creating a lock on a surface with an active confinement region on the same seat is a protocol error.
|
// Creating a lock on a surface with an active confinement region on the same seat is a protocol error.
|
||||||
if (seat->pointer.confined_pointer) {
|
if (seat->pointer.confined_pointer) {
|
||||||
|
@@ -191,7 +191,6 @@ extern int Wayland_WaitEventTimeout(SDL_VideoDevice *_this, Sint64 timeoutNS);
|
|||||||
|
|
||||||
extern void Wayland_DisplayInitInputTimestampManager(SDL_VideoData *display);
|
extern void Wayland_DisplayInitInputTimestampManager(SDL_VideoData *display);
|
||||||
extern void Wayland_DisplayInitCursorShapeManager(SDL_VideoData *display);
|
extern void Wayland_DisplayInitCursorShapeManager(SDL_VideoData *display);
|
||||||
extern void Wayland_DisplayInitRelativePointerManager(SDL_VideoData *display);
|
|
||||||
extern void Wayland_DisplayInitTabletManager(SDL_VideoData *display);
|
extern void Wayland_DisplayInitTabletManager(SDL_VideoData *display);
|
||||||
extern void Wayland_DisplayInitDataDeviceManager(SDL_VideoData *display);
|
extern void Wayland_DisplayInitDataDeviceManager(SDL_VideoData *display);
|
||||||
extern void Wayland_DisplayInitPrimarySelectionDeviceManager(SDL_VideoData *display);
|
extern void Wayland_DisplayInitPrimarySelectionDeviceManager(SDL_VideoData *display);
|
||||||
@@ -201,7 +200,6 @@ extern void Wayland_DisplayCreateTextInputManager(SDL_VideoData *d, uint32_t id)
|
|||||||
extern void Wayland_DisplayCreateSeat(SDL_VideoData *display, struct wl_seat *wl_seat, Uint32 id);
|
extern void Wayland_DisplayCreateSeat(SDL_VideoData *display, struct wl_seat *wl_seat, Uint32 id);
|
||||||
extern void Wayland_SeatDestroy(SDL_WaylandSeat *seat, bool send_events);
|
extern void Wayland_SeatDestroy(SDL_WaylandSeat *seat, bool send_events);
|
||||||
|
|
||||||
extern bool Wayland_SeatHasRelativePointerFocus(SDL_WaylandSeat *seat);
|
|
||||||
extern void Wayland_SeatUpdatePointerGrab(SDL_WaylandSeat *seat);
|
extern void Wayland_SeatUpdatePointerGrab(SDL_WaylandSeat *seat);
|
||||||
extern void Wayland_DisplayUpdatePointerGrabs(SDL_VideoData *display, SDL_WindowData *window);
|
extern void Wayland_DisplayUpdatePointerGrabs(SDL_VideoData *display, SDL_WindowData *window);
|
||||||
extern void Wayland_DisplayUpdateKeyboardGrabs(SDL_VideoData *display, SDL_WindowData *window);
|
extern void Wayland_DisplayUpdateKeyboardGrabs(SDL_VideoData *display, SDL_WindowData *window);
|
||||||
|
@@ -881,8 +881,7 @@ static bool Wayland_WarpMouseRelative(SDL_Window *window, float x, float y)
|
|||||||
|
|
||||||
if (d->pointer_constraints) {
|
if (d->pointer_constraints) {
|
||||||
wl_list_for_each (seat, &d->seat_list, link) {
|
wl_list_for_each (seat, &d->seat_list, link) {
|
||||||
if (wind == seat->pointer.focus ||
|
if (wind == seat->pointer.focus) {
|
||||||
(!seat->pointer.focus && wind == seat->keyboard.focus)) {
|
|
||||||
Wayland_SeatWarpMouse(seat, wind, x, y);
|
Wayland_SeatWarpMouse(seat, wind, x, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -939,7 +938,7 @@ static bool Wayland_SetRelativeMouseMode(bool enabled)
|
|||||||
return SDL_SetError("Failed to enable relative mode: compositor lacks support for the required zwp_pointer_constraints_v1 protocol");
|
return SDL_SetError("Failed to enable relative mode: compositor lacks support for the required zwp_pointer_constraints_v1 protocol");
|
||||||
}
|
}
|
||||||
|
|
||||||
data->relative_mode_enabled = enabled;
|
// Windows have a relative mode flag, so just update the grabs on a state change.
|
||||||
Wayland_DisplayUpdatePointerGrabs(data, NULL);
|
Wayland_DisplayUpdatePointerGrabs(data, NULL);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1122,13 +1121,10 @@ void Wayland_SeatUpdateCursor(SDL_WaylandSeat *seat)
|
|||||||
SDL_WindowData *pointer_focus = seat->pointer.focus;
|
SDL_WindowData *pointer_focus = seat->pointer.focus;
|
||||||
|
|
||||||
if (pointer_focus && mouse->cursor_visible) {
|
if (pointer_focus && mouse->cursor_visible) {
|
||||||
const bool has_relative_focus = Wayland_SeatHasRelativePointerFocus(seat);
|
if (!seat->pointer.relative_pointer || !mouse->relative_mode_hide_cursor) {
|
||||||
|
|
||||||
if (!seat->display->relative_mode_enabled || !has_relative_focus || !mouse->relative_mode_hide_cursor) {
|
|
||||||
const SDL_HitTestResult rc = pointer_focus->hit_test_result;
|
const SDL_HitTestResult rc = pointer_focus->hit_test_result;
|
||||||
|
|
||||||
if ((seat->display->relative_mode_enabled && has_relative_focus) ||
|
if (seat->pointer.relative_pointer || rc == SDL_HITTEST_NORMAL || rc == SDL_HITTEST_DRAGGABLE) {
|
||||||
rc == SDL_HITTEST_NORMAL || rc == SDL_HITTEST_DRAGGABLE) {
|
|
||||||
Wayland_SeatSetCursor(seat, mouse->cur_cursor);
|
Wayland_SeatSetCursor(seat, mouse->cur_cursor);
|
||||||
} else {
|
} else {
|
||||||
Wayland_SeatSetCursor(seat, sys_cursors[rc]);
|
Wayland_SeatSetCursor(seat, sys_cursors[rc]);
|
||||||
|
@@ -1267,7 +1267,6 @@ static void display_handle_global(void *data, struct wl_registry *registry, uint
|
|||||||
d->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1);
|
d->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1);
|
||||||
} else if (SDL_strcmp(interface, "zwp_relative_pointer_manager_v1") == 0) {
|
} else if (SDL_strcmp(interface, "zwp_relative_pointer_manager_v1") == 0) {
|
||||||
d->relative_pointer_manager = wl_registry_bind(d->registry, id, &zwp_relative_pointer_manager_v1_interface, 1);
|
d->relative_pointer_manager = wl_registry_bind(d->registry, id, &zwp_relative_pointer_manager_v1_interface, 1);
|
||||||
Wayland_DisplayInitRelativePointerManager(d);
|
|
||||||
} else if (SDL_strcmp(interface, "zwp_pointer_constraints_v1") == 0) {
|
} else if (SDL_strcmp(interface, "zwp_pointer_constraints_v1") == 0) {
|
||||||
d->pointer_constraints = wl_registry_bind(d->registry, id, &zwp_pointer_constraints_v1_interface, 1);
|
d->pointer_constraints = wl_registry_bind(d->registry, id, &zwp_pointer_constraints_v1_interface, 1);
|
||||||
} else if (SDL_strcmp(interface, "zwp_keyboard_shortcuts_inhibit_manager_v1") == 0) {
|
} else if (SDL_strcmp(interface, "zwp_keyboard_shortcuts_inhibit_manager_v1") == 0) {
|
||||||
|
@@ -96,9 +96,7 @@ struct SDL_VideoData
|
|||||||
int output_count;
|
int output_count;
|
||||||
int output_max;
|
int output_max;
|
||||||
|
|
||||||
bool relative_mode_enabled;
|
|
||||||
bool display_externally_owned;
|
bool display_externally_owned;
|
||||||
|
|
||||||
bool scale_to_display_enabled;
|
bool scale_to_display_enabled;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -2209,7 +2209,7 @@ static const struct xdg_activation_token_v1_listener activation_listener_xdg = {
|
|||||||
*
|
*
|
||||||
* As you might expect from Wayland, the general policy is to go with #2 unless
|
* As you might expect from Wayland, the general policy is to go with #2 unless
|
||||||
* the client can prove to the compositor beyond a reasonable doubt that raising
|
* the client can prove to the compositor beyond a reasonable doubt that raising
|
||||||
* the window will not be malicuous behavior.
|
* the window will not be malicious behavior.
|
||||||
*
|
*
|
||||||
* For SDL this means RaiseWindow and FlashWindow both use the same protocol,
|
* For SDL this means RaiseWindow and FlashWindow both use the same protocol,
|
||||||
* but in different ways: RaiseWindow will provide as _much_ information as
|
* but in different ways: RaiseWindow will provide as _much_ information as
|
||||||
|
Reference in New Issue
Block a user