Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions src/xsettings/settingmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,17 @@ void SettingManager::setDoubleClickInterval(int interval)

void SettingManager::setGlobalScale(qreal scale)
{
const int windowScale = qMax(1, qFloor(scale));

m_resource->setPropertyValue(XResource::toByteArray(XResource::Xft_DPI), scale * BASE_DPI);
m_settings->setPropertyValue(XSettings::toByteArray(XSettings::Gdk_WindowScalingFactor), qFloor(scale));
m_settings->setPropertyValue(XSettings::toByteArray(XSettings::Gdk_UnscaledDPI), XSETTINGS_BASE_DPI_FIXED);
m_settings->setPropertyValue(XSettings::toByteArray(XSettings::Gdk_WindowScalingFactor), windowScale);
// Gdk/UnscaledDPI is defined as the DPI without the integer window scaling
// factor, but GDK/GTK (and Chromium through GTK's display config) prefer it
// over Xft/DPI. Keep the fractional part in it, otherwise GTK and Electron/
// Chromium clients resolve to the base 96 DPI and ignore Xft/DPI entirely,
// so fractional scales end up rendered at 100%.
m_settings->setPropertyValue(XSettings::toByteArray(XSettings::Gdk_UnscaledDPI),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gdk_UnscaledDPI不就是96x1024吗?我没看懂你这个改动的作用

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GNOME 的约定确实如此(我抓了 gsd 源码,plugins/xsettings/gsd-xsettings-manager.c:670-673):

settings->window_scale = get_window_scale (manager);          /* 整数缩放(mutter UiScalingFactor) */settings->dpi          = dpi * 1024;                          /* Gdk/UnscaledDPI = 96×1024 */settings->scaled_dpi   = dpi * settings->window_scale * 1024; /* Xft/DPI = 96×scale×1024 */

treeland 的 ac2b0abcc 就是照这个抄的。但这个约定成立有个前提:合成器自己把 X11 表面整体放大(mutter 的 framebuffer scaling)——分数部分由合成器渲染时放大(略糊),XSETTINGS 只需要表达"整数窗口缩放"。

而 treeland/wlroots 没有这个能力:vendored wlroots 的 xwayland/ 里没有任何 scale 处理、公开头文件无 scale API、waylib 也不缩放 X11 表面(都已 grep 确认)。本机实测也印证:打了补丁后 X11 客户端恰好是 1.25×,如果是"合成器 1.25 + 提示 1.25"会变成 1.5625×。

所以在 treeland 上分数缩放只能靠客户端 DPI 提示表达,而 GDK/GTK 的取值顺序是"有 Gdk/UnscaledDPI 就优先用它当 DPI"(实测:live 上 UnscaledDPI=98304 + Xft/DPI=122880 → gtk-xft-dpi=98304;Xvfb 上把 UnscaledDPI 去掉 → 122880),Gdk/WindowScalingFactor 只承载整数部分。于是固定 96×1024 会把 0.25 直接丢掉:

客户端 结果
GTK gtk-xft-dpi=98304 → 96dpi → 100%
Chromium/Electron DSF = max(1, gdk_monitor_get_scale_factor()) × gtk-xft-dpi/1024/96 = 1×1.0 → 100%(Chromium 源码 ui/gtk/gtk_ui.cc + GtkUiPlatformX11::IncludeFontScaleInDeviceScale()==true;真 Electron 实测 1200x800 vs 1500x1000)
Qt 直接读 Xft/DPI=122880 → 125%(所以"有些应用正常")

补丁的策略因此是:整数档完全遵循 GNOME 约定(100% → 98304;200% → 98304 + WSF=2;实测若删掉 UnscaledDPI,GDK 会拿 Xft/DPI=196608 当分辨率再乘 WSF=2 → 4.0× 双重放大,所以不能简单删键);只有分数档把分数因子折进 Gdk/UnscaledDPI(= 有效 DPI ÷ 整数窗口缩放,125% → 122880)。这正是 treeland 在 ac2b0abcc 之前的原行为(scale × 98304)——是那个提交把分数档一起改成固定基值才引入了差异。

qRound(scale / windowScale * XSETTINGS_BASE_DPI_FIXED));
m_settings->setPropertyValue(XSettings::toByteArray(XSettings::Xft_DPI), qRound(scale * XSETTINGS_BASE_DPI_FIXED));
}

Expand Down
Loading