fix(linux): account for window decorator offset on Wayland for max size constraints#4778
fix(linux): account for window decorator offset on Wayland for max size constraints#4778leaanthony wants to merge 3 commits into
Conversation
…ze constraints Ports the v2 fix from PR #4047 to v3. On Wayland, GTK reports window allocation size including decorations (header bar, shadows), but gtk_window_get_size() returns the size without decorations. This caused max size constraints to be too restrictive, preventing fullscreen and maximize from filling the screen properly. The fix calculates and caches the decorator offset (difference between allocated size and window size) and adds it to max width/height when setting geometry hints on Wayland. Fixes #4429 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
WalkthroughAdds Wayland-specific window decorator offset caching to the Linux GTK backend. A shared ChangesWayland Decorator Offset Fix
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Possibly related PRs
Suggested labels
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
⚔️ Resolve merge conflicts
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 golangci-lint (2.12.2)level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies" Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Deploying wails with
|
| Latest commit: |
a774f93
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://28e97de9.wails.pages.dev |
| Branch Preview URL: | https://fix-4429-wayland-maxsize.wails.pages.dev |
|
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@v3/pkg/application/application_linux.go`:
- Around line 85-92: The package-global decoratorOffset in application_linux.go
is causing the first Wayland window’s delta to be reused across later windows
and can be seeded before setFrameless() changes decoration state. Move this
cached offset onto linuxWebviewWindow, or explicitly invalidate/recompute it
when decoration settings change, and make windowSetGeometryHints() read the
per-window value instead of shared package state.
- Around line 97-101: `isWayland()` currently keys off `XDG_SESSION_TYPE` and
`decoratorOffset` is cached globally, which can mis-detect the actual GTK
backend and reuse one window’s decoration delta for all windows. Update the
logic in `isWayland()`/the related window offset path in `application_linux.go`
to inspect the backend from the window or GTK/GDK state instead of the
environment, and remove the process-wide one-time cache so the decoration offset
is computed per window rather than stored in `waylandOnce`/`waylandDetected`.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: e8df94e5-4ffd-4488-85a9-1825dfb9a488
📒 Files selected for processing (3)
v3/pkg/application/application_linux.gov3/pkg/application/linux_cgo.gov3/pkg/application/linux_purego.go
| var ( | ||
| waylandOnce sync.Once | ||
| waylandDetected bool | ||
| decoratorOffset struct { | ||
| width int | ||
| height int | ||
| once sync.Once | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
rg -n -C2 'windowSetGeometryHints\(|setDecorated|gtk_window_set_decorated' v3/pkg/applicationRepository: wailsapp/wails
Length of output: 2723
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n== application_linux.go ==\n'
sed -n '1,140p' v3/pkg/application/application_linux.go
printf '\n== linux_purego.go: windowSetGeometryHints ==\n'
sed -n '900,980p' v3/pkg/application/linux_purego.go
printf '\n== linux_cgo.go: windowSetGeometryHints ==\n'
sed -n '1230,1305p' v3/pkg/application/linux_cgo.goRepository: wailsapp/wails
Length of output: 9520
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n== call sites of windowSetGeometryHints and setFrameless ==\n'
rg -n -C 3 'windowSetGeometryHints\(|setFrameless\(' v3/pkg/application
printf '\n== linuxWebviewWindow struct / window creation area ==\n'
rg -n -C 3 'type linuxWebviewWindow|NewWebviewWindow|frameless|Decorated|GeometryHints' v3/pkg/application/linux_cgo.go v3/pkg/application/linux_purego.go v3/pkg/application/webview_window_linux.goRepository: wailsapp/wails
Length of output: 11893
🏁 Script executed:
#!/bin/bash
set -euo pipefail
sed -n '120,340p' v3/pkg/application/webview_window_linux.goRepository: wailsapp/wails
Length of output: 5810
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n== setMinMaxSize / setMaxSize call sites ==\n'
rg -n -C 2 'setMinMaxSize\(|setMaxSize\(' v3/pkg/application
printf '\n== any reset or update of decorator offset ==\n'
rg -n -C 2 'decoratorOffset|setDecoratorOffset\(' v3/pkg/applicationRepository: wailsapp/wails
Length of output: 8523
Cache the decorator delta per window
decoratorOffset is package-global, so the first Wayland window seeds the offset for every later window. setMinMaxSize() also runs before setFrameless(), which means a frameless window can cache the wrong delta and later windowSetGeometryHints() calls will reuse it. Move this state onto linuxWebviewWindow or invalidate/recompute it when decoration changes.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@v3/pkg/application/application_linux.go` around lines 85 - 92, The
package-global decoratorOffset in application_linux.go is causing the first
Wayland window’s delta to be reused across later windows and can be seeded
before setFrameless() changes decoration state. Move this cached offset onto
linuxWebviewWindow, or explicitly invalidate/recompute it when decoration
settings change, and make windowSetGeometryHints() read the per-window value
instead of shared package state.
| func isWayland() bool { | ||
| waylandOnce.Do(func() { | ||
| waylandDetected = os.Getenv("XDG_SESSION_TYPE") == "wayland" | ||
| }) | ||
| return waylandDetected |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
sed -n '95,120p' v3/pkg/application/application_linux.go
sed -n '238,242p' v3/pkg/application/linux_purego.go
rg -n -C2 'isWayland\(' v3/pkg/applicationRepository: wailsapp/wails
Length of output: 2862
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '--- application_linux.go (85-125) ---'
sed -n '85,125p' v3/pkg/application/application_linux.go
echo '--- linux_purego.go (900-950) ---'
sed -n '900,950p' v3/pkg/application/linux_purego.go
echo '--- linux_cgo.go (1228-1275) ---'
sed -n '1228,1275p' v3/pkg/application/linux_cgo.go
echo '--- backend detection/search ---'
rg -n -C2 'GDK_BACKEND|XDG_SESSION_TYPE|isWayland\(|decoratorOffset|gtk_widget|gtk_window_get' v3/pkg/applicationRepository: wailsapp/wails
Length of output: 23425
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '--- setDecoratorOffset call sites ---'
rg -n -C3 'setDecoratorOffset\(' v3/pkg/application
echo '--- windowSetGeometryHints call sites ---'
rg -n -C3 'windowSetGeometryHints\(' v3/pkg/application
echo '--- frameless/decorated related call sites ---'
rg -n -C2 'setFrameless\(|gtk_window_set_decorated|frameless' v3/pkg/applicationRepository: wailsapp/wails
Length of output: 18880
🏁 Script executed:
#!/bin/bash
set -euo pipefail
sed -n '150,190p' v3/pkg/application/webview_window_linux.goRepository: wailsapp/wails
Length of output: 1294
Detect the GTK backend from the window, not XDG_SESSION_TYPE, and avoid a global offset cache.
v3/pkg/application/linux_purego.goforcesGDK_BACKEND=x11, soisWayland()can take the Wayland branch on an X11 backend.decoratorOffsetis process-wide and one-time; the first window’s decoration delta is reused for every later window, which breaks mixed window setups.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@v3/pkg/application/application_linux.go` around lines 97 - 101, `isWayland()`
currently keys off `XDG_SESSION_TYPE` and `decoratorOffset` is cached globally,
which can mis-detect the actual GTK backend and reuse one window’s decoration
delta for all windows. Update the logic in `isWayland()`/the related window
offset path in `application_linux.go` to inspect the backend from the window or
GTK/GDK state instead of the environment, and remove the process-wide one-time
cache so the decoration offset is computed per window rather than stored in
`waylandOnce`/`waylandDetected`.
|
Closing as part of the v3 beta triage sweep. Master has moved under this branch: the default Linux backend is now GTK4, where max size is enforced by client-side clamping using content size (no decorations), so the #4429 offset problem does not apply to that path; the patched geometry-hints code only remains in the GTK3 fallback; and the linux_purego.go part of the diff targets a file that was deleted from master (purego backend redone in #5715). The approach also caches the decorator offset via sync.Once at the first geometry-hints call, which happens before the window is realized (allocation 1x1), so it would cache a large negative offset and permanently shrink max-size constraints on Wayland. If #4429 still reproduces on the GTK3 fallback, a fresh fix should compute the offset only after realization, per call rather than cached once. |



Summary
gtk_window_get_size()returns size without decorationsTechnical Details
isWayland()helper that caches Wayland detection viaXDG_SESSION_TYPEenvironment variablesetDecoratorOffset()andgetDecoratorOffset()functions to calculate and cache the decorator dimensionswindowSetGeometryHintsin both CGO and PureGo implementations to add decorator offset to max width/heightTest plan
Fixes #4429
🤖 Generated with Claude Code
Summary by CodeRabbit