فهرست منبع

x11: Add GTK signal handler for gtk-xft-dpi and reader in GetGlobalContentScale

- This is to support dynamic updates of content scale when running in XWayland. The GTK signal is
  preferred over the XSettings watcher and Xrm database if supported as it will trigger and update
  for both native X11 and XWayland on changes to Xft.dpi.
Sam Lantinga 1 ماه پیش
والد
کامیت
bf7b4d4a9e
3فایلهای تغییر یافته به همراه74 افزوده شده و 3 حذف شده
  1. 16 0
      src/video/x11/SDL_x11modes.c
  2. 54 3
      src/video/x11/SDL_x11settings.c
  3. 4 0
      src/video/x11/SDL_x11settings.h

+ 16 - 0
src/video/x11/SDL_x11modes.c

@@ -27,6 +27,8 @@
 #include "edid.h"
 #include "../../events/SDL_displayevents_c.h"
 
+#include "../../core/unix/SDL_gtk.h"
+
 // #define X11MODES_DEBUG
 
 /* Timeout and revert mode switches if the timespan has elapsed without the window becoming fullscreen.
@@ -61,6 +63,20 @@ static float GetGlobalContentScale(SDL_VideoDevice *_this)
             }
         }
 
+        // If that failed, try "Xft.dpi" from GTK if available. On XWayland this
+        // will retrieve the current scale factor which is not updated dynamically
+        // in the Xrm database.
+        SDL_GtkContext *gtk = SDL_Gtk_EnterContext();
+        if (gtk) {
+            GtkSettings *gtksettings = gtk->gtk.settings_get_default();
+            if (gtksettings) {
+                int dpi = 0;
+                gtk->g.object_get(gtksettings, "gtk-xft-dpi", &dpi, NULL);
+                scale_factor = dpi / 1024.0 / 96.0;
+            }
+            SDL_Gtk_ExitContext(gtk);
+        }
+
         // If that failed, try "Xft.dpi" from the XResourcesDatabase...
         if (scale_factor <= 0.0)
         {

+ 54 - 3
src/video/x11/SDL_x11settings.c

@@ -26,6 +26,8 @@
 #include "SDL_x11video.h"
 #include "SDL_x11settings.h"
 
+#include "core/unix/SDL_gtk.h"
+
 #define SDL_XSETTINGS_GDK_WINDOW_SCALING_FACTOR "Gdk/WindowScalingFactor"
 #define SDL_XSETTINGS_XFT_DPI "Xft/DPI"
 
@@ -65,13 +67,53 @@ static void X11_XsettingsNotify(const char *name, XSettingsAction action, XSetti
     }
 }
 
+static void OnGtkXftDpi(GtkSettings *settings, GParamSpec *pspec, gpointer ptr)
+{
+    SDL_VideoDevice *_this = (SDL_VideoDevice *)ptr;
+
+    SDL_GtkContext *gtk = SDL_Gtk_EnterContext();
+    if (gtk) {
+        int dpi = 0;
+        gtk->g.object_get(settings, "gtk-xft-dpi", &dpi, NULL);
+        
+        if (dpi != 0) {
+            float scale_factor = dpi / 1024.f / 96.f;
+
+            for (int i = 0; i < _this->num_displays; ++i) {
+                SDL_VideoDisplay *display = _this->displays[i];
+                SDL_SetDisplayContentScale(display, scale_factor);
+            }
+        }
+        SDL_Gtk_ExitContext(gtk);
+    }
+}
+
 void X11_InitXsettings(SDL_VideoDevice *_this)
 {
     SDL_VideoData *data = _this->internal;
     SDLX11_SettingsData *xsettings_data = &data->xsettings_data;
 
-    xsettings_data->xsettings = xsettings_client_new(data->display,
-        DefaultScreen(data->display), X11_XsettingsNotify, NULL, _this);
+    GtkSettings *gtksettings = NULL;
+    guint xft_dpi_signal_handler_id = 0;
+
+    SDL_GtkContext *gtk = SDL_Gtk_EnterContext();
+    if (gtk) {
+        // Prefer to listen for DPI changes from gtk. In XWayland this is necessary as XSettings
+        // are not updated dynamically.
+        gtksettings = gtk->gtk.settings_get_default();
+        if (gtksettings) {
+            xft_dpi_signal_handler_id = gtk->g.signal_connect(gtksettings, "notify::gtk-xft-dpi", &OnGtkXftDpi, _this);
+        }
+        SDL_Gtk_ExitContext(gtk);
+    }
+
+    if (gtksettings && xft_dpi_signal_handler_id) {
+        xsettings_data->gtksettings = gtksettings;
+        xsettings_data->xft_dpi_signal_handler_id = xft_dpi_signal_handler_id;
+    } else {
+        xsettings_data->xsettings = xsettings_client_new(data->display,
+            DefaultScreen(data->display), X11_XsettingsNotify, NULL, _this);
+    }
 
 }
 
@@ -82,8 +124,17 @@ void X11_QuitXsettings(SDL_VideoDevice *_this)
 
     if (xsettings_data->xsettings) {
         xsettings_client_destroy(xsettings_data->xsettings);
-        xsettings_data->xsettings = NULL;
     }
+
+    SDL_GtkContext *gtk = SDL_Gtk_EnterContext();
+    if (gtk) {
+        if (xsettings_data->gtksettings && xsettings_data->xft_dpi_signal_handler_id) {
+            gtk->g.signal_handler_disconnect(xsettings_data->gtksettings, xsettings_data->xft_dpi_signal_handler_id);
+        }
+        SDL_Gtk_ExitContext(gtk);
+    }
+
+    SDL_zero(xsettings_data);
 }
 
 void X11_HandleXsettings(SDL_VideoDevice *_this, const XEvent *xevent)

+ 4 - 0
src/video/x11/SDL_x11settings.h

@@ -27,8 +27,12 @@
 #include <X11/Xlib.h>
 #include "xsettings-client.h"
 
+#include "core/unix/SDL_gtk.h"
+
 typedef struct X11_SettingsData {
     XSettingsClient *xsettings;
+    GtkSettings *gtksettings;
+    guint xft_dpi_signal_handler_id;
 } SDLX11_SettingsData;
 
 extern void X11_InitXsettings(SDL_VideoDevice *_this);