Skip to content

[v3] setMenuItemChecked() applies state after menu is shown on macOS (dispatch_async race) #5002

@RALIST

Description

@RALIST

Description

When using context menus with checkbox (checked) items on macOS, calling setMenuItemChecked() does not update the visual state in time — the checkmark appears stale when the menu opens.

Root cause: The Objective-C implementation of setMenuItemChecked() wraps the NSMenuItem.state assignment inside dispatch_async(dispatch_get_main_queue(), ...). This means the state change is enqueued and executes after the menu has already been rendered and shown to the user.

As a result, if you update checked state in response to an action and then the user right-clicks to reopen the context menu, the menu displays the previous checked state rather than the current one.

To Reproduce

  1. Create an application context menu with checkbox-style items (e.g., Bold, Italic formatting toggles)
  2. Use the context menu to toggle an item (e.g., Bold on)
  3. Immediately right-click again to reopen the context menu
  4. Observe that the checked state shown is stale (reflects the state before the toggle)

The issue occurs because:

  • The action callback fires and calls setMenuItemChecked(true)
  • dispatch_async enqueues the NSMenuItem.state = NSControlStateValueOn call
  • The user opens the menu again before the async block executes
  • Menu renders with the old state

Expected behaviour

setMenuItemChecked() should update NSMenuItem.state synchronously (or at least before the menu is displayed). If the call originates from the main thread, dispatch_async is unnecessary. If it comes from a background thread, dispatch_sync or checking NSThread.isMainThread would ensure the state is applied before the menu renders.

Workaround

On the application side, we work around this by manually re-reading the current state after each action triggered from the context menu and pushing it to Go via an explicit IPC call, ensuring the Go-side state is up to date before the next menu open. Deduplication prevents unnecessary IPC when the state hasn't actually changed.

Related issues

These are related but focus on systray menus. This issue affects application context menus with checked items.

System Details

Wails v3 alpha
Platform: macOS (darwin/arm64)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status

    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions