SDL: wayland: Use high-DPI system cursors on non-DPI aware windows

From d0c9c008e1bb4bb94de58d9a95d9d98efbef8bbc Mon Sep 17 00:00:00 2001
From: Frank Praznik <[EMAIL REDACTED]>
Date: Sun, 29 Sep 2024 11:05:32 -0400
Subject: [PATCH] wayland: Use high-DPI system cursors on non-DPI aware windows

Using an unscaled buffer just results in the compositor scaling up the low-res cursor image for output, resulting in it appearing blurry. Always use the scaled cursor to ensure that it appears sharp and matches the native system look.
---
 src/video/wayland/SDL_waylandwindow.c | 29 +++++++++++++++------------
 1 file changed, 16 insertions(+), 13 deletions(-)

diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c
index e685689bee629..653ca10c23ef3 100644
--- a/src/video/wayland/SDL_waylandwindow.c
+++ b/src/video/wayland/SDL_waylandwindow.c
@@ -48,6 +48,11 @@
 #include <libdecor.h>
 #endif
 
+static double GetWindowScale(SDL_Window *window)
+{
+    return (window->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) || window->internal->scale_to_display ? window->internal->scale_factor : 1.0;
+}
+
 // These are point->pixel->point round trip safe; the inverse is not round trip safe due to rounding.
 static int PointToPixel(SDL_Window *window, int point)
 {
@@ -55,12 +60,12 @@ static int PointToPixel(SDL_Window *window, int point)
      * Wayland scale units are in units of 1/120, so the offset is required to correct for
      * rounding errors when using certain scale values.
      */
-    return SDL_max((int)SDL_lround((double)point * window->internal->scale_factor + 1e-6), 1);
+    return SDL_max((int)SDL_lround((double)point * GetWindowScale(window) + 1e-6), 1);
 }
 
 static int PixelToPoint(SDL_Window *window, int pixel)
 {
-    return SDL_max((int)SDL_lround((double)pixel / window->internal->scale_factor), 1);
+    return SDL_max((int)SDL_lround((double)pixel / GetWindowScale(window)), 1);
 }
 
 /* According to the Wayland spec:
@@ -295,6 +300,7 @@ static void SetSurfaceOpaqueRegion(SDL_WindowData *wind, bool is_opaque)
 static void ConfigureWindowGeometry(SDL_Window *window)
 {
     SDL_WindowData *data = window->internal;
+    const double scale_factor = GetWindowScale(window);
     const int old_pixel_width = data->current.pixel_width;
     const int old_pixel_height = data->current.pixel_height;
     int window_width, window_height;
@@ -381,7 +387,7 @@ static void ConfigureWindowGeometry(SDL_Window *window)
                 wp_viewport_set_destination(data->viewport, window_width, window_height);
             } else if (window->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) {
                 // Don't change this if the DPI awareness flag is unset, as an application may have set this manually on a custom or external surface.
-                wl_surface_set_buffer_scale(data->surface, (int32_t)data->scale_factor);
+                wl_surface_set_buffer_scale(data->surface, (int32_t)scale_factor);
             }
 
             // Clamp the physical window size to the system minimum required size.
@@ -392,8 +398,8 @@ static void ConfigureWindowGeometry(SDL_Window *window)
                 data->pointer_scale.x = 1.0;
                 data->pointer_scale.y = 1.0;
             } else {
-                data->pointer_scale.x = data->scale_factor;
-                data->pointer_scale.y = data->scale_factor;
+                data->pointer_scale.x = scale_factor;
+                data->pointer_scale.y = scale_factor;
             }
         }
     }
@@ -1345,11 +1351,6 @@ static void Wayland_HandlePreferredScaleChanged(SDL_WindowData *window_data, dou
 {
     const double old_factor = window_data->scale_factor;
 
-    if (!(window_data->sdlwindow->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) && !window_data->scale_to_display) {
-        // Scale will always be 1, just ignore this
-        return;
-    }
-
     // Round the scale factor if viewports aren't available.
     if (!window_data->viewport) {
         factor = SDL_ceil(factor);
@@ -1372,8 +1373,10 @@ static void Wayland_HandlePreferredScaleChanged(SDL_WindowData *window_data, dou
             }
         }
 
-        ConfigureWindowGeometry(window_data->sdlwindow);
-        CommitLibdecorFrame(window_data->sdlwindow);
+        if (window_data->sdlwindow->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY || window_data->scale_to_display) {
+            ConfigureWindowGeometry(window_data->sdlwindow);
+            CommitLibdecorFrame(window_data->sdlwindow);
+        }
     }
 }
 
@@ -2398,7 +2401,7 @@ bool Wayland_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_Proper
         data->scale_to_display = window->parent->internal->scale_to_display;
         data->scale_factor = window->parent->internal->scale_factor;
         EnsurePopupPositionIsValid(window, &window->x, &window->y);
-    } else if ((window->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) || c->scale_to_display_enabled) {
+    } else {
         for (int i = 0; i < _this->num_displays; i++) {
             data->scale_factor = SDL_max(data->scale_factor, _this->displays[i]->internal->scale_factor);
         }