Skip to content

fix(systray): recover click type on macOS 27 - #5919

Merged
leaanthony merged 4 commits into
wailsapp:masterfrom
ChewbaccaCookie:fix/5752-macos27-tray-click-event-coercion
Aug 28, 2026
Merged

fix(systray): recover click type on macOS 27#5919
leaanthony merged 4 commits into
wailsapp:masterfrom
ChewbaccaCookie:fix/5752-macos27-tray-click-event-coercion

Conversation

@ChewbaccaCookie

@ChewbaccaCookie ChewbaccaCookie commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Description

Context

macOS 27 Golden Gate (currently in developer beta) rebuilds the menu bar and NSStatusItem
internals substantially. Apple has publicly acknowledged the direction of travel on developer forums thread 832823
(https://developer.apple.com/forums/thread/832823): "Local event monitors are no longer the
recommended way of scanning for events on status items." The wider menu-bar-app ecosystem
(Ice, BetterDisplay, Deskflow, SaneBar, …) is hitting parallel issues. This PR is a tactical
fix for one specific symptom in Wails

Info: a broader review of the local-event-monitor pattern in systemtray_darwin.m is a reasonable follow-up. This is partially already started in #5760.

Problem

On macOS 27 Golden Gate, left-clicking a Wails system tray icon does nothing (#5752).
Right-click still works.

The root cause is a behaviour change in AppKit's event dispatch:

  • NSStatusItem's target/action (-[StatusItemController statusItemClicked:]) fires from the
    button's sendActionOn: handler.
  • Previously, [NSApp currentEvent] inside that action returned the originating
    NSEventTypeLeftMouseDown / NSEventTypeRightMouseDown.

Fix

Introduce a small C helper, systemTrayCoerceEventType, that maps the raw event type to a
button processClick can dispatch on:

  1. If the raw type is already NSEventTypeLeftMouseDown / NSEventTypeRightMouseDown (macOS ≤26
    path), pass it through unchanged.
  2. Otherwise, fall back to [NSEvent pressedMouseButtons] — bit 1 (right) wins over bit 0
    (left), matching existing right-click-takes-precedence semantics.
  3. If nothing is pressed either, default to left — the action wouldn't have fired without a
    click, so something triggered it.

statusItemClicked: sends the coerced value to Go instead of raw event.type. The Go switch is
untouched, so macOS ≤26 behaviour is unchanged.

Fixes #5752.

Type of change

Please select the option that is relevant.

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • WEP (proposal only; no implementation)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How Has This Been Tested?

Was tested on macOS 27.0 beta(26A5388g) and on macOS 26.5.2 (25F84).

  • Windows
  • macOS
  • Linux

Test Configuration

Wails v3.0.0-beta.4 › Wails Doctor
                                                                                                                        
# System
        
┌────────────────────────────┐
| Name          | MacOS      |
| Version       | 27.0       |
| ID            | 26A5388g   |
| Branding      | MacOS 27.0 |
| Platform      | darwin     |
| Architecture  | arm64      |
| Apple Silicon | true       |
| CPU           | Apple M3   |
| CPU           | Apple M3   |
| GPU           | 10 cores   |
| Memory        | 16 GB      |
└────────────────────────────┘
                   
# Build Environment
                   
┌──────────────────────────────────────────────────────────────────────┐
| Wails CLI      | v3.0.0-beta.4                                       |
| Go Version     | go1.26.5                                            |
| -buildmode     | exe                                                 |
| -compiler      | gc                                                  |
| CGO_CFLAGS     |                                                     |
| CGO_CPPFLAGS   |                                                     |
| CGO_CXXFLAGS   |                                                     |
| CGO_ENABLED    | 1                                                   |
| CGO_LDFLAGS    |                                                     |
| DefaultGODEBUG | cryptocustomrand=1,tlssecpmlkem=0,urlstrictcolons=0 |
| GOARCH         | arm64                                               |
| GOARM64        | v8.0                                                |
| GOOS           | darwin                                              |
└──────────────────────────────────────────────────────────────────────┘
              
# Dependencies
              
┌──────────────────────────────────────────────────────────────────────────────────────────────────────────┐
| *Android SDK       | Not found. Set ANDROID_HOME (install via Android Studio or the command-line tools). |
| *NSIS              | Not Installed. Install with `brew install makensis`.                                |
| *Xcode (iOS)       | Not installed. iOS builds need full Xcode (App Store), not just the CLI tools.      |
| *iOS Device SDK    | Not found                                                                           |
| *iOS Simulator SDK | Not found                                                                           |
| Xcode cli tools    | 2417                                                                                |
| npm                | 10.9.8                                                                              |
| docker             | *Not installed (optional - for cross-compilation)                                   |
|                                                                                                          |
└──────────────────────────────────────── * - Optional Dependency ─────────────────────────────────────────┘
         
# Signing
         
┌────────────────────────────────────────┐
| macOS Signing   | Not configured       |
| Windows Signing | Not configured       |
| Linux Signing   | Not configured (GPG) |
└────────────────────────────────────────┘
                     
# Checking for issues
                     
 SUCCESS  No issues found
           
# Diagnosis
           
 SUCCESS  Your system is ready for Wails development!

Checklist:

  • (v2 only) I have updated website/src/pages/changelog.mdx with details of this PR (v3 changelog entries are added automatically)
  • My code follows the general coding style of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation -> no documentation changes done
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes

Summary by CodeRabbit

  • Bug Fixes
    • Improved macOS system tray click handling to correctly identify left- and right-button interactions.
    • Fixed ambiguous click events on newer macOS versions, ensuring tray actions are dispatched reliably.
    • Improved handling when mouse buttons are pressed or released in different event sequences.
    • Ensured right-click actions take precedence when multiple button states are detected.
  • Tests
    • Added regression coverage for macOS system tray mouse-event behavior across supported event sequences.

On macOS 27 Golden Gate, [NSApp currentEvent] inside an NSStatusItem
action selector no longer reflects the originating mouse-down, so
processClick's left/right switch dropped the event.

Coerce via [NSEvent pressedMouseButtons] as a fallback. Behaviour on
macOS <=26 is unchanged (the coercion is a no-op when the raw event
type is already a mouse-down). Adds a table-driven regression test.

Closes wailsapp#5752
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: f7f1bafb-ad66-4d3d-b072-f63cf8c1c114

📥 Commits

Reviewing files that changed from the base of the PR and between 2ca26f4 and d8314bb.

📒 Files selected for processing (1)
  • v3/pkg/application/systemtray_darwin.m

Walkthrough

The Darwin status item callback now coerces macOS event types using the pressed-button state before dispatch. A Go wrapper exposes the C helper for testing. Darwin regression tests cover legacy and macOS 27 event types.

Changes

Darwin status item event handling

Layer / File(s) Summary
Event coercion and callback wiring
v3/pkg/application/systemtray_darwin.h, v3/pkg/application/systemtray_darwin.m, v3/pkg/application/systemtray_darwin.go
The C helper preserves explicit mouse-down events, infers right clicks from the pressed-button mask, defaults to left clicks, and passes the coerced type to systrayClickCallback. The Go wrapper delegates to the C helper.
Event coercion regression coverage
v3/pkg/application/systemtray_darwin_test.go
Darwin-only table-driven tests cover legacy mouse-down events, macOS 27 event types, left-button defaults, mouse-up recovery, and right-button precedence.

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk: ⚪ Minimal · up to 2ca26

This localized macOS system tray fix restores left-click handling while preserving existing right-click behavior, with no actionable merge-blocking risk remaining beyond normal checks and review.

Sequence Diagram(s)

sequenceDiagram
  participant AppKitStatusItem
  participant systemTrayCoerceEventType
  participant systrayClickCallback
  AppKitStatusItem->>systemTrayCoerceEventType: raw event type and pressed mouse buttons
  systemTrayCoerceEventType->>systrayClickCallback: coerced event type
Loading

Poem

I’m a rabbit with ears held high,
Coercing clicks beneath the sky.
Left or right, the path is clear,
macOS 27 now behaves near.
Tests hop through each event with cheer.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the macOS 27 system tray click fix, which is the main change.
Description check ✅ Passed The description includes context, issue reference, fix details, testing information, configuration, change type, and completed relevant checklists.
Linked Issues check ✅ Passed The changes address issue #5752 by coercing macOS 27 tray events so the existing Go click handling can open the context menu.
Out of Scope Changes check ✅ Passed The helper, integration change, and Darwin regression tests are directly related to the macOS 27 system tray click issue.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@ChewbaccaCookie
ChewbaccaCookie force-pushed the fix/5752-macos27-tray-click-event-coercion branch from 3563e45 to cbe84c2 Compare August 6, 2026 15:17
@ChewbaccaCookie ChewbaccaCookie changed the title fix: macos 27 left mouse click system tray fix fix(systray): recover click type on macOS 27 Aug 6, 2026
amigoer added a commit to amigoer/mq-studio that referenced this pull request Aug 7, 2026
Closing the window quit the process, which ends the background sampling
the collector now does. Intercept WindowClosing and hide the window
instead, so the app stays resident and keeps collecting.

A new closeBehavior setting under Settings > General picks between
minimising to the tray and quitting outright, defaulting to the tray.
Because the hook must decide before the window is destroyed, the choice
is read in Go; the renderer only skips its own quit confirmation when
the window will merely hide.

The tray menu restores the window, jumps to a page, opens settings, or
quits. Page jumps travel as a tray:navigate event the renderer turns
into a sidebar selection. Its labels cannot come from the frontend i18n
bundles, which the Go process never loads, so the handful of strings
live in the tray package and follow the language setting through a new
change listener on the configuration service.

Two Wails constraints shaped this. The native menu is bound once when
the tray starts and never rebound, so the menu is built up front and
only relabelled afterwards. And a tray click only reaches native menu
tracking while no click handler is registered, so none is - registering
one silently falls back to a path where the left button does nothing.

Note that macOS 26+ breaks the left button regardless: the status item
action no longer sees the originating mouse-down, so the click type
Wails dispatches on is one its switch does not handle. Right-click
works. Upstream fix: wailsapp/wails#5919.
@taliesin-ai taliesin-ai added v3 and removed v3-alpha labels Aug 9, 2026
@ffeldmann

Copy link
Copy Markdown

Upvote for this one :)

@coderabbitai

coderabbitai Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@misa198

misa198 commented Aug 20, 2026

Copy link
Copy Markdown

Works like a charm. Can we get this reviewed and merged?

@ffeldmann

Copy link
Copy Markdown

Hi maintainers, would be great to have that in before the release of Mac OSX 27, works like a charm! :-)

@leaanthony leaanthony left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks for this!

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 addresses a macOS 27 (Golden Gate) behavior change where -[NSApp currentEvent] inside an NSStatusItem action can no longer be relied on to determine whether the status item was left- or right-clicked. It adds a small native helper to coerce the event type using +[NSEvent pressedMouseButtons], and pins the behavior with a darwin-only regression test.

Changes:

  • Added systemTrayCoerceEventType (ObjC/C) to map non-mouse-down currentEvent types to left/right mouse-down using pressed mouse button state.
  • Updated statusItemClicked: to send the coerced event type to the Go callback.
  • Added a darwin regression test to lock in the macOS 27 click-type recovery behavior.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
v3/pkg/application/systemtray_darwin.m Adds the event-type coercion helper and uses it when dispatching tray click callbacks.
v3/pkg/application/systemtray_darwin.h Documents and exposes systemTrayCoerceEventType for regression testing.
v3/pkg/application/systemtray_darwin.go Adds a small Go wrapper for the C helper to make it callable from tests.
v3/pkg/application/systemtray_darwin_test.go Adds darwin-only regression coverage for macOS 27 event coercion behavior.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread v3/pkg/application/systemtray_darwin.m Outdated
leaanthony and others added 2 commits August 29, 2026 08:33
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@leaanthony
leaanthony merged commit 8a6979c into wailsapp:master Aug 28, 2026
2 of 5 checks passed
@leaanthony

Copy link
Copy Markdown
Member

Thanks all for testing!

leaanthony pushed a commit that referenced this pull request Aug 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[v3][macOS 27] Tray menu fails to open/render on click

6 participants