x11: Fix regression reading GNOME content scale

- Removed gtk-xft-dpi read from GetGlobalContentScale. Xrm either returns either the same value as gtk-xft-dpi or the integer
  scale value in cases where gtk-xft-dpi is 1.

- Refactor SDL_x11settings handlers to defer to GetGlobalContentScale

- GetGlobalContentScale is now exported and the XSettings and Gtk signal handlers now use it for consistency. This involves
  a bit of extra work reading from Xrm rather than the setting notification but ensures consistent handling based on signal
  origin and hints enabled.

- Hook both gtk-xft-dpi in SDL_x11settings. This should generally result in only one being called based on which is updated.
  Since both signal handlers defer to X11_GetGlobalContentScale this will cause the same content scale to be applied multiple
  times. The gtk-xft-dpi signal is now only used to trigger content scale updates when the XSettings notification does not occur.
This commit is contained in:
Sam Lantinga
2025-08-04 16:53:09 -07:00
parent 7bb045ca22
commit 293b8b9fd6
3 changed files with 17 additions and 65 deletions

View File

@@ -48,7 +48,7 @@
*/
// #define XRANDR_DISABLED_BY_DEFAULT
static float GetGlobalContentScale(SDL_VideoDevice *_this)
float X11_GetGlobalContentScale(SDL_VideoDevice *_this)
{
static double scale_factor = 0.0;
@@ -63,20 +63,6 @@ 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)
{
@@ -505,7 +491,7 @@ static bool X11_FillXRandRDisplayInfo(SDL_VideoDevice *_this, Display *dpy, int
display->name = display_name;
}
display->desktop_mode = mode;
display->content_scale = GetGlobalContentScale(_this);
display->content_scale = X11_GetGlobalContentScale(_this);
display->internal = displaydata;
return true;
@@ -875,7 +861,7 @@ static bool X11_InitModes_StdXlib(SDL_VideoDevice *_this)
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.internal = displaydata;
display.content_scale = GetGlobalContentScale(_this);
display.content_scale = X11_GetGlobalContentScale(_this);
if (SDL_AddVideoDisplay(&display, true) == 0) {
return false;
}

View File

@@ -62,6 +62,8 @@ extern SDL_PixelFormat X11_GetPixelFormatFromVisualInfo(Display *display, XVisua
extern bool X11_GetDisplayBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *sdl_display, SDL_Rect *rect);
extern bool X11_GetDisplayUsableBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *sdl_display, SDL_Rect *rect);
extern float X11_GetGlobalContentScale(SDL_VideoDevice *_this);
#ifdef SDL_VIDEO_DRIVER_X11_XRANDR
extern void X11_HandleXRandREvent(SDL_VideoDevice *_this, const XEvent *xevent);
#endif

View File

@@ -31,61 +31,26 @@
#define SDL_XSETTINGS_GDK_WINDOW_SCALING_FACTOR "Gdk/WindowScalingFactor"
#define SDL_XSETTINGS_XFT_DPI "Xft/DPI"
static void X11_XsettingsNotify(const char *name, XSettingsAction action, XSettingsSetting *setting, void *data)
static void UpdateContentScale(SDL_VideoDevice *_this)
{
SDL_VideoDevice *_this = data;
float scale_factor = 1.0;
int i;
if (SDL_strcmp(name, SDL_XSETTINGS_GDK_WINDOW_SCALING_FACTOR) != 0 ||
SDL_strcmp(name, SDL_XSETTINGS_XFT_DPI) != 0) {
return;
}
if (setting->type != XSETTINGS_TYPE_INT) {
return;
}
switch (action) {
case XSETTINGS_ACTION_NEW:
SDL_FALLTHROUGH;
case XSETTINGS_ACTION_CHANGED:
scale_factor = setting->data.v_int;
if (SDL_strcmp(name, SDL_XSETTINGS_XFT_DPI) == 0) {
scale_factor = scale_factor / 1024.0f / 96.0f;
}
break;
case XSETTINGS_ACTION_DELETED:
scale_factor = 1.0;
break;
}
if (_this) {
for (i = 0; i < _this->num_displays; ++i) {
float scale_factor = X11_GetGlobalContentScale(_this);
for (int i = 0; i < _this->num_displays; ++i) {
SDL_SetDisplayContentScale(_this->displays[i], scale_factor);
}
}
}
static void X11_XsettingsNotify(const char *name, XSettingsAction action, XSettingsSetting *setting, void *data)
{
SDL_VideoDevice *_this = data;
UpdateContentScale(_this);
}
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);
}
UpdateContentScale(_this);
}
void X11_InitXsettings(SDL_VideoDevice *_this)
@@ -110,11 +75,10 @@ void X11_InitXsettings(SDL_VideoDevice *_this)
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);
}
xsettings_data->xsettings = xsettings_client_new(data->display,
DefaultScreen(data->display), X11_XsettingsNotify, NULL, _this);
}
void X11_QuitXsettings(SDL_VideoDevice *_this)