SDL: Return xrandr-scaled display modes

From e4eab186ecb3d38a43b6c7645f2048eda1655478 Mon Sep 17 00:00:00 2001
From: Jeffrey Knockel <[EMAIL REDACTED]>
Date: Sun, 20 Mar 2022 18:52:49 -0400
Subject: [PATCH] Return xrandr-scaled display modes

XRandR supports applying transformations to an output's picture
including changes to scale. Such scaling is used by some desktop
environments under feature names such as "fractional scaling" to
accomodate HiDPI devices. Alternatively, such scaling can be enabled by
a command such as the following:

xrandr --output DP1 --scale 0.5x0.5 --filter nearest

XRandR scaling has no "HiDPI awareness" or other way for an application
to signal that it wants to work with physical display pixels, and so all
we do is scale SDL's returned display modes so that applications receive
the number of usable pixels that they expect.
---
 src/video/x11/SDL_x11modes.c | 15 +++++++++++----
 src/video/x11/SDL_x11sym.h   |  1 +
 2 files changed, 12 insertions(+), 4 deletions(-)

diff --git a/src/video/x11/SDL_x11modes.c b/src/video/x11/SDL_x11modes.c
index f77c58b6afb3..59920974d283 100644
--- a/src/video/x11/SDL_x11modes.c
+++ b/src/video/x11/SDL_x11modes.c
@@ -397,19 +397,26 @@ static SDL_bool SetXRandRModeInfo(Display *display, XRRScreenResources *res, RRC
         if (info->id == modeID) {
             XRRCrtcInfo *crtcinfo;
             Rotation rotation = 0;
+            XFixed scale_w = 0x10000, scale_h = 0x10000;
+            XRRCrtcTransformAttributes *attr;
 
             crtcinfo = X11_XRRGetCrtcInfo(display, res, crtc);
             if (crtcinfo) {
                 rotation = crtcinfo->rotation;
                 X11_XRRFreeCrtcInfo(crtcinfo);
             }
+            if (X11_XRRGetCrtcTransform(display, crtc, &attr) && attr) {
+                scale_w = attr->currentTransform.matrix[0][0];
+                scale_h = attr->currentTransform.matrix[1][1];
+                X11_XFree(attr);
+            }
 
             if (rotation & (XRANDR_ROTATION_LEFT | XRANDR_ROTATION_RIGHT)) {
-                mode->w = info->height;
-                mode->h = info->width;
+                mode->w = (info->height * scale_w + 0xffff) >> 16;
+                mode->h = (info->width * scale_h + 0xffff) >> 16;
             } else {
-                mode->w = info->width;
-                mode->h = info->height;
+                mode->w = (info->width * scale_w + 0xffff) >> 16;
+                mode->h = (info->height * scale_h + 0xffff) >> 16;
             }
             mode->refresh_rate = CalculateXRandRRefreshRate(info);
             ((SDL_DisplayModeData *)mode->driverdata)->xrandr_mode = modeID;
diff --git a/src/video/x11/SDL_x11sym.h b/src/video/x11/SDL_x11sym.h
index 9f8f6b69b4df..0a5fe38d56dc 100644
--- a/src/video/x11/SDL_x11sym.h
+++ b/src/video/x11/SDL_x11sym.h
@@ -309,6 +309,7 @@ SDL_X11_SYM(XRRPropertyInfo*,XRRQueryOutputProperty,(Display *dpy,RROutput outpu
 SDL_X11_SYM(int,XRRGetOutputProperty,(Display *dpy,RROutput output, Atom property, long offset, long length, Bool _delete, Bool pending, Atom req_type, Atom *actual_type, int *actual_format, unsigned long *nitems, unsigned long *bytes_after, unsigned char **prop),(dpy,output,property,offset,length, _delete, pending, req_type, actual_type, actual_format, nitems, bytes_after, prop),return)
 SDL_X11_SYM(RROutput,XRRGetOutputPrimary,(Display *dpy,Window window),(dpy,window),return)
 SDL_X11_SYM(void,XRRSelectInput,(Display *dpy, Window window, int mask),(dpy,window,mask),)
+SDL_X11_SYM(Status,XRRGetCrtcTransform,(Display *dpy,RRCrtc crtc,XRRCrtcTransformAttributes **attributes),(dpy,crtc,attributes),return)
 #endif
 
 /* MIT-SCREEN-SAVER support */