diff --git a/src/events/SDL_mouse.c b/src/events/SDL_mouse.c index 166518a6f8..4845bb5724 100644 --- a/src/events/SDL_mouse.c +++ b/src/events/SDL_mouse.c @@ -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. const Uint64 now = SDL_GetTicksNS(); 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; } } diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c index 6aa95a5bee..ec01cbc0a2 100644 --- a/src/video/wayland/SDL_waylandevents.c +++ b/src/video/wayland/SDL_waylandevents.c @@ -912,7 +912,7 @@ static void pointer_handle_button_common(SDL_WaylandSeat *seat, uint32_t serial, * * 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) { window->sdlwindow->flags |= SDL_WINDOW_MOUSE_CAPTURE; } else { @@ -1164,30 +1164,23 @@ static void relative_pointer_handle_relative_motion(void *data, wl_fixed_t dy_unaccel_w) { SDL_WaylandSeat *seat = data; + SDL_WindowData *window = seat->pointer.focus; + SDL_Mouse *mouse = SDL_GetMouse(); - if (seat->display->relative_mode_enabled) { - SDL_WindowData *window = seat->pointer.focus; + // Relative pointer event times are in microsecond granularity. + const Uint64 timestamp = Wayland_AdjustEventTimestampBase(SDL_US_TO_NS(((Uint64)time_hi << 32) | (Uint64)time_lo)); - // Relative motion follows keyboard focus. - if (Wayland_SeatHasRelativePointerFocus(seat)) { - SDL_Mouse *mouse = SDL_GetMouse(); - - // Relative pointer event times are in microsecond granularity. - const Uint64 timestamp = Wayland_AdjustEventTimestampBase(SDL_US_TO_NS(((Uint64)time_hi << 32) | (Uint64)time_lo)); - - double dx; - double dy; - if (mouse->InputTransform || !mouse->enable_relative_system_scale) { - dx = wl_fixed_to_double(dx_unaccel_w); - dy = wl_fixed_to_double(dy_unaccel_w); - } else { - dx = wl_fixed_to_double(dx_w) * window->pointer_scale.x; - dy = wl_fixed_to_double(dy_w) * window->pointer_scale.y; - } - - SDL_SendMouseMotion(timestamp, window->sdlwindow, seat->pointer.sdl_id, true, (float)dx, (float)dy); - } + double dx; + double dy; + if (mouse->InputTransform || !mouse->enable_relative_system_scale) { + dx = wl_fixed_to_double(dx_unaccel_w); + dy = wl_fixed_to_double(dy_unaccel_w); + } else { + dx = wl_fixed_to_double(dx_w) * window->pointer_scale.x; + dy = wl_fixed_to_double(dy_w) * window->pointer_scale.y; } + + 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 = { @@ -2077,26 +2070,6 @@ static const struct wl_keyboard_listener keyboard_listener = { 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) { // 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_add_listener(seat->pointer.wl_pointer, &pointer_listener, seat); - Wayland_SeatCreateRelativePointer(seat); - seat->pointer.sdl_id = SDL_GetNextObjectID(); if (seat->name) { @@ -3490,16 +3461,36 @@ void Wayland_SeatDestroy(SDL_WaylandSeat *seat, bool send_events) SDL_free(seat); } -bool Wayland_SeatHasRelativePointerFocus(SDL_WaylandSeat *seat) +static void Wayland_SeatUpdateRelativePointer(SDL_WaylandSeat *seat) { - /* 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 - * focus on the window with pointer focus. - */ - if (seat->keyboard.wl_keyboard) { - return seat->keyboard.focus && seat->keyboard.focus == seat->pointer.focus; - } else { - return seat->pointer.focus && seat->pointer.focus->keyboard_focus_count != 0; + 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 + * attached to that seat. Otherwise, relative focus will be gained if any other seat has keyboard + * focus on the window with pointer focus. + */ + if (seat->pointer.focus->sdlwindow->flags & SDL_WINDOW_MOUSE_RELATIVE_MODE) { + if (seat->keyboard.wl_keyboard) { + relative_focus = seat->keyboard.focus == seat->pointer.focus; + } else { + 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) { SDL_VideoData *display = seat->display; + Wayland_SeatUpdateRelativePointer(seat); if (display->pointer_constraints) { - const bool has_relative_focus = Wayland_SeatHasRelativePointerFocus(seat); - - if (seat->pointer.locked_pointer && (!display->relative_mode_enabled || !has_relative_focus)) { + if (seat->pointer.locked_pointer && !seat->pointer.relative_pointer) { zwp_locked_pointer_v1_destroy(seat->pointer.locked_pointer); seat->pointer.locked_pointer = NULL; @@ -3546,7 +3536,7 @@ void Wayland_SeatUpdatePointerGrab(SDL_WaylandSeat *seat) if (seat->pointer.wl_pointer) { // 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) { // Creating a lock on a surface with an active confinement region on the same seat is a protocol error. if (seat->pointer.confined_pointer) { diff --git a/src/video/wayland/SDL_waylandevents_c.h b/src/video/wayland/SDL_waylandevents_c.h index a6c1eed589..a80793922f 100644 --- a/src/video/wayland/SDL_waylandevents_c.h +++ b/src/video/wayland/SDL_waylandevents_c.h @@ -191,7 +191,6 @@ extern int Wayland_WaitEventTimeout(SDL_VideoDevice *_this, Sint64 timeoutNS); extern void Wayland_DisplayInitInputTimestampManager(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_DisplayInitDataDeviceManager(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_SeatDestroy(SDL_WaylandSeat *seat, bool send_events); -extern bool Wayland_SeatHasRelativePointerFocus(SDL_WaylandSeat *seat); extern void Wayland_SeatUpdatePointerGrab(SDL_WaylandSeat *seat); extern void Wayland_DisplayUpdatePointerGrabs(SDL_VideoData *display, SDL_WindowData *window); extern void Wayland_DisplayUpdateKeyboardGrabs(SDL_VideoData *display, SDL_WindowData *window); diff --git a/src/video/wayland/SDL_waylandmouse.c b/src/video/wayland/SDL_waylandmouse.c index a4f354cdb8..39b3fcb8c7 100644 --- a/src/video/wayland/SDL_waylandmouse.c +++ b/src/video/wayland/SDL_waylandmouse.c @@ -881,8 +881,7 @@ static bool Wayland_WarpMouseRelative(SDL_Window *window, float x, float y) if (d->pointer_constraints) { wl_list_for_each (seat, &d->seat_list, link) { - if (wind == seat->pointer.focus || - (!seat->pointer.focus && wind == seat->keyboard.focus)) { + if (wind == seat->pointer.focus) { 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"); } - data->relative_mode_enabled = enabled; + // Windows have a relative mode flag, so just update the grabs on a state change. Wayland_DisplayUpdatePointerGrabs(data, NULL); return true; } @@ -1122,13 +1121,10 @@ void Wayland_SeatUpdateCursor(SDL_WaylandSeat *seat) SDL_WindowData *pointer_focus = seat->pointer.focus; if (pointer_focus && mouse->cursor_visible) { - const bool has_relative_focus = Wayland_SeatHasRelativePointerFocus(seat); - - if (!seat->display->relative_mode_enabled || !has_relative_focus || !mouse->relative_mode_hide_cursor) { + if (!seat->pointer.relative_pointer || !mouse->relative_mode_hide_cursor) { const SDL_HitTestResult rc = pointer_focus->hit_test_result; - if ((seat->display->relative_mode_enabled && has_relative_focus) || - rc == SDL_HITTEST_NORMAL || rc == SDL_HITTEST_DRAGGABLE) { + if (seat->pointer.relative_pointer || rc == SDL_HITTEST_NORMAL || rc == SDL_HITTEST_DRAGGABLE) { Wayland_SeatSetCursor(seat, mouse->cur_cursor); } else { Wayland_SeatSetCursor(seat, sys_cursors[rc]); diff --git a/src/video/wayland/SDL_waylandvideo.c b/src/video/wayland/SDL_waylandvideo.c index b615bf7079..1713d493ab 100644 --- a/src/video/wayland/SDL_waylandvideo.c +++ b/src/video/wayland/SDL_waylandvideo.c @@ -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); } 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); - Wayland_DisplayInitRelativePointerManager(d); } 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); } else if (SDL_strcmp(interface, "zwp_keyboard_shortcuts_inhibit_manager_v1") == 0) { diff --git a/src/video/wayland/SDL_waylandvideo.h b/src/video/wayland/SDL_waylandvideo.h index 33f2091966..e702a8e6a3 100644 --- a/src/video/wayland/SDL_waylandvideo.h +++ b/src/video/wayland/SDL_waylandvideo.h @@ -96,9 +96,7 @@ struct SDL_VideoData int output_count; int output_max; - bool relative_mode_enabled; bool display_externally_owned; - bool scale_to_display_enabled; }; diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c index 7a06d37dbf..eafe9f8b88 100644 --- a/src/video/wayland/SDL_waylandwindow.c +++ b/src/video/wayland/SDL_waylandwindow.c @@ -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 * 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, * but in different ways: RaiseWindow will provide as _much_ information as