Skip to content

Commit bf7b4d4

Browse files
committed
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.
1 parent 3c369aa commit bf7b4d4

File tree

3 files changed

+74
-3
lines changed

3 files changed

+74
-3
lines changed

src/video/x11/SDL_x11modes.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
#include "edid.h"
2828
#include "../../events/SDL_displayevents_c.h"
2929

30+
#include "../../core/unix/SDL_gtk.h"
31+
3032
// #define X11MODES_DEBUG
3133

3234
/* 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)
6163
}
6264
}
6365

66+
// If that failed, try "Xft.dpi" from GTK if available. On XWayland this
67+
// will retrieve the current scale factor which is not updated dynamically
68+
// in the Xrm database.
69+
SDL_GtkContext *gtk = SDL_Gtk_EnterContext();
70+
if (gtk) {
71+
GtkSettings *gtksettings = gtk->gtk.settings_get_default();
72+
if (gtksettings) {
73+
int dpi = 0;
74+
gtk->g.object_get(gtksettings, "gtk-xft-dpi", &dpi, NULL);
75+
scale_factor = dpi / 1024.0 / 96.0;
76+
}
77+
SDL_Gtk_ExitContext(gtk);
78+
}
79+
6480
// If that failed, try "Xft.dpi" from the XResourcesDatabase...
6581
if (scale_factor <= 0.0)
6682
{

src/video/x11/SDL_x11settings.c

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
#include "SDL_x11video.h"
2727
#include "SDL_x11settings.h"
2828

29+
#include "core/unix/SDL_gtk.h"
30+
2931
#define SDL_XSETTINGS_GDK_WINDOW_SCALING_FACTOR "Gdk/WindowScalingFactor"
3032
#define SDL_XSETTINGS_XFT_DPI "Xft/DPI"
3133

@@ -65,13 +67,53 @@ static void X11_XsettingsNotify(const char *name, XSettingsAction action, XSetti
6567
}
6668
}
6769

70+
static void OnGtkXftDpi(GtkSettings *settings, GParamSpec *pspec, gpointer ptr)
71+
{
72+
SDL_VideoDevice *_this = (SDL_VideoDevice *)ptr;
73+
74+
SDL_GtkContext *gtk = SDL_Gtk_EnterContext();
75+
if (gtk) {
76+
int dpi = 0;
77+
gtk->g.object_get(settings, "gtk-xft-dpi", &dpi, NULL);
78+
79+
if (dpi != 0) {
80+
float scale_factor = dpi / 1024.f / 96.f;
81+
82+
for (int i = 0; i < _this->num_displays; ++i) {
83+
SDL_VideoDisplay *display = _this->displays[i];
84+
SDL_SetDisplayContentScale(display, scale_factor);
85+
}
86+
}
87+
SDL_Gtk_ExitContext(gtk);
88+
}
89+
}
90+
6891
void X11_InitXsettings(SDL_VideoDevice *_this)
6992
{
7093
SDL_VideoData *data = _this->internal;
7194
SDLX11_SettingsData *xsettings_data = &data->xsettings_data;
7295

73-
xsettings_data->xsettings = xsettings_client_new(data->display,
74-
DefaultScreen(data->display), X11_XsettingsNotify, NULL, _this);
96+
GtkSettings *gtksettings = NULL;
97+
guint xft_dpi_signal_handler_id = 0;
98+
99+
SDL_GtkContext *gtk = SDL_Gtk_EnterContext();
100+
if (gtk) {
101+
// Prefer to listen for DPI changes from gtk. In XWayland this is necessary as XSettings
102+
// are not updated dynamically.
103+
gtksettings = gtk->gtk.settings_get_default();
104+
if (gtksettings) {
105+
xft_dpi_signal_handler_id = gtk->g.signal_connect(gtksettings, "notify::gtk-xft-dpi", &OnGtkXftDpi, _this);
106+
}
107+
SDL_Gtk_ExitContext(gtk);
108+
}
109+
110+
if (gtksettings && xft_dpi_signal_handler_id) {
111+
xsettings_data->gtksettings = gtksettings;
112+
xsettings_data->xft_dpi_signal_handler_id = xft_dpi_signal_handler_id;
113+
} else {
114+
xsettings_data->xsettings = xsettings_client_new(data->display,
115+
DefaultScreen(data->display), X11_XsettingsNotify, NULL, _this);
116+
}
75117

76118
}
77119

@@ -82,8 +124,17 @@ void X11_QuitXsettings(SDL_VideoDevice *_this)
82124

83125
if (xsettings_data->xsettings) {
84126
xsettings_client_destroy(xsettings_data->xsettings);
85-
xsettings_data->xsettings = NULL;
86127
}
128+
129+
SDL_GtkContext *gtk = SDL_Gtk_EnterContext();
130+
if (gtk) {
131+
if (xsettings_data->gtksettings && xsettings_data->xft_dpi_signal_handler_id) {
132+
gtk->g.signal_handler_disconnect(xsettings_data->gtksettings, xsettings_data->xft_dpi_signal_handler_id);
133+
}
134+
SDL_Gtk_ExitContext(gtk);
135+
}
136+
137+
SDL_zero(xsettings_data);
87138
}
88139

89140
void X11_HandleXsettings(SDL_VideoDevice *_this, const XEvent *xevent)

src/video/x11/SDL_x11settings.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,12 @@
2727
#include <X11/Xlib.h>
2828
#include "xsettings-client.h"
2929

30+
#include "core/unix/SDL_gtk.h"
31+
3032
typedef struct X11_SettingsData {
3133
XSettingsClient *xsettings;
34+
GtkSettings *gtksettings;
35+
guint xft_dpi_signal_handler_id;
3236
} SDLX11_SettingsData;
3337

3438
extern void X11_InitXsettings(SDL_VideoDevice *_this);

0 commit comments

Comments
 (0)