Skip to content

fix(windows): Prevent systray menu crash on rapid clicks (#4151) - #4812

Merged
leaanthony merged 2 commits into
v3-alphafrom
vk/3b03-windows-v3-somet
Dec 25, 2025
Merged

leaanthony merged 2 commits into
v3-alphafrom
vk/3b03-windows-v3-somet

Conversation

@leaanthony

@leaanthony leaanthony commented Dec 17, 2025 •

Copy link
Copy Markdown
Member

Summary

  • Fix Windows systray menu crash when clicking icon repeatedly by adding guard against concurrent TrackPopupMenuEx calls
  • Add isShowing atomic.Bool field to prevent race condition in popup menu display
  • Change TrackPopupMenuEx failure from fatal crash to graceful debug log with early return

Fixes #4151

Test plan

  • Run v3/examples/systray-menu example on Windows
  • Rapidly click the systray icon multiple times
  • Verify the application no longer crashes with "TrackPopupMenu failed"
  • Verify the menu still displays correctly on normal clicks

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Fixed a Windows system tray crash that could occur when the tray icon was clicked rapidly.
    • Improved system tray menu positioning and display stability on Windows to reduce misplacement near screen edges.

✏️ Tip: You can customize this high-level summary in your review settings.

Add guard against concurrent TrackPopupMenuEx calls using atomic.Bool
to prevent race condition when user clicks systray icon repeatedly.
Change TrackPopupMenuEx failure from fatal to debug log with early
return so the application gracefully handles failed menu display
attempts instead of crashing.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Dec 17, 2025 •

Copy link
Copy Markdown
Contributor

Caution

Review failed

The pull request is closed.

Walkthrough

Added an atomic concurrency guard to prevent simultaneous TrackPopupMenuEx calls on Windows, converted a fatal TrackPopupMenuEx error to a non-fatal debug log with early return, and added monitor-aware menu positioning (bottom-left preference with right-edge adjustment). Changes limited to systray/menu display logic and changelog.

Changes

Cohort / File(s) Summary
Windows popup menu logic
v3/pkg/application/popupmenu_windows.go
Added isShowing (atomic.Bool) to Win32Menu and a CAS guard to serialize TrackPopupMenuEx calls; changed fatal error on TrackPopupMenuEx failure to debug log + early return; added monitor-aware positioning (prefer bottom-left, adjust for right edge); added sync/atomic import.
Changelog
v3/UNRELEASED_CHANGELOG.md
Added entry describing guard against concurrent menu popups and Windows systray crash fix.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

Windows, Bug, v3-alpha, size:M

Poem

🐰 I hopped to guard the popup gate,
Atoms standing watch — no race or fate.
Menus open once, no crashing fray,
I nibble bugs and hop away. 🎉

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The PR title clearly and specifically describes the main change: preventing systray menu crashes on rapid clicks in Windows, which aligns with the primary objective of fixing issue #4151.
Description check ✅ Passed The PR description adequately covers the bug fix with summary, linked issue reference, and test plan. While some optional checklist items are unchecked, the core required information is present.
Linked Issues check ✅ Passed The code changes directly address the objectives in linked issue #4151: adding a concurrency guard (isShowing atomic.Bool) to prevent concurrent TrackPopupMenuEx calls and changing fatal error handling to graceful debug logging.
Out of Scope Changes check ✅ Passed All changes in the PR are directly scoped to fixing the systray menu crash issue: concurrency guard, error handling improvement, and screen-positioning logic are all within the scope of stabilizing rapid menu interactions.

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fb35afd and efc9ec5.

📒 Files selected for processing (1)
  • v3/UNRELEASED_CHANGELOG.md

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.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Dec 17, 2025 •

Copy link
Copy Markdown

Deploying wails with  Cloudflare Pages  Cloudflare Pages

Latest commit: efc9ec5
Status:⚡️  Build in progress...

View logs

@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: 0

🧹 Nitpick comments (1)
v3/pkg/application/popupmenu_windows.go (1)

221-225: Consider extracting magic numbers as named constants.

The hardcoded 200 (assumed menu width) and 10 (padding) work but are opaque. Named constants would improve readability.

+const (
+	estimatedMenuWidth = 200 // pixels; used for right-edge detection
+	menuEdgePadding    = 10  // pixels; spacing from screen edge
+)
+
 // Check if we're close to the right edge of the screen
 // If so, right-align the menu with some padding
-if x > int(monitorInfo.RcWork.Right)-200 { // Assuming 200px as a reasonable menu width
+if x > int(monitorInfo.RcWork.Right)-estimatedMenuWidth {
 	menuFlags = uint32(w32.TPM_RIGHTALIGN | w32.TPM_BOTTOMALIGN)
 	// Add a small padding (10px) from the right edge
-	x = int(monitorInfo.RcWork.Right) - 10
+	x = int(monitorInfo.RcWork.Right) - menuEdgePadding
 }
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a81cb18 and fb35afd.

📒 Files selected for processing (2)
  • v3/UNRELEASED_CHANGELOG.md (1 hunks)
  • v3/pkg/application/popupmenu_windows.go (4 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-01-24T22:41:18.566Z
Learnt from: leaanthony
Repo: wailsapp/wails PR: 4031
File: v3/pkg/application/menu.go:199-202
Timestamp: 2025-01-24T22:41:18.566Z
Learning: In the Wails menu system (v3/pkg/application/menu.go), shared state between menus is intentionally designed and desirable. Methods like `Append()` and `Prepend()` should maintain shared references to menu items rather than creating deep copies.

Applied to files:

  • v3/pkg/application/popupmenu_windows.go
📚 Learning: 2025-02-04T23:59:43.956Z
Learnt from: fbbdev
Repo: wailsapp/wails PR: 4045
File: v3/internal/generator/render/info.go:28-68
Timestamp: 2025-02-04T23:59:43.956Z
Learning: In the Wails v3 project, internal functions are designed to panic on nil parameters as they represent contract violations, rather than adding defensive nil checks.

Applied to files:

  • v3/pkg/application/popupmenu_windows.go
📚 Learning: 2024-10-08T22:11:37.054Z
Learnt from: leaanthony
Repo: wailsapp/wails PR: 3763
File: v3/examples/window/main.go:472-475
Timestamp: 2024-10-08T22:11:37.054Z
Learning: In `v3/examples/window/main.go`, `time.Sleep` is used within a goroutine and does not block the UI thread.

Applied to files:

  • v3/pkg/application/popupmenu_windows.go
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Analyze (go)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: Cloudflare Pages
🔇 Additional comments (4)
v3/pkg/application/popupmenu_windows.go (3)

54-54: Concurrency guard field is well-placed.

Using atomic.Bool as an instance field correctly scopes the guard to each Win32Menu, allowing different menus to display independently while preventing re-entrant calls on the same menu.


195-200: Solid concurrency guard implementation.

The CompareAndSwap + defer Store(false) pattern correctly prevents concurrent TrackPopupMenuEx calls. The defer ensures the flag is reset on all exit paths including early returns and panics.


227-232: Good error handling change.

Converting the fatal crash to a debug log with early return is the right approach for transient failures during rapid clicks. The guard should prevent most failures, but this provides a safe fallback if TrackPopupMenuEx fails for other reasons (e.g., menu already dismissed).

v3/UNRELEASED_CHANGELOG.md (1)

28-28: Verify the author attribution.

The changelog attributes this fix to @anthropics-ai, but the PR was opened by @leaanthony. Should this be attributed to the PR author instead?

@leaanthony
leaanthony merged commit f30c888 into v3-alpha Dec 25, 2025
9 of 12 checks passed
@leaanthony
leaanthony deleted the vk/3b03-windows-v3-somet branch December 25, 2025 08:35
@sonarqubecloud

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot mentioned this pull request Feb 13, 2026
13 tasks done
@coderabbitai coderabbitai Bot mentioned this pull request Apr 24, 2026
10 of 15 tasks
Grantmartin2002 pushed a commit to Grantmartin2002/wails that referenced this pull request Apr 29, 2026
…) (wailsapp#4812)

Add guard against concurrent TrackPopupMenuEx calls using atomic.Bool
to prevent race condition when user clicks systray icon repeatedly.
Change TrackPopupMenuEx failure from fatal to debug log with early
return so the application gracefully handles failed menu display
attempts instead of crashing.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Vibe Kanban <noreply@vibekanban.com>
Co-authored-by: Claude <noreply@anthropic.com>
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.

1 participant