From 304f958640b34fff6cf080e4abfc720b0718586a Mon Sep 17 00:00:00 2001 From: Lea Anthony Date: Mon, 15 Dec 2025 22:26:25 +1100 Subject: [PATCH] fix(linux): add mutex protection for menuActive flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Address data race in menuActive flag access: - Add menuMutex sync.RWMutex to WindowAttachConfig struct - Protect menuActive read in WindowLostFocus handler with RLock - Protect menuActive writes in AboutToShow and Event handlers with Lock This fixes concurrent access between DBus callbacks (writes) and the WindowLostFocus handler (reads) that could cause data races. Addresses CodeRabbit review comments from PR #4775. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- v3/UNRELEASED_CHANGELOG.md | 6 ++- v3/pkg/application/systemtray.go | 15 ++++++ v3/pkg/application/systemtray_linux.go | 13 +++++ v3/test/4494-systray/Taskfile.yml | 22 +++++++++ v3/test/4494-systray/assets/icon.png | Bin 0 -> 1292 bytes v3/test/4494-systray/assets/index.html | 56 ++++++++++++++++++++++ v3/test/4494-systray/main.go | 64 +++++++++++++++++++++++++ 7 files changed, 174 insertions(+), 2 deletions(-) create mode 100644 v3/test/4494-systray/Taskfile.yml create mode 100644 v3/test/4494-systray/assets/icon.png create mode 100644 v3/test/4494-systray/assets/index.html create mode 100644 v3/test/4494-systray/main.go diff --git a/v3/UNRELEASED_CHANGELOG.md b/v3/UNRELEASED_CHANGELOG.md index 928ae143f..88c4a4b3d 100644 --- a/v3/UNRELEASED_CHANGELOG.md +++ b/v3/UNRELEASED_CHANGELOG.md @@ -17,20 +17,22 @@ After processing, the content will be moved to the main changelog and this file ## Added - Add `XDG_SESSION_TYPE` to `wails3 doctor` output on Linux by @leaanthony -- Add additional WebKit2 load-change events for Linux: `WindowLoadStarted`, `WindowLoadRedirected`, `WindowLoadCommitted`, `WindowLoadFinished` (#3896) by @leaanthony ## Changed ## Fixed +- Fix window menu crash on Wayland caused by appmenu-gtk-module accessing unrealized window (#4769) by @leaanthony +- Fix GTK application crash when app name contains invalid characters (spaces, parentheses, etc.) by @leaanthony +- Fix "not enough memory" error when initializing drag and drop on Windows (#4701) by @overlordtm +- Fix systray context menu hiding attached window on Linux (#4494) by @leaanthony ## Deprecated ## Removed -- **BREAKING**: Remove `linux:WindowLoadChanged` event - use `linux:WindowLoadFinished` instead for detecting when WebView has finished loading (#3896) by @leaanthony ## Security diff --git a/v3/pkg/application/systemtray.go b/v3/pkg/application/systemtray.go index ef0525e54..f60ec80eb 100644 --- a/v3/pkg/application/systemtray.go +++ b/v3/pkg/application/systemtray.go @@ -101,6 +101,14 @@ func (s *SystemTray) Run() { if s.attachedWindow.Window != nil { // Setup listener s.attachedWindow.Window.OnWindowEvent(events.Common.WindowLostFocus, func(event *WindowEvent) { + // On Linux, don't hide when the systray menu is active (opening or open). + // The menu steals focus from the window, but we don't want to hide in this case. + s.attachedWindow.menuMutex.RLock() + menuActive := s.attachedWindow.menuActive + s.attachedWindow.menuMutex.RUnlock() + if menuActive { + return + } s.attachedWindow.Window.Hide() // Special handler for Windows if runtime.GOOS == "windows" { @@ -274,6 +282,13 @@ type WindowAttachConfig struct { // Used to ensure that the window state is read on first click initialClick sync.Once + + // Protects menuActive from concurrent access + menuMutex sync.RWMutex + + // Indicates that the systray menu is currently open or about to open. + // Used on Linux to prevent hiding the attached window when the menu steals focus. + menuActive bool } // AttachWindow attaches a window to the system tray. The window will be shown when the system tray icon is clicked. diff --git a/v3/pkg/application/systemtray_linux.go b/v3/pkg/application/systemtray_linux.go index d1319f4bd..fe629c4e3 100644 --- a/v3/pkg/application/systemtray_linux.go +++ b/v3/pkg/application/systemtray_linux.go @@ -620,6 +620,11 @@ func iconToPX(icon []byte) (PX, error) { // AboutToShow is an implementation of the com.canonical.dbusmenu.AboutToShow method. func (s *linuxSystemTray) AboutToShow(id int32) (needUpdate bool, err *dbus.Error) { + // Mark menu as active to prevent hiding attached window when menu steals focus. + // This is called by the desktop environment before showing the menu. + s.parent.attachedWindow.menuMutex.Lock() + s.parent.attachedWindow.menuActive = true + s.parent.attachedWindow.menuMutex.Unlock() return } @@ -646,6 +651,10 @@ func (s *linuxSystemTray) Event(id int32, eventID string, data dbus.Variant, tim InvokeAsync(item.menuItem.handleClick) } case "opened": + // Menu is now open - keep the flag active + s.parent.attachedWindow.menuMutex.Lock() + s.parent.attachedWindow.menuActive = true + s.parent.attachedWindow.menuMutex.Unlock() if s.parent.clickHandler != nil { s.parent.clickHandler() } @@ -653,6 +662,10 @@ func (s *linuxSystemTray) Event(id int32, eventID string, data dbus.Variant, tim s.parent.onMenuOpen() } case "closed": + // Menu is closed - clear the flag so normal focus behavior resumes + s.parent.attachedWindow.menuMutex.Lock() + s.parent.attachedWindow.menuActive = false + s.parent.attachedWindow.menuMutex.Unlock() if s.parent.onMenuClose != nil { s.parent.onMenuClose() } diff --git a/v3/test/4494-systray/Taskfile.yml b/v3/test/4494-systray/Taskfile.yml new file mode 100644 index 000000000..6e8e2dedd --- /dev/null +++ b/v3/test/4494-systray/Taskfile.yml @@ -0,0 +1,22 @@ +version: '3' + +vars: + APP_NAME: "4494-systray{{exeExt}}" + +tasks: + build: + summary: Builds the test application + cmds: + - go build -o bin/{{.APP_NAME}} . + + run: + summary: Runs the test application + deps: + - build + cmds: + - ./bin/{{.APP_NAME}} + + dev: + summary: Builds and runs the test application + cmds: + - go run . diff --git a/v3/test/4494-systray/assets/icon.png b/v3/test/4494-systray/assets/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..a6129a69feabbeb0bcee252e1ba18fe3c1c0b736 GIT binary patch literal 1292 zcmV+n1@roeP)FFgUB^@0dfq{YU?(W9M#sdQbKR-VP1_r#myriV0 zLqtS7J3HXu;5Ron)z#Ilt*xl2s46Nd+uPf@xw*BqwU(Ba*x1;RkdO}#5Z&F~(b3V) z&dyFwP8Sy!%F4z>%6m(KfQ_kY? z`HTR!ei-)JaZf4fo{6kv4%NF`jsO4yu1Q2eR9M5+*J*#6Fc<)Ey3Mv*+nq54P!L5x zITXCD_fhX2`~Dwh0}>GB`2Fge?Rn)B!{6kINtAl{_7S{0K77BWZmz%u@#QCV4K9ff z*A#UT@cGMyz{jh93Rtp!aJJhb`gz~Y`&`h)J_ib;9FD=R=RU6uaXw~+zqwEz4M>-< zb`FfYH1r~0+&c}OQG@aFgCsiOn@V~xrSds2IWWiz+H5-wY)OV*{vrv^49qMfJw}~# zVEO{HUNDt~)1as_&Wi=X0b4MOLzW_nxHlLAR140C=Qzhee^DoZT+||fxk($59XB9-(}@7u&pz;|IIB_(1MFi1c{!|0ViZvEft9n2Gc_9mdR-aki0^<1Knj4G zGsR&(3`j6b2Cx>RfI^i3`5FrVTMGlronKRa773I~GyyD*lq3K&3zD}@PKW}OM<00Y z0I+F70?@^>03;LP3S?{1o2j?*fj1j~N0f^uKaK{pwGZS(pqX?S80Ld-Neoa6 z070Db%rO8szot*Qel)-aT{b|pR2Tw+MXpalG{9Ltum#Ja`>G)mV9a9>Rthmd=am5Y zG3a>%XsO5n3ByPEX2p1b zVqie#dvSo6BLJGQyzF#7Ox%^B&GG~<3esP>bU>e$q1So8_JD$gzn4&*_u~LCe8NC; zJ7L^iw_mJW;JHwgaRpi&NCgmYS#AlNTG`znjImb{op)aeB_Xz zpSj?WAtl^`1YnX41zdwufT>7Hz*G-C-`$=8`L|^vK+c@tek+th(~@@}0SGRF;A9O0 z$XFx-`xZJL!3dlJaKI)4^X?IVy7O~jE+ztP{s@5hemnx?mI9K2mm`32e?mw{0BWq+ zWME-nfE+ww0M=)AG9Z}&Aa{FbK$8V2K*a};USm%H)Tr1gKp_C2K3Sdsur(CZfD-h3 ztBT+Q!4;hXC`b3{i;ZXH19V9QX}}u#1F*ys0I4~U3ap-JFMhXX9m5ATYr>$`^xmC4-R-+X#k+}z)0GJgQ^J8-}5d&SZK0000 + + + + Systray Test (#4494) + + + +

Systray Test (#4494)

+ +
+

Test Steps:

+
    +
  1. Look for the systray icon in your system tray
  2. +
  3. Right-click the systray icon to open the context menu
  4. +
+ +

Expected: This window should stay visible when the context menu opens

+

Bug: On Linux (Wayland/KDE), this window hides when right-clicking the systray icon

+
+ +
+

Issue Details:

+

When an attached window loses focus (which happens when the context menu opens), + the WindowLostFocus event triggers and hides the window.

+

This is problematic because the user is still interacting with the systray, + not clicking away from it.

+
+ + diff --git a/v3/test/4494-systray/main.go b/v3/test/4494-systray/main.go new file mode 100644 index 000000000..82dc1cbd2 --- /dev/null +++ b/v3/test/4494-systray/main.go @@ -0,0 +1,64 @@ +package main + +import ( + "embed" + _ "embed" + "log" + + "github.com/wailsapp/wails/v3/pkg/application" +) + +//go:embed assets/* +var assets embed.FS + +//go:embed assets/icon.png +var icon []byte + +func main() { + app := application.New(application.Options{ + Name: "Systray Test (#4494)", + Description: "Test for systray context menu hiding attached window", + Assets: application.AssetOptions{ + Handler: application.BundledAssetFileServer(assets), + }, + }) + + // Create the main window + window := app.Window.NewWithOptions(application.WebviewWindowOptions{ + Title: "Systray Test (#4494)", + Width: 400, + Height: 300, + }) + + // Create a systray menu + menu := app.NewMenu() + menu.Add("Show Window").OnClick(func(ctx *application.Context) { + log.Println("Show Window clicked") + window.Show() + }) + menu.Add("Hide Window").OnClick(func(ctx *application.Context) { + log.Println("Hide Window clicked") + window.Hide() + }) + menu.AddSeparator() + menu.Add("Quit").OnClick(func(ctx *application.Context) { + log.Println("Quit clicked") + app.Quit() + }) + + // Create system tray with attached window + // Issue #4494: Right-clicking to open context menu hides the attached window + systemTray := app.SystemTray.New() + systemTray.SetIcon(icon) + systemTray.SetMenu(menu) + systemTray.AttachWindow(window) + + log.Println("Starting application...") + log.Println("TEST: Right-click the systray icon. The window should NOT hide when the context menu opens.") + log.Println("BUG: On Linux (especially Wayland/KDE), the window hides when right-clicking the systray icon.") + + err := app.Run() + if err != nil { + log.Fatal(err) + } +}