SDL: x11: Use XResources font DPI as a fallback for X11 content scale

From a6bb00f3995aa0e3b3d26d24084809e7e1fb4037 Mon Sep 17 00:00:00 2001
From: David Edmundson <[EMAIL REDACTED]>
Date: Wed, 24 May 2023 09:59:55 +0100
Subject: [PATCH] x11: Use XResources font DPI as a fallback for X11 content
 scale

There are many toolkit specific ways to set a font DPI in X11 desktop
environments. The primary approach of reading a Gnome specific setting
from the portal is ok, it will work on Gnome and on Plasma most the
time.

The current fallback GDK_SCALE is less great; it's an internal GTK
setting relating to the mapping of logical pixels to device pixels
within the toolkit, it's a developer setting for GTK devs. We were
instructed within Plasma to not set this as it caused issues.

Xft.dpi in xresources is a good universal fallback, it's very dated to
the point that it works in clients like xterm, Qt on X11 uses it in our
font DPI path.
---
 src/video/x11/SDL_x11dyn.h   |  1 +
 src/video/x11/SDL_x11modes.c | 33 +++++++++++++++++++++++++++++----
 src/video/x11/SDL_x11sym.h   |  6 ++++++
 src/video/x11/SDL_x11video.h |  1 +
 4 files changed, 37 insertions(+), 4 deletions(-)

diff --git a/src/video/x11/SDL_x11dyn.h b/src/video/x11/SDL_x11dyn.h
index 2ab8b8a9e697..610e12bc2fa0 100644
--- a/src/video/x11/SDL_x11dyn.h
+++ b/src/video/x11/SDL_x11dyn.h
@@ -26,6 +26,7 @@
 #include <X11/Xlib.h>
 #include <X11/Xutil.h>
 #include <X11/Xatom.h>
+#include <X11/Xresource.h>
 
 #ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM
 #include <X11/XKBlib.h>
diff --git a/src/video/x11/SDL_x11modes.c b/src/video/x11/SDL_x11modes.c
index d0353d352e9a..f77c58b6afb3 100644
--- a/src/video/x11/SDL_x11modes.c
+++ b/src/video/x11/SDL_x11modes.c
@@ -159,7 +159,7 @@ static DBusHandlerResult DBus_MessageFilter(DBusConnection *conn, DBusMessage *m
 
 #endif
 
-static float GetGlobalContentScale()
+static float GetGlobalContentScale(SDL_VideoDevice *_this)
 {
     static double scale_factor = 0.0;
 
@@ -184,9 +184,34 @@ static float GetGlobalContentScale()
             }
         }
 
-        /* If that failed, try the GDK_SCALE envvar... */
+        /* If that failed, try "Xft.dpi" from the XResourcesDatabase... */
         if (scale_factor <= 0.0)
 #endif
+        {
+            SDL_VideoData *data = _this->driverdata;
+            Display *display = data->display;
+            char * resource_manager;
+            XrmDatabase db;
+            XrmValue value;
+            char *type;
+
+            X11_XrmInitialize();
+
+            resource_manager = X11_XResourceManagerString(display);
+            db = X11_XrmGetStringDatabase(resource_manager);
+
+            // Get the value of Xft.dpi from the Database
+            if (X11_XrmGetResource(db, "Xft.dpi", "String", &type, &value)) {
+                if (value.addr && type && SDL_strcmp(type, "String") == 0) {
+                    int dpi = SDL_atoi(value.addr);
+                    scale_factor  = dpi / 96.0;
+                }
+            }
+            X11_XrmDestroyDatabase(db);
+        }
+
+        /* If that failed, try the GDK_SCALE envvar... */
+        if (scale_factor <= 0.0)
         {
             const char *scale_str = SDL_getenv("GDK_SCALE");
             if (scale_str) {
@@ -547,7 +572,7 @@ static int X11_AddXRandRDisplay(SDL_VideoDevice *_this, Display *dpy, int screen
         display.name = display_name;
     }
     display.desktop_mode = mode;
-    display.content_scale = GetGlobalContentScale();
+    display.content_scale = GetGlobalContentScale(_this);
     display.driverdata = displaydata;
     if (SDL_AddVideoDisplay(&display, send_event) == 0) {
         return -1;
@@ -755,8 +780,8 @@ static int X11_InitModes_StdXlib(SDL_VideoDevice *_this)
     SDL_zero(display);
     display.name = (char *)"Generic X11 Display"; /* this is just copied and thrown away, it's safe to cast to char* here. */
     display.desktop_mode = mode;
-    display.content_scale = GetGlobalContentScale();
     display.driverdata = displaydata;
+    display.content_scale = GetGlobalContentScale(_this);
     if (SDL_AddVideoDisplay(&display, SDL_TRUE) == 0) {
         return -1;
     }
diff --git a/src/video/x11/SDL_x11sym.h b/src/video/x11/SDL_x11sym.h
index ffcbaeb882fc..9f8f6b69b4df 100644
--- a/src/video/x11/SDL_x11sym.h
+++ b/src/video/x11/SDL_x11sym.h
@@ -157,6 +157,12 @@ SDL_X11_SYM(Bool,XSupportsLocale,(void),(),return)
 SDL_X11_SYM(Status,XmbTextListToTextProperty,(Display* a,char** b,int c,XICCEncodingStyle d,XTextProperty* e),(a,b,c,d,e),return)
 SDL_X11_SYM(Region,XCreateRegion,(void),(),return)
 SDL_X11_SYM(void,XDestroyRegion,(Region),(a),)
+SDL_X11_SYM(void,XrmInitialize,(),(),)
+SDL_X11_SYM(char*,XResourceManagerString,(Display *display),(display),)
+SDL_X11_SYM(XrmDatabase,XrmGetStringDatabase,(char *data),(data),)
+SDL_X11_SYM(void,XrmDestroyDatabase,(XrmDatabase db),(db),)
+SDL_X11_SYM(Bool,XrmGetResource,(XrmDatabase db, char* str_name, char* str_class, char **str_type_return, XrmValue *),(db, str_name, str_class,str_type_return,value_return),)
+
 
 #ifdef SDL_VIDEO_DRIVER_X11_XFIXES
 SDL_X11_MODULE(XFIXES)
diff --git a/src/video/x11/SDL_x11video.h b/src/video/x11/SDL_x11video.h
index 0b5df50c7dc8..6a1fd054f2fb 100644
--- a/src/video/x11/SDL_x11video.h
+++ b/src/video/x11/SDL_x11video.h
@@ -28,6 +28,7 @@
 #include <X11/Xlib.h>
 #include <X11/Xutil.h>
 #include <X11/Xatom.h>
+#include <X11/Xresource.h>
 
 #ifdef SDL_VIDEO_DRIVER_X11_XCURSOR
 #include <X11/Xcursor/Xcursor.h>