Skip to content

fix(xsettings): keep fractional DPI in Gdk/UnscaledDPI - #1436

Open
LFRon wants to merge 1 commit into
linuxdeepin:masterfrom
LFRon:fix/xwayland-scale
Open

LFRon wants to merge 1 commit into
linuxdeepin:masterfrom
LFRon:fix/xwayland-scale

Conversation

@LFRon

@LFRon LFRon commented Sep 22, 2026 •

Copy link
Copy Markdown
Contributor

该PR修复Xwayland跑的Electron应用99%出现的无法跟随系统分数缩放的问题

GTK and Electron/Chromium clients rendered fractional scales (125%) at 100%: treeland published Gdk/UnscaledDPI as the fixed 96 DPI base and kept the fractional part only in Xft/DPI, but GDK/GTK use Gdk/UnscaledDPI in preference to Xft/DPI.

  • GTK resolves gtk-xft-dpi from Gdk/UnscaledDPI first, so applications received 96 DPI at every scale.
  • Chromium (Electron) derives its X11 device scale factor from GTK's display config: max(1, gdk_monitor_get_scale_factor()) * gtk-xft-dpi / 1024 / 96. With the fixed base DPI it stayed at 1.0. Qt clients were unaffected because they read Xft/DPI directly.

Publish the effective DPI divided by the integer window scaling factor in Gdk/UnscaledDPI, and clamp that factor to at least 1 so that a scale below 1 can not publish Gdk/WindowScalingFactor = 0. Integer scales keep their previous values (100% and 200% still use the 96 DPI base with the integer window scale), while 125% now publishes 120 DPI and restores 1.25 rendering in GTK and Electron/Chromium clients.

Log: fractional scaling (e.g. 125%) works again in GTK and Electron/Chromium X11 clients
Influence: XSETTINGS DPI values at fractional scales change; integer scales are unaffected

Summary by Sourcery

Preserve fractional DPI information in XSETTINGS so X11 clients correctly follow fractional display scaling.

Bug Fixes:

  • Restore fractional scaling for GTK and Electron/Chromium X11 clients by preserving fractional DPI in Gdk/UnscaledDPI.

Enhancements:

  • Ensure Gdk/WindowScalingFactor is never published below 1 while retaining existing integer-scale behavior.

@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: LFRon

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@sourcery-ai

sourcery-ai Bot commented Sep 22, 2026

Copy link
Copy Markdown
Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

Updates global scale publication so Gdk/UnscaledDPI carries the fractional DPI component instead of always using the fixed 96 DPI base, restoring fractional rendering in GTK and Electron/Chromium X11 clients while leaving integer-scale behavior unchanged.

Sequence diagram for fractional DPI publication

sequenceDiagram
    participant Scale as GlobalScale
    participant Manager as SettingManager
    participant XResource
    participant XSettings
    participant GTK as GTK/Chromium

    Scale->>Manager: setGlobalScale(scale)
    Manager->>Manager: qMax(1, qFloor(scale))
    Manager->>XResource: setPropertyValue(Xft_DPI, scale * BASE_DPI)
    Manager->>XSettings: setPropertyValue(Gdk_WindowScalingFactor, windowScale)
    Manager->>XSettings: setPropertyValue(Gdk_UnscaledDPI, qRound(scale / windowScale * 96))
    Manager->>XSettings: setPropertyValue(Xft_DPI, qRound(scale * 96))
    GTK->>XSettings: Read Gdk_UnscaledDPI
    XSettings-->>GTK: Effective fractional DPI
Loading

File-Level Changes

Change Details Files
Preserve fractional scaling in the XSettings values consumed by GTK and Chromium while retaining integer window scaling semantics.
  • Clamp the published window scaling factor to at least 1.
  • Compute Gdk/UnscaledDPI from the effective scale divided by the integer window scale.
  • Continue publishing Xft/DPI from the full scale and round both DPI values.
src/xsettings/settingmanager.cpp

Possibly linked issues

  • #unknown: The PR directly fixes fractional-scale DPI propagation causing GTK and Electron applications to render at 100% instead of 125%.

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@deepin-ci-robot

Copy link
Copy Markdown

Hi @LFRon. Thanks for your PR.

I'm waiting for a linuxdeepin member to verify that this patch is reasonable to test. If it is, they should reply with /ok-to-test on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should join the org to skip this step.

Once the patch is verified, the new status will be reflected by the ok-to-test label.

I understand the commands that are listed here.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - I've reviewed your changes and they look great!


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

@wineee
wineee requested a review from zzxyb September 22, 2026 12:46
// 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)——是那个提交把分数档一起改成固定基值才引入了差异。

@LFRon
LFRon force-pushed the fix/xwayland-scale branch 2 times, most recently from 1ae20d0 to b7cd0da Compare October 9, 2026 04:29
GTK and Electron/Chromium clients rendered fractional scales (125%) at
100%: treeland published Gdk/UnscaledDPI as the fixed 96 DPI base and kept
the fractional part only in Xft/DPI, but GDK/GTK use Gdk/UnscaledDPI in
preference to Xft/DPI.

- GTK resolves gtk-xft-dpi from Gdk/UnscaledDPI first, so applications
  received 96 DPI at every scale.
- Chromium (Electron) derives its X11 device scale factor from GTK's
  display config: max(1, gdk_monitor_get_scale_factor()) * gtk-xft-dpi /
  1024 / 96. With the fixed base DPI it stayed at 1.0. Qt clients were
  unaffected because they read Xft/DPI directly.

Publish the effective DPI divided by the integer window scaling factor in
Gdk/UnscaledDPI, and clamp that factor to at least 1 so that a scale below
1 can not publish Gdk/WindowScalingFactor = 0. Integer scales keep their
previous values (100% and 200% still use the 96 DPI base with the integer
window scale), while 125% now publishes 120 DPI and restores 1.25
rendering in GTK and Electron/Chromium clients.

Log: fractional scaling (e.g. 125%) works again in GTK and Electron/Chromium X11 clients
Influence: XSETTINGS DPI values at fractional scales change; integer scales are unaffected
@LFRon
LFRon force-pushed the fix/xwayland-scale branch from b7cd0da to 410f882 Compare October 9, 2026 10:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants