Skip to content

fix(v3/windows): SetLabel/SetChecked/SetHidden/SetEnabled are no-ops - #5944

Merged
leaanthony merged 7 commits into
wailsapp:masterfrom
gilad-ch:fix/windows-submenu-item-command-id
Aug 11, 2026
Merged

leaanthony merged 7 commits into
wailsapp:masterfrom
gilad-ch:fix/windows-submenu-item-command-id

Conversation

@gilad-ch

@gilad-ch gilad-ch commented Aug 10, 2026 •

Copy link
Copy Markdown
Contributor

Description

On Windows Systray menu, runtime mutations on a submenu parent row (File ▶, Demo ▶, etc.) are silent no-ops: SetLabel, SetChecked, SetEnabled/SetDisabled, and SetHidden update Go state but the native menubar/popup UI never changes. Items inside a submenu work fine; only the parent row that opens the dropdown is affected. macOS and Linux are unaffected.

Severity: medium (P2). Not a crash or data loss, but a cross-platform API contract break that is hard to diagnose because Win32 failures are not surfaced to Go. Apps that dynamically update menubar submenu labels or state work on other platforms and appear broken on Windows.

Root cause: AppendMenu with MF_POPUP uses uIDNewItem as the child submenu HMENU, not as a command ID. Wails assigns every MenuItem an ID and later addresses rows with MF_BYCOMMAND (SetMenuItemInfo, RemoveMenu, etc.). Submenu parents are appended without that ID, so those lookups miss and the mutation is dropped.

Fix (9 lines of logic): immediately after AppendMenu for submenu items, call SetMenuItemInfo by position to assign the Wails command ID (assignCommandID). Also store the child HMENU on menuItemImpl.submenu in menu_windows.go (already done in popupmenu_windows.go) so hide/show reinsert can reattach the dropdown via getMenuInfo().

Both Windows menu builders are patched: windowsMenu.processMenu and Win32Menu.buildMenu.

Fixes #5943

Type of change

  • 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?

Verified manually on Windows 11 with this branch:

  1. Built and ran the menu example with UseApplicationMenu: true.
  2. Obtained a submenu parent item via menu.FindByLabel("Demo") (or equivalent role submenu).
  3. Called SetLabel, SetEnabled(false), and SetHidden(true) on that parent item.
  4. Confirmed the menubar row updates correctly (label, enabled state, visibility).

Repro code and expected behaviour are documented in #5943.

  • Windows
  • macOS
  • Linux

Test Configuration

Windows 11, windows/amd64, Wails v3 source build from this branch.

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
  • 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 Windows menu rebuilding to preserve submenu state during updates and recover cleanly if an update fails.
  • Fixed hidden submenu items so they can be restored with their original behavior intact.
  • Ensured submenu command IDs and icons remain correctly associated after menu changes.
  • Fixed cleanup of detached submenus when menus are replaced or destroyed.
  • Corrected Windows menu failure reporting to preserve error results accurately.

AppendMenu with MF_POPUP uses uIDNewItem as the child HMENU, leaving
submenu parent rows without the command ID that runtime mutations look
up via MF_BYCOMMAND. Assign the ID by position after append.

Fixes wailsapp#5943
@coderabbitai

coderabbitai Bot commented Aug 10, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Windows menu builders now restore command IDs for submenu parent items. Detached submenu handles are tracked across hiding, rebuilding, rollback, replacement, and destruction. Windows tests cover these behaviors and preserve Win32 menu-count failure values.

Changes

Windows menu state

Layer / File(s) Summary
Submenu command ID restoration
v3/pkg/application/menuitem_windows.go, v3/pkg/application/menu_windows.go, v3/pkg/application/popupmenu_windows.go
Submenu items regain their command IDs after insertion. Bitmap updates use those IDs.
Detached submenu lifecycle
v3/pkg/application/menu_windows.go, v3/pkg/application/menuitem_windows.go, v3/pkg/application/popupmenu_windows.go
Hidden submenu handles are tracked and released during reinsertion, rebuild rollback, replacement, and destruction.
Windows regression coverage
v3/pkg/application/menu_windows_internal_test.go, v3/pkg/w32/menubar.go, v3/pkg/w32/menu_windows_test.go
Tests cover submenu mutations, hidden submenu restoration, cleanup, command-ID errors, and signed menu-count failures.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

Suggested labels: size:L

Suggested reviewers: taliesin-ai, leaanthony

Poem

A rabbit guards each submenu gate,
Command IDs now set the state.
Hidden handles rest in a tracked row,
Failed rebuilds cleanly let them go.
Windows menus update straight.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ 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%. 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 clearly identifies the Windows submenu mutation bug addressed by the pull request.
Description check ✅ Passed The description covers the bug, root cause, fix, linked issue, test environment, manual validation, and implementation checklist.
Linked Issues check ✅ Passed The changes address issue #5943 by assigning submenu command IDs and preserving submenu handles for all affected Windows menu paths.
Out of Scope Changes check ✅ Passed The changes remain within the Windows menu mutation fix, including supporting submenu cleanup and the related Win32 failure-value regression test.
✨ 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.

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

🤖 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/menu_windows.go`:
- Around line 153-158: The submenu-item restoration paths in menu_windows.go
lines 153-158 and popupmenu_windows.go lines 194-199 must check the boolean
result from assignCommandID. If assignment fails, propagate a build error from
each respective builder instead of continuing with an incorrectly mapped popup
item; preserve the existing successful build behavior.
- Around line 153-158: The submenu item restoration must use its command
identifier consistently. In v3/pkg/application/menu_windows.go lines 153-158 and
v3/pkg/application/popupmenu_windows.go lines 194-199, update SetMenuIcons to
receive menuItemImpl.id rather than the child HMENU/itemID, and propagate any
assignCommandID failure before installing bitmaps.
- Line 129: Update processMenu so that when a hidden menu item skips AppendMenu,
it destroys the newly created submenu referenced by menuItemImpl.submenu instead
of leaving it unattached; retain the existing cleanup behavior for submenus that
are appended to the visible oldHMENU.
🪄 Autofix

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 Plus

Run ID: 52411fdf-8086-40ac-951a-e98e299dcdc1

📥 Commits

Reviewing files that changed from the base of the PR and between 857398f and bcea234.

📒 Files selected for processing (3)
  • v3/pkg/application/menu_windows.go
  • v3/pkg/application/menuitem_windows.go
  • v3/pkg/application/popupmenu_windows.go

Comment thread v3/pkg/application/menu_windows.go Resolved
Comment thread v3/pkg/application/menu_windows.go Resolved
@gilad-ch gilad-ch changed the title fix(v3/windows): assign command IDs to submenu parent menu items fix(v3/windows): SetLabel/SetChecked/SetHidden/SetEnabled are no-ops Aug 10, 2026
Address review feedback on the submenu command ID fix:

- Check the assignCommandID result in both Windows menu builders and fail
  the build with an error, matching how AppendMenu and SetMenuIcons
  failures are already handled, instead of silently continuing with a row
  that cannot be addressed by MF_BYCOMMAND.
- Pass menuItemImpl.id to SetMenuIcons rather than itemID. For submenu
  items itemID holds the child HMENU, and SetMenuIcons resolves the row
  via SetMenuItemBitmaps with MF_BYCOMMAND, so bitmaps on submenu rows
  were installed against an ID that does not exist. Non-submenu items are
  unaffected: there itemID and menuItemImpl.id are the same value.

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 fixes a Windows-specific issue where runtime mutations (SetLabel, SetChecked, SetEnabled/Disabled, SetHidden) on submenu parent rows were silently ignored because those rows lacked a valid Win32 command ID and, in one codepath, didn’t retain the submenu HMENU needed for reinsertion.

Changes:

  • Assign a command ID to MF_POPUP submenu parent rows immediately after AppendMenu so later MF_BYCOMMAND updates can locate them.
  • Persist the submenu HMENU on the Windows menu item implementation so hide/show reinsertion can reattach the correct dropdown.
  • Fix submenu icon updates by targeting rows via the command ID (not the submenu HMENU).

Reviewed changes

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

File Description
v3/pkg/application/popupmenu_windows.go Assign command IDs for submenu parent rows and ensure icon updates target the command ID.
v3/pkg/application/menuitem_windows.go Introduce assignCommandID helper to retroactively set Win32 command IDs by position.
v3/pkg/application/menu_windows.go Persist submenu HMENU, assign command IDs for submenu parent rows, and fix icon targeting.

💡 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/menu_windows.go Resolved
Comment thread v3/pkg/application/menuitem_windows.go Resolved
Comment thread v3/pkg/application/popupmenu_windows.go Resolved
@leaanthony
leaanthony merged commit f5022e8 into wailsapp:master Aug 11, 2026
63 of 64 checks passed
leaanthony pushed a commit that referenced this pull request Aug 11, 2026
…abel/SetChecked/SetHidden/SetEnabled are no-ops
timlinde pushed a commit to Topborn/wails that referenced this pull request Aug 22, 2026
…ailsapp#5944)

* fix(v3/windows): assign command IDs to submenu parent menu items

AppendMenu with MF_POPUP uses uIDNewItem as the child HMENU, leaving
submenu parent rows without the command ID that runtime mutations look
up via MF_BYCOMMAND. Assign the ID by position after append.

Fixes wailsapp#5943

* fix(v3/windows): surface command ID failures and fix submenu bitmaps

Address review feedback on the submenu command ID fix:

- Check the assignCommandID result in both Windows menu builders and fail
  the build with an error, matching how AppendMenu and SetMenuIcons
  failures are already handled, instead of silently continuing with a row
  that cannot be addressed by MF_BYCOMMAND.
- Pass menuItemImpl.id to SetMenuIcons rather than itemID. For submenu
  items itemID holds the child HMENU, and SetMenuIcons resolves the row
  via SetMenuItemBitmaps with MF_BYCOMMAND, so bitmaps on submenu rows
  were installed against an ID that does not exist. Non-submenu items are
  unaffected: there itemID and menuItemImpl.id are the same value.

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* fix(v3/windows): guard against GetMenuItemCount failure in buildMenu

* fix(windows): test submenu mutations and release hidden menus

---------

Co-authored-by: taliesin-ai <bot@taliesin.ai>
Co-authored-by: Lea Anthony <lea.anthony@gmail.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
timlinde pushed a commit to Topborn/wails that referenced this pull request Aug 22, 2026
…s): SetLabel/SetChecked/SetHidden/SetEnabled are no-ops
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/windows] Runtime menu mutations on submenu parent items are silent no-ops

4 participants