From 0c901edd813f2bb61a52c3aca5384eb4d748b868 Mon Sep 17 00:00:00 2001 From: Leon Liang Date: Fri, 20 Aug 2021 16:24:13 -0700 Subject: [PATCH] Create a window process for the tray icon (#10980) Currently, the monarch window will show itself when opening the tray icon context menu. This is because a window must be set as the foreground window when the context menu opens, otherwise the menu won't be able to be dismissed when clicking outside of the context menu. This PR makes the tray icon create a non visible/interactable window for the sole purpose of being set as the foreground window when the tray icon's context menu is opened. Then none of the terminal windows should be set as the foreground window when opening the context menu. Closes #10936 --- src/cascadia/WindowsTerminal/TrayIcon.cpp | 37 ++++++++++++++++++++++- src/cascadia/WindowsTerminal/TrayIcon.h | 2 ++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/cascadia/WindowsTerminal/TrayIcon.cpp b/src/cascadia/WindowsTerminal/TrayIcon.cpp index 83bc04343..e3df4fb0b 100644 --- a/src/cascadia/WindowsTerminal/TrayIcon.cpp +++ b/src/cascadia/WindowsTerminal/TrayIcon.cpp @@ -23,6 +23,32 @@ TrayIcon::~TrayIcon() RemoveIconFromTray(); } +void TrayIcon::_CreateWindow() +{ + WNDCLASSW wc{}; + wc.hCursor = LoadCursor(nullptr, IDC_ARROW); + wc.hInstance = wil::GetModuleInstanceHandle(); + wc.lpszClassName = L"TRAY_ICON_HOSTING_WINDOW_CLASS"; + wc.style = CS_HREDRAW | CS_VREDRAW; + wc.lpfnWndProc = DefWindowProcW; + wc.hIcon = static_cast(GetActiveAppIconHandle(true)); + RegisterClass(&wc); + + _trayIconHwnd = wil::unique_hwnd(CreateWindowW(wc.lpszClassName, + wc.lpszClassName, + WS_DISABLED, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + HWND_MESSAGE, + nullptr, + wc.hInstance, + nullptr)); + + WINRT_VERIFY(_trayIconHwnd); +} + // Method Description: // - Creates and adds an icon to the notification tray. // If an icon already exists, update the HWND associated @@ -33,6 +59,15 @@ TrayIcon::~TrayIcon() // - void TrayIcon::CreateTrayIcon() { + if (!_trayIconHwnd) + { + // Creating a disabled, non visible window just so we can set it + // as the foreground window when showing the context menu. + // This is done so that the context menu can be dismissed + // when clicking outside of it. + _CreateWindow(); + } + NOTIFYICONDATA nid{}; nid.cbSize = sizeof(NOTIFYICONDATA); @@ -81,7 +116,7 @@ void TrayIcon::ShowTrayContextMenu(const til::point coord, { // We'll need to set our window to the foreground before calling // TrackPopupMenuEx or else the menu won't dismiss when clicking away. - SetForegroundWindow(_owningHwnd); + SetForegroundWindow(_trayIconHwnd.get()); // User can select menu items with the left and right buttons. UINT uFlags = TPM_RIGHTBUTTON; diff --git a/src/cascadia/WindowsTerminal/TrayIcon.h b/src/cascadia/WindowsTerminal/TrayIcon.h index aa58d17f1..6095e56e3 100644 --- a/src/cascadia/WindowsTerminal/TrayIcon.h +++ b/src/cascadia/WindowsTerminal/TrayIcon.h @@ -30,8 +30,10 @@ public: WINRT_CALLBACK(SummonWindowRequested, winrt::delegate); private: + void _CreateWindow(); HMENU _CreateTrayContextMenu(winrt::Windows::Foundation::Collections::IMapView peasants); + wil::unique_hwnd _trayIconHwnd; HWND _owningHwnd; NOTIFYICONDATA _trayIconData; };