Repository navigation
fix(wayland): convert window geometry by the stage factor in mutter's PHYSICAL layout (extension v11) - #1785
Merged
Merged
Conversation
…nitor scale, in mutter's PHYSICAL layout mutter has two monitor layout modes. In LOGICAL (fractional scaling; mutter 50's default) the stage is logical px and device px = stage x the monitor scale. In PHYSICAL (Ubuntu 24.04 / GNOME 46 at an integer scale, out of the box) the stage already is device px: a 3840x2160 monitor at 200 % is a 3840x2160 stage rect with scale 2. comp_vk_native_wl_geom always multiplied the window-geometry extension's rects by the monitor scale, so in PHYSICAL it read the panel as a 7680x4320 output, decided the window was not on the panel, and presented flat 2D with the lens off (NOT_1TO1) at any scale above 100 %. Reproduced on a private headless mutter 50.1 (3840x2160 virtual monitor, gdctl --layout-mode physical --scale 2, cube_handle_vk_linux windowed on sim-display): wl_geom: monitor scale 2.0000 — window content logical 0,180 3840x2160 on a 3840x2160 logical monitor converts to DEVICE 0,360 7680x4320 on a 7680x4320 px monitor NOT_1TO1: presenting 2D (no weave) — this surface is not on the 3D panel. buffer 3840x2160 px, surface 7680x4320 px on a 7680x4320 px output, 3D panel 3840x2160 px. The same run in LOGICAL at 200 % converts correctly. Runtime: the factor is now resolved per window by u_wl_stage_to_device_scale() (new u_wayland_layout.h, kept out of the u_wayland_geom.h that displayxr-common vendors byte-for-byte): the publisher's monitor.device_scale, else its layout_mode, else mutter's own layout-mode from org.gnome.Mutter.DisplayConfig.GetCurrentState (for an extension older than version 11, e.g. the one a session keeps running until logout after a package upgrade; refreshed on MonitorsChanged), else the monitor scale as before. wr.scale carries the same factor, so the drop-time phase snap searches over the right device positions. One WARN names PHYSICAL and its source. Extension version 11: the snapshot gains a top-level layout_mode and monitor.device_scale, read from the stage view scales (any view scale other than 1 means LOGICAL; every view at 1 with a scaled monitor means PHYSICAL). No existing field changes meaning, so the schema stays version 1. The drag-lattice choice and the stamp audit weigh device px by the same factor. The move-sync tag decode needs no change: subsurface actor positions are in surface units in both modes (measured). Verified headless (sim-display, windowed 1600x900): PHYSICAL 200 % -> DEVICE 1120,720 1600x900 on 3840x2160, present origin set, no NOT_1TO1, with both the v11 extension and the installed v10 one (Mutter fallback); LOGICAL 100/125/150/166.67/200 % all land on the same device rect; fullscreen at PHYSICAL 200 % weaves 1:1. Tests: tests_aux_wayland_geom (both modes, every offered scale, the reported failure pinned); scripts/test_gnome_extension_stage_scale.js (new, in lint.yml). 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.
Problem
On Ubuntu 24.04 (GNOME 46, native Wayland) with a 3840x2160 3D panel at 200 %, no app weaves.
wl_geomreports the window on a 7680x4320 output against the 3840x2160 panel. So the runtime decides the window is not on the panel, presents flat 2D and turns the lens off (NOT_1TO1, #1595/#1596). At 100 % it works.Cause
mutter has two monitor layout modes, and the window-geometry extension publishes stage coordinates:
layout-modecomp_vk_native_wl_geomalways multiplied bymonitor.scale. That is right in LOGICAL, but in PHYSICAL it doubles values that are already device px.Repro (private headless mutter 50.1, never the shared panel)
A private
gnome-shell --headlessruns with its ownXDG_RUNTIME_DIR, D-Bus and dconf, plus a 3840x2160 virtual monitor. The mode is set withgdctl set --layout-mode physical --scale 2(GetCurrentStatelayout-mode= 2). The repo's extension is enabled.cube_handle_vk_linux --platform=wayland --windowedruns onDXR_PLUGIN_EXCLUSIVE=sim-display(active plug-in: id=sim-display):The same binary in LOGICAL at 200 % converts to
DEVICE 0,180 3840x2160 on a 3840x2160 px monitorand weaves.Fix
Runtime (
comp_vk_native_wl_geom.c, new pureu_wayland_layout.h): the conversion factor is now device px per stage px, resolved per window byu_wl_stage_to_device_scale(), in this order:monitor.device_scale(extension v11).layout_mode(extension v11).layout-modefromorg.gnome.Mutter.DisplayConfig.GetCurrentState. This covers an extension older than v11, e.g. the one a session keeps running until logout after a package upgrade. It is queried once and refreshed onMonitorsChanged.wr.scalecarries the same factor, so the drop-time phase snap searches the right device positions. One WARN names PHYSICAL and where that came from.u_wayland_geom.his untouched on purpose: displayxr-common vendors it byte-for-byte and the test-app build guards that, so this PR does not need a common release.Extension v11 (
lib.js): the snapshot gains a top-levellayout_mode("logical"/"physical") andmonitor.device_scale. mutter does not introspect its layout mode, but the stage view scales give it away (StageScale, pure + unit-tested). No existing field changes meaning, so the schema staysversion: 1. Bumping it would make every shipped runtime refuse a payload that is still correct for it on LOGICAL desktops. The drag-lattice choice and the stamp audit now weigh device px by the same factor.Audit of the extension's other logic
MoveWindow, the pointer drag and the move-sync history all work in stage coordinates, so they follow the mode unchanged.96,208for a buffer at stage1120,720(= mod 256), exactly what the runtime set.The spec (§2, §3, new §4.1) and the extension README are updated.
Verification (headless, sim-display, windowed 1600x900)
NOT_1TO1NOT_1TO1 cleared, weaves 1:1(gdctl snaps a requested 1.75 to 1.6667 on this mode.)
Tests
tests_aux_wayland_geom: PHYSICAL at 200 % lands 1:1; the reported failure (x2 → 7680x4320, "not the panel") is pinned; LOGICAL at 100/125/150/175/200 %; precedence and string parsing.scripts/test_gnome_extension_stage_scale.js(new, added tolint.yml), on the measured view scales.check_gnome_extension.pypass.Follow-ups
weave_set_window_geometry), so the browser's own use of the extension payload needs the same audit (separate repo).🤖 Generated with Claude Code