From d682943afb1f14302f395bc6166b3add3810be76 Mon Sep 17 00:00:00 2001 From: Forst Date: Sat, 25 Apr 2026 10:14:28 +0800 Subject: [PATCH] fix: re-sync native menu item state after menu widget creation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When right-clicking the Recycle Bin while it contains items, Windows asynchronously queries the bin state after WM_INITMENUPOPUP and updates the "Empty Recycle Bin" item's disabled flag via SetMenuItemInfoW. This update arrives between construct_with_hmenu (which reads stale state) and the renderer thread setup (which enables the sync hooks), so it was silently dropped — requiring a second right-click to show the correct state. Re-read native HMENU item states after menu_render::create to catch any async updates that arrived during this gap. --- src/shell/contextmenu/hooks.cc | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/shell/contextmenu/hooks.cc b/src/shell/contextmenu/hooks.cc index 7306d55..b06df9d 100644 --- a/src/shell/contextmenu/hooks.cc +++ b/src/shell/contextmenu/hooks.cc @@ -398,6 +398,37 @@ mb_shell::track_popup_menu(mb_shell::menu menu, int x, int y, menu_render.rt->last_time = menu_render.rt->clock.now(); perf.end("menu_render::create"); + // Re-sync native menu item states to catch async updates + // that arrived between construct_with_hmenu and now (e.g., + // recycle bin "Empty Recycle Bin" enabled state). + if (auto root_menu = current_root_menu_widget()) { + HMENU hMenu = (HMENU)menu.native_handle; + int count = GetMenuItemCount(hMenu); + for (int i = 0; i < count; i++) { + MENUITEMINFOW info{sizeof(MENUITEMINFOW)}; + info.fMask = MIIM_STATE; + if (!GetMenuItemInfoW(hMenu, i, TRUE, &info)) + continue; + auto identity = + query_native_menu_item_identity(hMenu, i, TRUE); + if (!identity) + continue; + auto target = find_menu_item_widget_by_identity( + root_menu, *identity); + if (!target) + continue; + bool disabled = + (info.fState & (MFS_DISABLED | MFS_GRAYED)) != 0; + if (target->item.disabled != disabled) { + spdlog::info("Re-synced native menu item state: " + "item={}, disabled={} -> {}", + identity->name.value_or("?"), + target->item.disabled, disabled); + target->item.disabled = disabled; + } + } + } + if (shift_pressed && menu_render.rt->nvg) { spdlog::info("Resetting font atlas due to shift key pressed"); nvgFonsResetAtlas(menu_render.rt->nvg);