diff --git a/src/cascadia/WindowsTerminal/AppHost.cpp b/src/cascadia/WindowsTerminal/AppHost.cpp index bc45ea9605a..492a21d1d27 100644 --- a/src/cascadia/WindowsTerminal/AppHost.cpp +++ b/src/cascadia/WindowsTerminal/AppHost.cpp @@ -530,6 +530,7 @@ bool AppHost::HasWindow() void AppHost::_DispatchCommandline(winrt::Windows::Foundation::IInspectable /*sender*/, Remoting::CommandlineArgs args) { + _window->SummonWindow(); _logic.ExecuteCommandline(args.Commandline(), args.CurrentDirectory()); } diff --git a/src/cascadia/WindowsTerminal/IslandWindow.cpp b/src/cascadia/WindowsTerminal/IslandWindow.cpp index ff3a4967e2c..0850f7e08df 100644 --- a/src/cascadia/WindowsTerminal/IslandWindow.cpp +++ b/src/cascadia/WindowsTerminal/IslandWindow.cpp @@ -844,5 +844,41 @@ void IslandWindow::_ApplyWindowSize() SWP_FRAMECHANGED | SWP_NOACTIVATE)); } +// Method Description: +// - Force activate this window. This method will bring us to the foreground and +// activate us. If the window is minimized, it will restore the window. If the +// window is on another desktop, the OS will switch to that desktop. +// Arguments: +// - +// Return Value: +// - +winrt::fire_and_forget IslandWindow::SummonWindow() +{ + // On the foreground thread: + co_await winrt::resume_foreground(_rootGrid.Dispatcher()); + + // From: https://stackoverflow.com/a/59659421 + // > The trick is to make windows ‘think’ that our process and the target + // > window (hwnd) are related by attaching the threads (using + // > AttachThreadInput API) and using an alternative API: BringWindowToTop. + // If the window is minimized, then restore it. We don't want to do this + // always though, because if you SW_RESTORE a maximized window, it will + // restore-down the window. + if (IsIconic(_window.get())) + { + LOG_IF_WIN32_BOOL_FALSE(ShowWindow(_window.get(), SW_RESTORE)); + } + const DWORD windowThreadProcessId = GetWindowThreadProcessId(GetForegroundWindow(), nullptr); + const DWORD currentThreadId = GetCurrentThreadId(); + + LOG_IF_WIN32_BOOL_FALSE(AttachThreadInput(windowThreadProcessId, currentThreadId, true)); + // Just in case, add the thread detach as a scope_exit, to make _sure_ we do it. + auto detachThread = wil::scope_exit([windowThreadProcessId, currentThreadId]() { + LOG_IF_WIN32_BOOL_FALSE(AttachThreadInput(windowThreadProcessId, currentThreadId, false)); + }); + LOG_IF_WIN32_BOOL_FALSE(BringWindowToTop(_window.get())); + LOG_IF_WIN32_BOOL_FALSE(ShowWindow(_window.get(), SW_SHOW)); +} + DEFINE_EVENT(IslandWindow, DragRegionClicked, _DragRegionClickedHandlers, winrt::delegate<>); DEFINE_EVENT(IslandWindow, WindowCloseButtonClicked, _windowCloseButtonClickedHandler, winrt::delegate<>); diff --git a/src/cascadia/WindowsTerminal/IslandWindow.h b/src/cascadia/WindowsTerminal/IslandWindow.h index fe0cae1ec65..f17b81c252e 100644 --- a/src/cascadia/WindowsTerminal/IslandWindow.h +++ b/src/cascadia/WindowsTerminal/IslandWindow.h @@ -38,6 +38,8 @@ class IslandWindow : void FlashTaskbar(); void SetTaskbarProgress(const size_t state, const size_t progress); + winrt::fire_and_forget SummonWindow(); + #pragma endregion DECLARE_EVENT(DragRegionClicked, _DragRegionClickedHandlers, winrt::delegate<>); diff --git a/src/cascadia/WindowsTerminal/pch.h b/src/cascadia/WindowsTerminal/pch.h index b416ccccc4f..2a4fb9c4a60 100644 --- a/src/cascadia/WindowsTerminal/pch.h +++ b/src/cascadia/WindowsTerminal/pch.h @@ -56,8 +56,10 @@ Module Name: #include // Additional headers for various xaml features. We need: +// * Core so we can resume_foreground // * Controls for grid // * Media for ScaleTransform +#include #include #include