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);
}