Skip to content

Commit

Permalink
Restore the ability for alt+tab to restore the Terminal after minimiz…
Browse files Browse the repository at this point in the history
…ing with taskbar (microsoft#13624)

Curiously, at least on Windows 10 (and rarely on Windows 11), if you minimize the Terminal by clicking on the taskbar, then alt-tab to try and restore the window, the Taskbar will decide to call `SwitchToWindow` on the invisible, owned ConPTY window instead of the main window. When that happens, ConPTY'll get a `WM_SIZE(SIZE_RESTORED, lParam=0)`. The main window will NOT get a `SwitchToWindow` called. If ConPTY doesn't actually inform the hosting process about this, then the main HWND might stay hidden.

* Refer to microsoft#13158 where we disabled this.
* Closes microsoft#13589
* Closes microsoft#13248
* Tested manually on a Windows 10 VM.
* Confirmed that opening tabs while maximized/snapped doesn't restore down.
* `[Native]::ShowWindow([Native]::GetConsoleWindow(), 6)` still works

(cherry picked from commit d1fc112)
Service-Card-Id: 84673887
Service-Version: 1.15
(cherry picked from commit b670800)
Service-Card-Id: 84673886
Service-Version: 1.14
  • Loading branch information
zadjii-msft authored and DHowett committed Aug 10, 2022
1 parent 1642360 commit ac9d697
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 26 deletions.
16 changes: 13 additions & 3 deletions src/cascadia/WindowsTerminal/IslandWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -834,10 +834,20 @@ void IslandWindow::SetAlwaysOnTop(const bool alwaysOnTop)
// - <none>
void IslandWindow::ShowWindowChanged(const bool showOrHide)
{
const auto hwnd = GetHandle();
if (hwnd)
if (const auto hwnd = GetHandle())
{
PostMessage(hwnd, WM_SYSCOMMAND, showOrHide ? SC_RESTORE : SC_MINIMIZE, 0);
// IMPORTANT!
//
// ONLY "restore" if already minimized. If the window is maximized or
// snapped, a restore will restore-down the window instead.
if (showOrHide == true && ::IsIconic(hwnd))
{
::PostMessage(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
}
else if (showOrHide == false)
{
::PostMessage(hwnd, WM_SYSCOMMAND, SC_MINIMIZE, 0);
}
}
}

Expand Down
49 changes: 26 additions & 23 deletions src/interactivity/base/InteractivityFactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,15 @@ void InteractivityFactory::SetPseudoWindowCallback(std::function<void(bool)> fun
// It can be fun to toggle WM_QUERYOPEN but DefWindowProc returns TRUE.
case WM_SIZE:
{
// Curiously, at least on Windows 10 (and rarely on Windows 11), if you
// minimize the Terminal by clicking on the taskbar, then alt-tab to try
// and restore the window, the Taskbar will decide to call
// SwitchToWindow on us, the invisible, owned window of the main window.
// When that happens, we'll get a WM_SIZE(SIZE_RESTORED, lParam=0). The
// main window will NOT get a SwitchToWindow called. If we don't
// actually inform the hosting process about this, then the main HWND
// might stay hidden. Refer to GH#13589

if (wParam == SIZE_RESTORED)
{
_WritePseudoWindowCallback(true);
Expand All @@ -447,23 +456,23 @@ void InteractivityFactory::SetPseudoWindowCallback(std::function<void(bool)> fun
}
break;
}
// case WM_WINDOWPOSCHANGING:
// As long as user32 didn't eat the `ShowWindow` call because the window state requested
// matches the existing WS_VISIBLE state of the HWND... we should hear from it in WM_WINDOWPOSCHANGING.
// WM_WINDOWPOSCHANGING can tell us a bunch through the flags fields.
// We can also check IsIconic/IsZoomed on the HWND during the message
// and we could suppress the change to prevent things from happening.
// case WM_WINDOWPOSCHANGING:
// As long as user32 didn't eat the `ShowWindow` call because the window state requested
// matches the existing WS_VISIBLE state of the HWND... we should hear from it in WM_WINDOWPOSCHANGING.
// WM_WINDOWPOSCHANGING can tell us a bunch through the flags fields.
// We can also check IsIconic/IsZoomed on the HWND during the message
// and we could suppress the change to prevent things from happening.
// case WM_SYSCOMMAND:
// WM_SYSCOMMAND will not come through. Don't try.
// WM_SYSCOMMAND will not come through. Don't try.
// WM_SHOWWINDOW does come through on some of the messages.
case WM_SHOWWINDOW:
// WM_SHOWWINDOW comes through on some of the messages.
{
if (0 == lParam) // Someone explicitly called ShowWindow on us.
{
if (0 == lParam) // Someone explicitly called ShowWindow on us.
{
_WritePseudoWindowCallback((bool)wParam);
}
_WritePseudoWindowCallback((bool)wParam);
}
}
}
// If we get this far, call the default window proc
return DefWindowProcW(hWnd, Message, wParam, lParam);
}
Expand All @@ -478,18 +487,12 @@ void InteractivityFactory::SetPseudoWindowCallback(std::function<void(bool)> fun
// - <none>
void InteractivityFactory::_WritePseudoWindowCallback(bool showOrHide)
{
// BODGY
//
// GH#13158 - At least temporarily, only allow the PTY to HIDE the terminal
// window. There seem to be many issues with this so far, and the quickest
// route to mitigate them seems to be limiting the interaction here to
// allowing ConPTY to minimize the terminal only. This will still allow
// applications to hide the Terminal via GetConsoleWindow(), but should
// broadly prevent any other impact of this feature.
// IMPORTANT!
//
// Should we need to restore this functionality in the future, we should
// only do so with great caution.
if (_pseudoWindowMessageCallback && showOrHide == false)
// A hosting terminal window should only "restore" itself in response to
// this message, if it's already minimized. If the window is maximized a
// restore will restore-down the window instead.
if (_pseudoWindowMessageCallback)
{
_pseudoWindowMessageCallback(showOrHide);
}
Expand Down

0 comments on commit ac9d697

Please sign in to comment.