diff --git a/src/video/wayland/SDL_waylandmouse.c b/src/video/wayland/SDL_waylandmouse.c index 72b9d14d5e..2ae9a418ae 100644 --- a/src/video/wayland/SDL_waylandmouse.c +++ b/src/video/wayland/SDL_waylandmouse.c @@ -1103,12 +1103,14 @@ static void Wayland_CursorStateSetCursor(SDL_WaylandCursorState *state, const Wa dst_height = dst_width; } else { - // If viewports aren't available, the scale is always 1.0. - state->scale = viddata->viewporter && focus ? focus->scale_factor : 1.0; - dst_width = cursor_data->cursor_data.custom.width; - dst_height = cursor_data->cursor_data.custom.height; - hot_x = cursor_data->cursor_data.custom.hot_x; - hot_y = cursor_data->cursor_data.custom.hot_y; + /* If viewports aren't available, the scale is always 1.0. + * The dimensions are scaled by the pointer scale, so custom cursors will be scaled relative to the window size. + */ + state->scale = viddata->viewporter && focus ? SDL_min(focus->pointer_scale.x, focus->pointer_scale.y) : 1.0; + dst_width = SDL_max((int)SDL_lround((double)cursor_data->cursor_data.custom.width / state->scale), 1); + dst_height = SDL_max((int)SDL_lround((double)cursor_data->cursor_data.custom.height / state->scale), 1); + hot_x = (int)SDL_lround((double)cursor_data->cursor_data.custom.hot_x / state->scale); + hot_y = (int)SDL_lround((double)cursor_data->cursor_data.custom.hot_y / state->scale); } state->current_cursor = cursor_data; @@ -1180,6 +1182,34 @@ static void Wayland_CursorStateResetCursor(SDL_WaylandCursorState *state) state->current_frame = -1; } +void Wayland_DisplayUpdatePointerFocusedScale(SDL_WindowData *updated_window) +{ + SDL_VideoData *viddata = updated_window->waylandData; + SDL_WaylandSeat *seat; + const double new_scale = SDL_min(updated_window->pointer_scale.x, updated_window->pointer_scale.y); + + wl_list_for_each (seat, &viddata->seat_list, link) { + if (seat->pointer.focus == updated_window) { + SDL_WaylandCursorState *state = &seat->pointer.cursor_state; + if (state->current_cursor && !state->current_cursor->is_system_cursor && state->scale != new_scale) { + Wayland_CursorStateResetCursor(state); + Wayland_SeatUpdatePointerCursor(seat); + } + } + + SDL_WaylandPenTool *tool; + wl_list_for_each (tool, &seat->tablet.tool_list, link) { + if (tool->focus == updated_window) { + SDL_WaylandCursorState *state = &tool->cursor_state; + if (state->current_cursor && !state->current_cursor->is_system_cursor && state->scale != new_scale) { + Wayland_CursorStateResetCursor(&tool->cursor_state); + Wayland_TabletToolUpdateCursor(tool); + } + } + } + } +} + static bool Wayland_ShowCursor(SDL_Cursor *cursor) { SDL_VideoDevice *vd = SDL_GetVideoDevice(); diff --git a/src/video/wayland/SDL_waylandmouse.h b/src/video/wayland/SDL_waylandmouse.h index 85ba5eef24..1707445a35 100644 --- a/src/video/wayland/SDL_waylandmouse.h +++ b/src/video/wayland/SDL_waylandmouse.h @@ -29,6 +29,7 @@ extern void Wayland_FiniMouse(SDL_VideoData *data); extern void Wayland_SeatUpdatePointerCursor(SDL_WaylandSeat *seat); extern void Wayland_SeatSetDefaultCursor(SDL_WaylandSeat *seat); extern void Wayland_SeatResetCursor(SDL_WaylandSeat *seat); +extern void Wayland_DisplayUpdatePointerFocusedScale(SDL_WindowData *updated_window); extern void Wayland_TabletToolUpdateCursor(SDL_WaylandPenTool *tool); extern void Wayland_SeatWarpMouse(SDL_WaylandSeat *seat, SDL_WindowData *window, float x, float y); extern void Wayland_CursorStateSetFrameCallback(SDL_WaylandCursorState *state, void *userdata); diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c index d2ad64974d..20da36b633 100644 --- a/src/video/wayland/SDL_waylandwindow.c +++ b/src/video/wayland/SDL_waylandwindow.c @@ -30,6 +30,7 @@ #include "../../core/unix/SDL_appid.h" #include "../SDL_egl_c.h" #include "SDL_waylandevents_c.h" +#include "SDL_waylandmouse.h" #include "SDL_waylandwindow.h" #include "SDL_waylandvideo.h" #include "../../SDL_hints_c.h" @@ -287,6 +288,8 @@ static void ConfigureWindowGeometry(SDL_Window *window) { SDL_WindowData *data = window->internal; const double scale_factor = GetWindowScale(window); + const double prev_pointer_scale_x = data->pointer_scale.x; + const double prev_pointer_scale_y = data->pointer_scale.y; const int old_pixel_width = data->current.pixel_width; const int old_pixel_height = data->current.pixel_height; int window_width = 0; @@ -566,6 +569,11 @@ static void ConfigureWindowGeometry(SDL_Window *window) } } + // Update the scale for any focused cursors. + if (prev_pointer_scale_x != data->pointer_scale.x || prev_pointer_scale_y != data->pointer_scale.y) { + Wayland_DisplayUpdatePointerFocusedScale(data); + } + /* Update the min/max dimensions, primarily if the state was changed, and for non-resizable * xdg-toplevel windows where the limits should match the window size. */