Skip to content

Commit b0a282e

Browse files
committed
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.
1 parent 968222e commit b0a282e

File tree

7 files changed

+55
-73
lines changed

7 files changed

+55
-73
lines changed

src/events/SDL_mouse.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1314,8 +1314,9 @@ static void SDL_MaybeEnableWarpEmulation(SDL_Window *window, float x, float y)
13141314
// Require two consecutive warps to the center within a certain timespan to enter warp emulation mode.
13151315
const Uint64 now = SDL_GetTicksNS();
13161316
if (now - mouse->last_center_warp_time_ns < WARP_EMULATION_THRESHOLD_NS) {
1317-
if (SDL_SetRelativeMouseMode(true)) {
1318-
mouse->warp_emulation_active = true;
1317+
mouse->warp_emulation_active = true;
1318+
if (!SDL_SetRelativeMouseMode(true)) {
1319+
mouse->warp_emulation_active = false;
13191320
}
13201321
}
13211322

src/video/wayland/SDL_waylandevents.c

Lines changed: 47 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -912,7 +912,7 @@ static void pointer_handle_button_common(SDL_WaylandSeat *seat, uint32_t serial,
912912
*
913913
* The mouse is not captured in relative mode.
914914
*/
915-
if (!seat->display->relative_mode_enabled || !Wayland_SeatHasRelativePointerFocus(seat)) {
915+
if (!seat->pointer.relative_pointer) {
916916
if (seat->pointer.buttons_pressed != 0) {
917917
window->sdlwindow->flags |= SDL_WINDOW_MOUSE_CAPTURE;
918918
} else {
@@ -1164,30 +1164,23 @@ static void relative_pointer_handle_relative_motion(void *data,
11641164
wl_fixed_t dy_unaccel_w)
11651165
{
11661166
SDL_WaylandSeat *seat = data;
1167+
SDL_WindowData *window = seat->pointer.focus;
1168+
SDL_Mouse *mouse = SDL_GetMouse();
11671169

1168-
if (seat->display->relative_mode_enabled) {
1169-
SDL_WindowData *window = seat->pointer.focus;
1170-
1171-
// Relative motion follows keyboard focus.
1172-
if (Wayland_SeatHasRelativePointerFocus(seat)) {
1173-
SDL_Mouse *mouse = SDL_GetMouse();
1174-
1175-
// Relative pointer event times are in microsecond granularity.
1176-
const Uint64 timestamp = Wayland_AdjustEventTimestampBase(SDL_US_TO_NS(((Uint64)time_hi << 32) | (Uint64)time_lo));
1170+
// Relative pointer event times are in microsecond granularity.
1171+
const Uint64 timestamp = Wayland_AdjustEventTimestampBase(SDL_US_TO_NS(((Uint64)time_hi << 32) | (Uint64)time_lo));
11771172

1178-
double dx;
1179-
double dy;
1180-
if (mouse->InputTransform || !mouse->enable_relative_system_scale) {
1181-
dx = wl_fixed_to_double(dx_unaccel_w);
1182-
dy = wl_fixed_to_double(dy_unaccel_w);
1183-
} else {
1184-
dx = wl_fixed_to_double(dx_w) * window->pointer_scale.x;
1185-
dy = wl_fixed_to_double(dy_w) * window->pointer_scale.y;
1186-
}
1187-
1188-
SDL_SendMouseMotion(timestamp, window->sdlwindow, seat->pointer.sdl_id, true, (float)dx, (float)dy);
1189-
}
1173+
double dx;
1174+
double dy;
1175+
if (mouse->InputTransform || !mouse->enable_relative_system_scale) {
1176+
dx = wl_fixed_to_double(dx_unaccel_w);
1177+
dy = wl_fixed_to_double(dy_unaccel_w);
1178+
} else {
1179+
dx = wl_fixed_to_double(dx_w) * window->pointer_scale.x;
1180+
dy = wl_fixed_to_double(dy_w) * window->pointer_scale.y;
11901181
}
1182+
1183+
SDL_SendMouseMotion(timestamp, window->sdlwindow, seat->pointer.sdl_id, true, (float)dx, (float)dy);
11911184
}
11921185

11931186
static const struct zwp_relative_pointer_v1_listener relative_pointer_listener = {
@@ -2077,26 +2070,6 @@ static const struct wl_keyboard_listener keyboard_listener = {
20772070
keyboard_handle_repeat_info, // Version 4
20782071
};
20792072

2080-
static void Wayland_SeatCreateRelativePointer(SDL_WaylandSeat *seat)
2081-
{
2082-
if (seat->display->relative_pointer_manager) {
2083-
if (seat->pointer.wl_pointer && !seat->pointer.relative_pointer) {
2084-
seat->pointer.relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(seat->display->relative_pointer_manager, seat->pointer.wl_pointer);
2085-
zwp_relative_pointer_v1_add_listener(seat->pointer.relative_pointer,
2086-
&relative_pointer_listener,
2087-
seat);
2088-
}
2089-
}
2090-
}
2091-
2092-
void Wayland_DisplayInitRelativePointerManager(SDL_VideoData *display)
2093-
{
2094-
SDL_WaylandSeat *seat;
2095-
wl_list_for_each(seat, &display->seat_list, link) {
2096-
Wayland_SeatCreateRelativePointer(seat);
2097-
}
2098-
}
2099-
21002073
static void Wayland_SeatDestroyPointer(SDL_WaylandSeat *seat, bool send_event)
21012074
{
21022075
// 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
22392212
wl_pointer_set_user_data(seat->pointer.wl_pointer, seat);
22402213
wl_pointer_add_listener(seat->pointer.wl_pointer, &pointer_listener, seat);
22412214

2242-
Wayland_SeatCreateRelativePointer(seat);
2243-
22442215
seat->pointer.sdl_id = SDL_GetNextObjectID();
22452216

22462217
if (seat->name) {
@@ -3490,16 +3461,36 @@ void Wayland_SeatDestroy(SDL_WaylandSeat *seat, bool send_events)
34903461
SDL_free(seat);
34913462
}
34923463

3493-
bool Wayland_SeatHasRelativePointerFocus(SDL_WaylandSeat *seat)
3464+
static void Wayland_SeatUpdateRelativePointer(SDL_WaylandSeat *seat)
34943465
{
3495-
/* If a seat has both keyboard and pointer capabilities, relative focus will follow the keyboard
3496-
* attached to that seat. Otherwise, relative focus will be gained if any other seat has keyboard
3497-
* focus on the window with pointer focus.
3498-
*/
3499-
if (seat->keyboard.wl_keyboard) {
3500-
return seat->keyboard.focus && seat->keyboard.focus == seat->pointer.focus;
3501-
} else {
3502-
return seat->pointer.focus && seat->pointer.focus->keyboard_focus_count != 0;
3466+
if (seat->display->relative_pointer_manager) {
3467+
bool relative_focus = false;
3468+
3469+
if (seat->pointer.focus) {
3470+
/* If a seat has both keyboard and pointer capabilities, relative focus will follow the keyboard
3471+
* attached to that seat. Otherwise, relative focus will be gained if any other seat has keyboard
3472+
* focus on the window with pointer focus.
3473+
*/
3474+
if (seat->pointer.focus->sdlwindow->flags & SDL_WINDOW_MOUSE_RELATIVE_MODE) {
3475+
if (seat->keyboard.wl_keyboard) {
3476+
relative_focus = seat->keyboard.focus == seat->pointer.focus;
3477+
} else {
3478+
relative_focus = seat->pointer.focus->keyboard_focus_count != 0;
3479+
}
3480+
} else {
3481+
relative_focus = SDL_GetMouse()->warp_emulation_active;
3482+
}
3483+
}
3484+
3485+
if (relative_focus) {
3486+
if (!seat->pointer.relative_pointer) {
3487+
seat->pointer.relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(seat->display->relative_pointer_manager, seat->pointer.wl_pointer);
3488+
zwp_relative_pointer_v1_add_listener(seat->pointer.relative_pointer, &relative_pointer_listener, seat);
3489+
}
3490+
} else if (seat->pointer.relative_pointer) {
3491+
zwp_relative_pointer_v1_destroy(seat->pointer.relative_pointer);
3492+
seat->pointer.relative_pointer = NULL;
3493+
}
35033494
}
35043495
}
35053496

@@ -3532,11 +3523,10 @@ static void Wayland_SeatUpdateKeyboardGrab(SDL_WaylandSeat *seat)
35323523
void Wayland_SeatUpdatePointerGrab(SDL_WaylandSeat *seat)
35333524
{
35343525
SDL_VideoData *display = seat->display;
3526+
Wayland_SeatUpdateRelativePointer(seat);
35353527

35363528
if (display->pointer_constraints) {
3537-
const bool has_relative_focus = Wayland_SeatHasRelativePointerFocus(seat);
3538-
3539-
if (seat->pointer.locked_pointer && (!display->relative_mode_enabled || !has_relative_focus)) {
3529+
if (seat->pointer.locked_pointer && !seat->pointer.relative_pointer) {
35403530
zwp_locked_pointer_v1_destroy(seat->pointer.locked_pointer);
35413531
seat->pointer.locked_pointer = NULL;
35423532

@@ -3546,7 +3536,7 @@ void Wayland_SeatUpdatePointerGrab(SDL_WaylandSeat *seat)
35463536

35473537
if (seat->pointer.wl_pointer) {
35483538
// If relative mode is active, and the pointer focus matches the keyboard focus, lock it.
3549-
if (seat->display->relative_mode_enabled && has_relative_focus) {
3539+
if (seat->pointer.relative_pointer) {
35503540
if (!seat->pointer.locked_pointer) {
35513541
// Creating a lock on a surface with an active confinement region on the same seat is a protocol error.
35523542
if (seat->pointer.confined_pointer) {

src/video/wayland/SDL_waylandevents_c.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,6 @@ extern int Wayland_WaitEventTimeout(SDL_VideoDevice *_this, Sint64 timeoutNS);
191191

192192
extern void Wayland_DisplayInitInputTimestampManager(SDL_VideoData *display);
193193
extern void Wayland_DisplayInitCursorShapeManager(SDL_VideoData *display);
194-
extern void Wayland_DisplayInitRelativePointerManager(SDL_VideoData *display);
195194
extern void Wayland_DisplayInitTabletManager(SDL_VideoData *display);
196195
extern void Wayland_DisplayInitDataDeviceManager(SDL_VideoData *display);
197196
extern void Wayland_DisplayInitPrimarySelectionDeviceManager(SDL_VideoData *display);
@@ -201,7 +200,6 @@ extern void Wayland_DisplayCreateTextInputManager(SDL_VideoData *d, uint32_t id)
201200
extern void Wayland_DisplayCreateSeat(SDL_VideoData *display, struct wl_seat *wl_seat, Uint32 id);
202201
extern void Wayland_SeatDestroy(SDL_WaylandSeat *seat, bool send_events);
203202

204-
extern bool Wayland_SeatHasRelativePointerFocus(SDL_WaylandSeat *seat);
205203
extern void Wayland_SeatUpdatePointerGrab(SDL_WaylandSeat *seat);
206204
extern void Wayland_DisplayUpdatePointerGrabs(SDL_VideoData *display, SDL_WindowData *window);
207205
extern void Wayland_DisplayUpdateKeyboardGrabs(SDL_VideoData *display, SDL_WindowData *window);

src/video/wayland/SDL_waylandmouse.c

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -881,8 +881,7 @@ static bool Wayland_WarpMouseRelative(SDL_Window *window, float x, float y)
881881

882882
if (d->pointer_constraints) {
883883
wl_list_for_each (seat, &d->seat_list, link) {
884-
if (wind == seat->pointer.focus ||
885-
(!seat->pointer.focus && wind == seat->keyboard.focus)) {
884+
if (wind == seat->pointer.focus) {
886885
Wayland_SeatWarpMouse(seat, wind, x, y);
887886
}
888887
}
@@ -939,7 +938,7 @@ static bool Wayland_SetRelativeMouseMode(bool enabled)
939938
return SDL_SetError("Failed to enable relative mode: compositor lacks support for the required zwp_pointer_constraints_v1 protocol");
940939
}
941940

942-
data->relative_mode_enabled = enabled;
941+
// Windows have a relative mode flag, so just update the grabs on a state change.
943942
Wayland_DisplayUpdatePointerGrabs(data, NULL);
944943
return true;
945944
}
@@ -1122,13 +1121,10 @@ void Wayland_SeatUpdateCursor(SDL_WaylandSeat *seat)
11221121
SDL_WindowData *pointer_focus = seat->pointer.focus;
11231122

11241123
if (pointer_focus && mouse->cursor_visible) {
1125-
const bool has_relative_focus = Wayland_SeatHasRelativePointerFocus(seat);
1126-
1127-
if (!seat->display->relative_mode_enabled || !has_relative_focus || !mouse->relative_mode_hide_cursor) {
1124+
if (!seat->pointer.relative_pointer || !mouse->relative_mode_hide_cursor) {
11281125
const SDL_HitTestResult rc = pointer_focus->hit_test_result;
11291126

1130-
if ((seat->display->relative_mode_enabled && has_relative_focus) ||
1131-
rc == SDL_HITTEST_NORMAL || rc == SDL_HITTEST_DRAGGABLE) {
1127+
if (seat->pointer.relative_pointer || rc == SDL_HITTEST_NORMAL || rc == SDL_HITTEST_DRAGGABLE) {
11321128
Wayland_SeatSetCursor(seat, mouse->cur_cursor);
11331129
} else {
11341130
Wayland_SeatSetCursor(seat, sys_cursors[rc]);

src/video/wayland/SDL_waylandvideo.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1267,7 +1267,6 @@ static void display_handle_global(void *data, struct wl_registry *registry, uint
12671267
d->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1);
12681268
} else if (SDL_strcmp(interface, "zwp_relative_pointer_manager_v1") == 0) {
12691269
d->relative_pointer_manager = wl_registry_bind(d->registry, id, &zwp_relative_pointer_manager_v1_interface, 1);
1270-
Wayland_DisplayInitRelativePointerManager(d);
12711270
} else if (SDL_strcmp(interface, "zwp_pointer_constraints_v1") == 0) {
12721271
d->pointer_constraints = wl_registry_bind(d->registry, id, &zwp_pointer_constraints_v1_interface, 1);
12731272
} else if (SDL_strcmp(interface, "zwp_keyboard_shortcuts_inhibit_manager_v1") == 0) {

src/video/wayland/SDL_waylandvideo.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,7 @@ struct SDL_VideoData
9696
int output_count;
9797
int output_max;
9898

99-
bool relative_mode_enabled;
10099
bool display_externally_owned;
101-
102100
bool scale_to_display_enabled;
103101
};
104102

src/video/wayland/SDL_waylandwindow.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2209,7 +2209,7 @@ static const struct xdg_activation_token_v1_listener activation_listener_xdg = {
22092209
*
22102210
* As you might expect from Wayland, the general policy is to go with #2 unless
22112211
* the client can prove to the compositor beyond a reasonable doubt that raising
2212-
* the window will not be malicuous behavior.
2212+
* the window will not be malicious behavior.
22132213
*
22142214
* For SDL this means RaiseWindow and FlashWindow both use the same protocol,
22152215
* but in different ways: RaiseWindow will provide as _much_ information as

0 commit comments

Comments
 (0)