Skip to content

Commit 70e2c18

Browse files
committed
Fix Windows context menu not closing when clicking outside
1 parent d7ec4be commit 70e2c18

1 file changed

Lines changed: 28 additions & 15 deletions

File tree

packages/tray_manager/windows/tray_manager_plugin.cpp

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ class TrayManagerPlugin : public flutter::Plugin {
5252
HMENU hMenu = CreatePopupMenu();
5353
bool tray_icon_setted = false;
5454
UINT windows_taskbar_created_message_id = 0;
55+
56+
// Track when menu closes to prevent immediate reopen on tray icon click
57+
ULONGLONG menu_close_tick = 0;
5558

5659
// The ID of the WindowProc delegate registration.
5760
int window_proc_id = -1;
@@ -198,6 +201,12 @@ std::optional<LRESULT> TrayManagerPlugin::HandleWindowProc(HWND hWnd,
198201
} else if (message == WM_MYMESSAGE) {
199202
switch (lParam) {
200203
case WM_LBUTTONUP:
204+
// Suppress click if menu just closed (within 200ms) to prevent reopening
205+
// when user clicks tray icon to close the menu
206+
if (menu_close_tick > 0 && (GetTickCount64() - menu_close_tick) < 200) {
207+
menu_close_tick = 0; // Reset so next click works
208+
break;
209+
}
201210
channel->InvokeMethod("onTrayIconMouseDown",
202211
std::make_unique<flutter::EncodableValue>());
203212
break;
@@ -335,32 +344,36 @@ void TrayManagerPlugin::SetContextMenu(
335344
void TrayManagerPlugin::PopUpContextMenu(
336345
const flutter::MethodCall<flutter::EncodableValue>& method_call,
337346
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result) {
338-
const flutter::EncodableMap& args =
339-
std::get<flutter::EncodableMap>(*method_call.arguments());
340-
341-
bool bringAppToFront =
342-
std::get<bool>(args.at(flutter::EncodableValue("bringAppToFront")));
343-
347+
// Note: bringAppToFront parameter is ignored. SetForegroundWindow is ALWAYS
348+
// required before TrackPopupMenu for notification icon menus per Windows docs:
349+
// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-trackpopupmenu
350+
// "To display a context menu for a notification icon, the current window must
351+
// be the foreground window before the application calls TrackPopupMenu"
352+
(void)method_call.arguments(); // Suppress unused warning
353+
344354
HWND hWnd = GetMainWindow();
345355

346356
double x, y;
347357

348-
// RECT rect;
349-
// Shell_NotifyIconGetRect(&niif, &rect);
350-
351-
// x = rect.left + ((rect.right - rect.left) / 2);
352-
// y = rect.top + ((rect.bottom - rect.top) / 2);
353-
354358
POINT cursorPos;
355359
GetCursorPos(&cursorPos);
356360
x = cursorPos.x;
357361
y = cursorPos.y;
358362

359-
if (bringAppToFront) {
360-
SetForegroundWindow(hWnd);
361-
}
363+
// SetForegroundWindow is REQUIRED before TrackPopupMenu for notification icons.
364+
SetForegroundWindow(hWnd);
365+
362366
TrackPopupMenu(hMenu, TPM_BOTTOMALIGN | TPM_LEFTALIGN, static_cast<int>(x),
363367
static_cast<int>(y), 0, hWnd, NULL);
368+
369+
// Record when menu closed to suppress immediate reopen on tray icon click
370+
menu_close_tick = GetTickCount64();
371+
372+
// IMPORTANT: Post a benign message to the window to work around a Windows bug.
373+
// Without this, the menu won't close when clicking outside of it.
374+
// This is documented in the official TrackPopupMenu API documentation.
375+
// See: https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-trackpopupmenu
376+
PostMessage(hWnd, WM_NULL, 0, 0);
364377
result->Success(flutter::EncodableValue(true));
365378
}
366379

0 commit comments

Comments
 (0)