Repository navigation
fix(linux_window): separate the surface scale from the stage factor in mutter's PHYSICAL layout - #69
Merged
Merged
Conversation
…n mutter's PHYSICAL layout
mutter has two monitor layout modes. In LOGICAL (fractional scaling;
mutter 50's default) the stage is logical px and one number, the monitor
scale, is both the surface scale and the stage factor. In PHYSICAL (Ubuntu
24.04 / GNOME 46 at an integer scale, out of the box) the stage already is
device px: at 200 % the stage factor is 1 while clients still draw at 2.
The Wayland window treated them as one number, in two places:
- Sizing: `mode / xdg_output.logical_size` (the stage factor, 1 in
PHYSICAL) was used as the surface scale, so request_initial_rect()
declared a 720x400 rect as 1440x800 and held it, and the deferred
fullscreen's first configure guess was twice the panel.
- Positions: the window-geometry extension's rects were converted by its
monitor.scale (2 in PHYSICAL), so the initial rect's landing check read
(600, 400) 2880x1600 for a window at (300, 200) 720x400, and the drag
lattice map used the wrong factor.
New dxr_wl_scale.h keeps the two apart: dxr_wl_surface_scale_estimate()
(the integer wl_output.scale when the stage factor is 1, else the stage
factor) sizes; dxr_wl_stage_factor() converts published rects, preferring
the extension's own answer (monitor.device_scale / layout_mode, extension
version 11), then this client's output at the monitor's origin (mode /
logical size, right in both modes), then the monitor scale. The runtime's
new u_wayland_layout.h is vendored verbatim in xrt_aux/util.
Measured on a private headless mutter 50.1 (3840x2160 virtual monitor,
gdctl --layout-mode physical --scale 2), linux_window_test with
DXR_LW_TEST_WAYLAND=1:
before: declared 1440x800, wanted 720x400; "the rect spans monitors of
different scales" at (600, 400) 2880x1600
after: initial rect: LANDED — (300, 200) 720x400 device px, off by
(+0, +0); same with the extension at version 10 (the output
fallback) and unchanged in LOGICAL at 200 %.
(The panel-fullscreen check fails under mutter in both modes, before and
after; it is written against weston.)
Tests: tests/linux_window_scale_test.cpp (new).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Companion to DisplayXR/displayxr-runtime#1785 (no merge-order dependency: this PR builds against today's runtime headers, and the runtime PR does not touch the vendored
u_wayland_geom.h).Problem
mutter has two monitor layout modes. In LOGICAL (fractional scaling; mutter 50's default) the stage is logical px. One number, the monitor scale, is then both the surface scale and the stage factor. In PHYSICAL (Ubuntu 24.04 / GNOME 46 at an integer scale, out of the box) the stage already is device px. At 200 % the stage factor is 1 while clients still draw at 2.
The Wayland window used one number for both:
mode / xdg_output.logical_sizeis the stage factor (1 in PHYSICAL), and it was used as the surface scale.request_initial_rect()therefore declared a 720x400 rect as 1440x800 and held it. The deferred fullscreen's first configure guess was also twice the panel.monitor.scale(2 in PHYSICAL). The initial rect's landing check and the drag-lattice map therefore used the wrong factor.Fix
The new
dxr_wl_scale.h(pure) keeps the two factors apart:dxr_wl_surface_scale_estimate()handles sizing. It returns the integerwl_output.scalewhen the stage factor is 1 (the PHYSICAL signature), else the stage factor.dxr_wl_stage_factor()converts published rects. It tries, in order:monitor.device_scale/layout_mode, extension v11 in runtime#1785).mode / logical_size, right in both modes).The runtime's new
u_wayland_layout.his vendored verbatim inxrt_aux/util.get_own_geometry()parses the two new fields.Verified
This ran on a private headless mutter 50.1 (3840x2160 virtual monitor,
gdctl set --layout-mode physical --scale 2), usinglinux_window_testwithDXR_LW_TEST_WAYLAND=1 DXR_LW_TEST_WAYLAND_PANEL=0,0,3840,2160:Meta-0.declared 1440x800, wanted 720x400; landing read as(600, 400) 2880x1600initial rect: LANDED — (300, 200) 720x400 device px, off by (+0, +0)The panel-fullscreen check (
fullscreen once mapped) fails under mutter in both modes, before and after. It is written against weston and is not part of this change.The existing lattice, drag and window tests pass. The new
tests/linux_window_scale_test.cppcovers both modes with the measured inputs.After merge
Tag it. When the runtime's test-app pin moves to that tag,
u_wayland_layout.hcan join the byte-identity guard intest_apps/common/dxr_linux_window_aux_guard.cmake.🤖 Generated with Claude Code