Skip to content

fix(linux): implement setAlwaysOnTop + fix SoupMessageHeaders leak (GTK4 + GTK3)#5488

Merged
leaanthony merged 5 commits into
masterfrom
fix/linux-gtk4-gaps
May 22, 2026
Merged

fix(linux): implement setAlwaysOnTop + fix SoupMessageHeaders leak (GTK4 + GTK3)#5488
leaanthony merged 5 commits into
masterfrom
fix/linux-gtk4-gaps

Conversation

@leaanthony

@leaanthony leaanthony commented May 21, 2026

Copy link
Copy Markdown
Member

Summary

Fixes three issues identified during review of PR #4570 (webkit_6 for v2) that were present or partially addressed in the v3 GTK4 codebase:

  • setAlwaysOnTop implemented via _NET_WM_STATE_ABOVE on X11, following the same dlsym-based function loading pattern already used for XMoveWindow/XTranslateCoordinates. No-op on Wayland — there is no compositor-neutral standard protocol for this in GTK4.
  • SoupMessageHeaders reference leak fixed in both GTK4 (webkit_linux.go) and GTK3 (webkit_linux_gtk3.go) asset-serving paths. soup_message_headers_new allocates a struct the caller owns; passing it to webkit_uri_scheme_response_set_http_headers does not transfer ownership, so the caller's ref was leaking one count per asset request served. Added defer soup_message_headers_unref immediately after allocation.
  • Dead GBytes allocation removed from linuxApp.setIcon: the previous code allocated a GBytes from the icon slice and immediately unref'd it without doing anything — effectively a no-op with a transient alloc. Both linuxApp.setIcon and linuxWebviewWindow.setIcon now have accurate comments explaining the GTK4 limitation: per-window icon APIs were removed in GTK4; the application icon is set via the .desktop file's Icon= field.

What's still a known limitation

  • setAlwaysOnTop is X11-only. Wayland does not expose a standard client-side API for this; it would require compositor-specific protocols (e.g. wlr-layer-shell, xdg-activation).
  • setIcon from bytes has no equivalent in GTK4. This is a GTK4 platform limitation, not a Wails gap.

Relation to PR #4570

These issues were surfaced while reviewing #4570 (webkit_6 opt-in for v2 Linux). The v2 PR has additional blockers that are tracked separately in a comment on that PR.

Test plan

  • Linux/X11: build with default tags (!gtk3), verify SetAlwaysOnTop(true/false) toggles window stacking order
  • Linux/Wayland: verify SetAlwaysOnTop is a silent no-op (no crash)
  • Linux: verify asset serving works correctly with no regression (existing tests)
  • Linux/GTK3: build with -tags gtk3, verify asset serving works

Summary by CodeRabbit

  • New Features

    • Added always-on-top window support for Linux (X11)
  • Bug Fixes

    • Fixed a native memory leak in WebKit response header handling on Linux
    • Improved native resource cleanup for greater stability and performance

Review Change Stack

… GTK4/GTK3 paths

- Implement setAlwaysOnTop via _NET_WM_STATE_ABOVE on X11 (no-op on Wayland,
  which has no standard compositor-neutral protocol for this)
- Fix SoupMessageHeaders reference leak: soup_message_headers_new transfers
  a floating ref to the caller; add soup_message_headers_unref after passing
  to webkit_uri_scheme_response_set_http_headers in both GTK4 and GTK3 paths
- Remove dead GBytes allocation in linuxApp.setIcon (allocated and unref'd
  without use); clarify GTK4 limitation in both app-level and window-level
  setIcon — GTK4 removed per-window icon APIs, icon is set via .desktop file
Copilot AI review requested due to automatic review settings May 21, 2026 01:17
@coderabbitai

coderabbitai Bot commented May 21, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: fdef33a9-f0fe-4e6d-80b0-4dbe271e3395

📥 Commits

Reviewing files that changed from the base of the PR and between 9a0e132 and fe8176e.

📒 Files selected for processing (1)
  • v3/pkg/application/linux_cgo.c

Walkthrough

Adds WebKit header unrefs to avoid C leaks, documents GTK4 per-window icon removal, and implements X11 always-on-top behavior with runtime symbol loading and Go bindings to apply/reapply the state.

Changes

Linux Platform Improvements

Layer / File(s) Summary
WebKit HTTP header memory cleanup
v3/internal/assetserver/webview/webkit_linux.go, v3/internal/assetserver/webview/webkit_linux_gtk3.go
SoupMessageHeaders created in webkit_uri_scheme_request_finish are now deferred-unreferenced to prevent C-side memory leaks.
GTK4 icon behavior documentation
v3/pkg/application/linux_cgo.go
App and window icon setters are documented as GTK4 no-ops; per-window icon APIs removed, icons now supplied via .desktop Icon= field.
X11 always-on-top header and symbol loading
v3/pkg/application/linux_cgo.h, v3/pkg/application/linux_cgo.c
Header declares prototypes for always-on-top helpers; runtime symbol resolution extended to load XSendEvent and XInternAtom via dlsym.
X11 always-on-top core implementation
v3/pkg/application/linux_cgo.c
Implements window state storage and X11 ClientMessage delivery: interns _NET_WM_STATE atoms, builds an _NET_WM_STATE_ABOVE message, sends via XSendEvent to root, and optionally flushes display.
X11 always-on-top Go wrapper and window integration
v3/pkg/application/linux_cgo.go
setAlwaysOnTop(bool) calls C helper (X11-only, no-op on Wayland). windowShow() re-applies pending always-on-top state once window surface exists.

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • wailsapp/wails#4923: Modifies Linux icon handling in v3/pkg/application/linux_cgo.go and manages icon memory lifetimes in the same functions.

Suggested labels

Bug, go, Linux, v3, size:L

Suggested reviewers

  • atterpac

Poem

🐰 I hopped through headers, left none behind,
I unrefbed crumbs so memory's kind.
I nudged windows upward, atop they stay,
And whispered GTK4: icons go your way.
Cheers from a rabbit, code cleaned today!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.57% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely summarizes the three main changes: implementing setAlwaysOnTop on Linux and fixing the SoupMessageHeaders leak for both GTK4 and GTK3.
Description check ✅ Passed The description provides comprehensive context including a detailed summary of all three fixes, known limitations, relation to other PRs, and a test plan. However, the PR template checklists and Type of change selection are not completed.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/linux-gtk4-gaps

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@leaanthony leaanthony mentioned this pull request May 21, 2026
15 tasks

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR improves the Linux frontend (GTK4 + GTK3) by implementing X11 always-on-top behavior, fixing a libsoup header reference leak in the asset server, and removing a dead GTK4 icon-setting allocation while clarifying the GTK4 icon limitation.

Changes:

  • Implement SetAlwaysOnTop on X11 (GTK4) via _NET_WM_STATE_ABOVE, using the existing dlsym-based X11 symbol resolution approach.
  • Fix a SoupMessageHeaders reference leak in the WebKit URI-scheme response path (GTK4 + GTK3).
  • Remove an unused GBytes allocation in GTK4 icon-setting and replace it with accurate limitation comments.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
v3/pkg/application/linux_cgo.h Adds the C API declaration for window_set_always_on_top.
v3/pkg/application/linux_cgo.go Removes dead GTK4 icon code; wires setAlwaysOnTop to the new C helper and updates icon comments.
v3/pkg/application/linux_cgo.c Adds X11 _NET_WM_STATE_ABOVE ClientMessage implementation with dlsym-loaded Xlib calls.
v3/internal/assetserver/webview/webkit_linux.go Unrefs SoupMessageHeaders to prevent a per-request leak (GTK4).
v3/internal/assetserver/webview/webkit_linux_gtk3.go Unrefs SoupMessageHeaders to prevent a per-request leak (GTK3).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread v3/pkg/application/linux_cgo.c
Comment thread v3/pkg/application/linux_cgo.c

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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/linux_cgo.c`:
- Around line 964-966: window_set_always_on_top currently returns early when
gtk_native_get_surface(native) is NULL, so the X11 _NET_WM_STATE_ABOVE message
never gets sent if setAlwaysOnTop is called before the surface exists; modify
the logic to cache the desired AlwaysOnTop state (e.g., a field on the window
struct) when gtk_native_get_surface(native) is NULL and schedule a retry after
the window is realized/presented, then in windowShow/present (linux_cgo.go) call
the retry path to apply the cached value; ensure updates happen from the same
symbol paths: window_set_always_on_top, the cached AlwaysOnTop flag on the
window object, and the present/windowShow flow used by webview_window_linux.go
-> w.setAlwaysOnTop so the flag is applied once the GTK surface exists.
🪄 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: dc701e8a-87e4-4b9e-9079-c45946d417f5

📥 Commits

Reviewing files that changed from the base of the PR and between 2f7c250 and 3031f6c.

📒 Files selected for processing (5)
  • v3/internal/assetserver/webview/webkit_linux.go
  • v3/internal/assetserver/webview/webkit_linux_gtk3.go
  • v3/pkg/application/linux_cgo.c
  • v3/pkg/application/linux_cgo.go
  • v3/pkg/application/linux_cgo.h

Comment thread v3/pkg/application/linux_cgo.c
pkg.InstallCommand is a string, not map[string]string. Indexing it
with a string key doesn't compile. Use the field directly, matching
every other package manager implementation.
If setAlwaysOnTop is called before the window is shown (GTK surface
doesn't exist yet), the X11 ClientMessage had nowhere to go and the
call was silently lost.

Store the desired state in g_object_data (1=true, 2=false; NULL=never
set) so we can distinguish "set to false" from "never called". Add
window_apply_pending_always_on_top() and call it from windowShow()
after gtk_window_present, so the state is applied as soon as the
surface exists.
XClientMessageEvent.display must be initialized to the X11 display
connection. Leaving it zeroed can cause window managers to ignore the
message or trigger undefined behaviour in Xlib.
@leaanthony

Copy link
Copy Markdown
Member Author

Addressed both outstanding Copilot inline comments:

Line 965 (surface NULL): Fixed in commit 3629288. window_set_always_on_top now stores the desired state via g_object_set_data (sentinels 1=true, 2=false; NULL=never set) regardless of whether the surface exists. windowShow() calls window_apply_pending_always_on_top() after gtk_window_present, so the state is applied as soon as the surface is available.

Line 981 (xclient.display not set): Fixed in commit fe8176e. Added xev.xclient.display = xdisplay to the XClientMessageEvent initialisation.

@leaanthony leaanthony merged commit 6825d76 into master May 22, 2026
20 of 21 checks passed
@leaanthony leaanthony deleted the fix/linux-gtk4-gaps branch May 22, 2026 13:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants