@@ -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(
335344void 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