Fiddle about until it works. Pipe the show/hide status back down from the terminal to the pty host.

This commit is contained in:
Michael Niksa
2022-02-22 15:13:45 -08:00
parent f4dc55df29
commit 1a8494f969
26 changed files with 125 additions and 64 deletions

View File

@@ -1123,6 +1123,14 @@ namespace winrt::TerminalApp::implementation
} }
} }
void AppLogic::WindowVisibilityChanged(const bool showOrHide)
{
if (_root)
{
_root->WindowVisibilityChanged(showOrHide);
}
}
// Method Description: // Method Description:
// - Implements the F7 handler (per GH#638) // - Implements the F7 handler (per GH#638)
// - Implements the Alt handler (per GH#6421) // - Implements the Alt handler (per GH#6421)

View File

@@ -114,6 +114,7 @@ namespace winrt::TerminalApp::implementation
bool OnDirectKeyEvent(const uint32_t vkey, const uint8_t scanCode, const bool down); bool OnDirectKeyEvent(const uint32_t vkey, const uint8_t scanCode, const bool down);
void CloseWindow(Microsoft::Terminal::Settings::Model::LaunchPosition position); void CloseWindow(Microsoft::Terminal::Settings::Model::LaunchPosition position);
void WindowVisibilityChanged(const bool showOrHide);
winrt::TerminalApp::TaskbarState TaskbarState(); winrt::TerminalApp::TaskbarState TaskbarState();

View File

@@ -89,6 +89,7 @@ namespace TerminalApp
Single CalcSnappedDimension(Boolean widthOrHeight, Single dimension); Single CalcSnappedDimension(Boolean widthOrHeight, Single dimension);
void TitlebarClicked(); void TitlebarClicked();
void CloseWindow(Microsoft.Terminal.Settings.Model.LaunchPosition position); void CloseWindow(Microsoft.Terminal.Settings.Model.LaunchPosition position);
void WindowVisibilityChanged(Boolean showOrHide);
TaskbarState TaskbarState{ get; }; TaskbarState TaskbarState{ get; };

View File

@@ -2788,6 +2788,29 @@ namespace winrt::TerminalApp::implementation
_DismissTabContextMenus(); _DismissTabContextMenus();
} }
void TerminalPage::WindowVisibilityChanged(const bool showOrHide)
{
for (const auto& tab : _tabs)
{
if (auto terminalTab{ _GetTerminalTabImpl(tab) })
{
// Manually enumerate the panes in each tab; this will let us recycle TerminalSettings
// objects but only have to iterate one time.
terminalTab->GetRootPane()->WalkTree([&](auto&& pane) {
if (const auto profile{ pane->GetProfile() })
{
if (auto control = pane->GetTerminalControl())
{
control.WindowVisibilityChanged(showOrHide);
}
}
});
}
}
}
// Method Description: // Method Description:
// - Called when the user tries to do a search using keybindings. // - Called when the user tries to do a search using keybindings.
// This will tell the current focused terminal control to create // This will tell the current focused terminal control to create

View File

@@ -75,6 +75,7 @@ namespace winrt::TerminalApp::implementation
hstring Title(); hstring Title();
void TitlebarClicked(); void TitlebarClicked();
void WindowVisibilityChanged(const bool showOrHide);
float CalcSnappedDimension(const bool widthOrHeight, const float dimension) const; float CalcSnappedDimension(const bool widthOrHeight, const float dimension) const;

View File

@@ -1745,6 +1745,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
} }
} }
void ControlCore::WindowVisibilityChanged(const bool showOrHide)
{
_terminal->UpdateVisibility(showOrHide);
}
bool ControlCore::_isBackgroundTransparent() bool ControlCore::_isBackgroundTransparent()
{ {
// If we're: // If we're:

View File

@@ -168,6 +168,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void AdjustOpacity(const double opacity, const bool relative); void AdjustOpacity(const double opacity, const bool relative);
void WindowVisibilityChanged(const bool showOrHide);
RUNTIME_SETTING(double, Opacity, _settings->Opacity()); RUNTIME_SETTING(double, Opacity, _settings->Opacity());
RUNTIME_SETTING(bool, UseAcrylic, _settings->UseAcrylic()); RUNTIME_SETTING(bool, UseAcrylic, _settings->UseAcrylic());

View File

@@ -100,6 +100,7 @@ namespace Microsoft.Terminal.Control
String ReadEntireBuffer(); String ReadEntireBuffer();
void AdjustOpacity(Double Opacity, Boolean relative); void AdjustOpacity(Double Opacity, Boolean relative);
void WindowVisibilityChanged(Boolean showOrHide);
event FontSizeChangedEventArgs FontSizeChanged; event FontSizeChangedEventArgs FontSizeChanged;

View File

@@ -2055,6 +2055,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return cells * fontDimension + nonTerminalArea; return cells * fontDimension + nonTerminalArea;
} }
void TermControl::WindowVisibilityChanged(const bool showOrHide)
{
_core.WindowVisibilityChanged(showOrHide);
}
// Method Description: // Method Description:
// - Create XAML Thickness object based on padding props provided. // - Create XAML Thickness object based on padding props provided.
// Used for controlling the TermControl XAML Grid container's Padding prop. // Used for controlling the TermControl XAML Grid container's Padding prop.

View File

@@ -42,6 +42,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
Windows::Foundation::Size MinimumSize(); Windows::Foundation::Size MinimumSize();
float SnapDimensionToGrid(const bool widthOrHeight, const float dimension); float SnapDimensionToGrid(const bool widthOrHeight, const float dimension);
void WindowVisibilityChanged(const bool showOrHide);
#pragma region ICoreState #pragma region ICoreState
const uint64_t TaskbarState() const noexcept; const uint64_t TaskbarState() const noexcept;
const uint64_t TaskbarProgress() const noexcept; const uint64_t TaskbarProgress() const noexcept;

View File

@@ -56,6 +56,8 @@ namespace Microsoft.Terminal.Control
Windows.Foundation.Size MinimumSize { get; }; Windows.Foundation.Size MinimumSize { get; };
Single SnapDimensionToGrid(Boolean widthOrHeight, Single dimension); Single SnapDimensionToGrid(Boolean widthOrHeight, Single dimension);
void WindowVisibilityChanged(Boolean showOrHide);
void ScrollViewport(Int32 viewTop); void ScrollViewport(Int32 viewTop);
void CreateSearchBoxControl(); void CreateSearchBoxControl();

View File

@@ -221,6 +221,11 @@ void Terminal::UpdateAppearance(const ICoreAppearance& appearance)
_defaultCursorShape = cursorShape; _defaultCursorShape = cursorShape;
} }
void Terminal::UpdateVisibility(const bool visible)
{
ReturnResponse(visible ? L"\x1b[1t" : L"\x1b[2t");
}
// Method Description: // Method Description:
// - Resize the terminal as the result of some user interaction. // - Resize the terminal as the result of some user interaction.
// Arguments: // Arguments:

View File

@@ -74,6 +74,7 @@ public:
void UpdateSettings(winrt::Microsoft::Terminal::Core::ICoreSettings settings); void UpdateSettings(winrt::Microsoft::Terminal::Core::ICoreSettings settings);
void UpdateAppearance(const winrt::Microsoft::Terminal::Core::ICoreAppearance& appearance); void UpdateAppearance(const winrt::Microsoft::Terminal::Core::ICoreAppearance& appearance);
void UpdateVisibility(const bool visible);
void SetFontInfo(const FontInfo& fontInfo); void SetFontInfo(const FontInfo& fontInfo);
// Write comes from the PTY and goes to our parser to be stored in the output buffer // Write comes from the PTY and goes to our parser to be stored in the output buffer

View File

@@ -337,6 +337,8 @@ void AppHost::Initialize()
// application layer. // application layer.
_window->DragRegionClicked([this]() { _logic.TitlebarClicked(); }); _window->DragRegionClicked([this]() { _logic.TitlebarClicked(); });
_window->WindowVisibilityChanged([this](bool showOrHide) { _logic.WindowVisibilityChanged(showOrHide); });
_logic.RequestedThemeChanged({ this, &AppHost::_UpdateTheme }); _logic.RequestedThemeChanged({ this, &AppHost::_UpdateTheme });
_logic.FullscreenChanged({ this, &AppHost::_FullscreenChanged }); _logic.FullscreenChanged({ this, &AppHost::_FullscreenChanged });
_logic.FocusModeChanged({ this, &AppHost::_FocusModeChanged }); _logic.FocusModeChanged({ this, &AppHost::_FocusModeChanged });

View File

@@ -471,13 +471,18 @@ long IslandWindow::_calculateTotalSize(const bool isWidth, const long clientSize
{ {
if (wparam == SIZE_RESTORED || wparam == SIZE_MAXIMIZED) if (wparam == SIZE_RESTORED || wparam == SIZE_MAXIMIZED)
{ {
_WindowVisibilityChangedHandlers(true);
_MaximizeChangedHandlers(wparam == SIZE_MAXIMIZED); _MaximizeChangedHandlers(wparam == SIZE_MAXIMIZED);
} }
if (wparam == SIZE_MINIMIZED && _isQuakeWindow) if (wparam == SIZE_MINIMIZED)
{ {
ShowWindow(GetHandle(), SW_HIDE); _WindowVisibilityChangedHandlers(false);
return 0; if (_isQuakeWindow)
{
ShowWindow(GetHandle(), SW_HIDE);
return 0;
}
} }
break; break;
} }
@@ -538,13 +543,14 @@ long IslandWindow::_calculateTotalSize(const bool isWidth, const long clientSize
return 0; return 0;
case WM_WINDOWPOSCHANGING: case WM_WINDOWPOSCHANGING:
{ {
// Pull out the parameters from the call.
auto lpwpos = (LPWINDOWPOS)lparam;
// GH#10274 - if the quake window gets moved to another monitor via aero // GH#10274 - if the quake window gets moved to another monitor via aero
// snap (win+shift+arrows), then re-adjust the size for the new monitor. // snap (win+shift+arrows), then re-adjust the size for the new monitor.
if (IsQuakeWindow()) if (IsQuakeWindow())
{ {
// Retrieve the suggested dimensions and make a rect and size. // Retrieve the suggested dimensions and make a rect and size.
LPWINDOWPOS lpwpos = (LPWINDOWPOS)lparam;
// We only need to apply restrictions if the position is changing. // We only need to apply restrictions if the position is changing.
// The SWP_ flags are confusing to read. This is // The SWP_ flags are confusing to read. This is
// "if we're not moving the window, do nothing." // "if we're not moving the window, do nothing."

View File

@@ -77,6 +77,7 @@ public:
WINRT_CALLBACK(MaximizeChanged, winrt::delegate<void(bool)>); WINRT_CALLBACK(MaximizeChanged, winrt::delegate<void(bool)>);
WINRT_CALLBACK(WindowMoved, winrt::delegate<void()>); WINRT_CALLBACK(WindowMoved, winrt::delegate<void()>);
WINRT_CALLBACK(WindowVisibilityChanged, winrt::delegate<void(bool)>);
protected: protected:
void ForceResize() void ForceResize()

View File

@@ -215,7 +215,11 @@ bool VtIo::IsUsingVt() const
g.pRender->AddRenderEngine(_pVtRenderEngine.get()); g.pRender->AddRenderEngine(_pVtRenderEngine.get());
g.getConsoleInformation().GetActiveOutputBuffer().SetTerminalConnection(_pVtRenderEngine.get()); g.getConsoleInformation().GetActiveOutputBuffer().SetTerminalConnection(_pVtRenderEngine.get());
g.getConsoleInformation().GetActiveInputBuffer()->SetTerminalConnection(_pVtRenderEngine.get()); g.getConsoleInformation().GetActiveInputBuffer()->SetTerminalConnection(_pVtRenderEngine.get());
ServiceLocator::SetPseudoWindowCallback([&](std::wstring_view text) { LOG_IF_FAILED(_pVtRenderEngine->WriteTerminalW(text)); }); ServiceLocator::SetPseudoWindowCallback([&](bool showOrHide) -> void
{
// Set the remote window visibility to the request
LOG_IF_FAILED(_pVtRenderEngine->SetWindowVisibility(showOrHide));
});
} }
CATCH_RETURN(); CATCH_RETURN();
} }

View File

@@ -511,8 +511,9 @@ void ConhostInternalGetSet::SetCursorStyle(const CursorType style)
// - <none> // - <none>
void ConhostInternalGetSet::ShowWindow(bool showOrHide) void ConhostInternalGetSet::ShowWindow(bool showOrHide)
{ {
auto hwnd = ServiceLocator::LocateConsoleWindow()->GetWindowHandle(); const auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
LOG_IF_WIN32_BOOL_FALSE(PostMessageW(hwnd, WM_SHOWWINDOW, showOrHide, 0)); const auto hwnd = gci.IsInVtIoMode() ? ServiceLocator::LocatePseudoWindow() : ServiceLocator::LocateConsoleWindow()->GetWindowHandle();
::ShowWindow(hwnd, showOrHide ? SW_NORMAL : SW_MINIMIZE);
} }
// Routine Description: // Routine Description:

View File

@@ -391,7 +391,7 @@ using namespace Microsoft::Console::Interactivity;
return status; return status;
} }
void InteractivityFactory::SetPseudoWindowCallback(std::function<void(std::wstring_view)> func) void InteractivityFactory::SetPseudoWindowCallback(std::function<void(bool)> func)
{ {
_pseudoWindowMessageCallback = func; _pseudoWindowMessageCallback = func;
} }
@@ -427,75 +427,41 @@ void InteractivityFactory::SetPseudoWindowCallback(std::function<void(std::wstri
return TRUE; return TRUE;
// As long as user32 didn't eat the `ShowWindow` call because the window state requested // 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. // matches the existing WS_VISIBLE state of the HWND... we should hear from it in WM_WINDOWPOSCHANGING.
case WM_WINDOWPOSCHANGING: case WM_SIZE:
{ {
// We're trying to discern what people are asking of us when they called if (wParam == SIZE_RESTORED)
// `ShowWindow` on our HWND. Since we're a ConPTY, our window isn't the
// place where the content is presented. The actual attached terminal is
// that place. Our goal, therefore, is to try to communicate to the
// final presentation.
// I've observed the following from `ShowWindow`:
// (reference https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showwindow)
// SW_HIDE (0)
// SW_NORMAL(1)
// SW_SHOWMINIMIZED (2)
// SW_SHOWMAXIMIZED (3)
// SW_SHOWNOACTIVATE (4)
// SW_SHOW (5)
// SW_MINIMIZE (6)
// SW_SHOWMINNOACTIVE (7)
// SW_SHOWNA (8)
// SW_RESTORE (9)
// SW_SHOWDEFAULT (10)
// SW_FORCEMINIMIZE (11)
// Dig information out of the message so we know what someone is asking for
/*auto pWindowPos = (PWINDOWPOS)lParam;*/
const auto minimizing = IsIconic(hWnd);
// Other potentially useful flags.
/*const auto maximizing = IsZoomed(hWnd);
const auto showing = WI_IsFlagSet(pWindowPos->flags, SWP_SHOWWINDOW);
const auto hiding = WI_IsFlagSet(pWindowPos->flags, SWP_HIDEWINDOW);
const auto activating = WI_IsFlagClear(pWindowPos->flags, SWP_NOACTIVATE);*/
if (minimizing)
{ {
_WritePseudoWindowCallback(L"\x1b[2t"); _WritePseudoWindowCallback(true);
} }
// On the way out, stop activation and showing so we remain hidden. if (wParam == SIZE_MINIMIZED)
/*WI_ClearFlag(pWindowPos->flags, SWP_SHOWWINDOW); {
WI_SetFlag(pWindowPos->flags, SWP_NOACTIVATE);*/ _WritePseudoWindowCallback(false);
return 0; }
break;
} }
// 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.
// WM_SYSCOMMAND will not come through. Don't try. // WM_SYSCOMMAND will not come through. Don't try.
// WM_SHOWWINDOW comes through on some of the messages. // WM_SHOWWINDOW comes through on some of the messages.
case WM_SHOWWINDOW: case WM_SHOWWINDOW:
{ {
if (lParam == 0) // Message came directly from someone calling ShowWindow on us. if (0 == lParam) // Someone explictly called ShowWindow on us.
{ {
if (wParam) // If TRUE, we're being shown _WritePseudoWindowCallback((bool)wParam);
{
_WritePseudoWindowCallback(L"\x1b[1t");
}
else // If FALSE, we're being hidden
{
_WritePseudoWindowCallback(L"\x1b[2t");
}
return 0;
} }
break;
} }
} }
// If we get this far, call the default window proc // If we get this far, call the default window proc
return DefWindowProcW(hWnd, Message, wParam, lParam); return DefWindowProcW(hWnd, Message, wParam, lParam);
} }
void InteractivityFactory::_WritePseudoWindowCallback(std::wstring_view text) void InteractivityFactory::_WritePseudoWindowCallback(bool showOrHide)
{ {
if (_pseudoWindowMessageCallback) if (_pseudoWindowMessageCallback)
{ {
_pseudoWindowMessageCallback(text); _pseudoWindowMessageCallback(showOrHide);
} }
} }

View File

@@ -28,7 +28,7 @@ namespace Microsoft::Console::Interactivity
[[nodiscard]] NTSTATUS CreateInputServices(_Inout_ std::unique_ptr<IInputServices>& services); [[nodiscard]] NTSTATUS CreateInputServices(_Inout_ std::unique_ptr<IInputServices>& services);
[[nodiscard]] NTSTATUS CreatePseudoWindow(HWND& hwnd); [[nodiscard]] NTSTATUS CreatePseudoWindow(HWND& hwnd);
void SetPseudoWindowCallback(std::function<void(std::wstring_view)> func); void SetPseudoWindowCallback(std::function<void(bool)> func);
// Wndproc // Wndproc
[[nodiscard]] static LRESULT CALLBACK s_PseudoWindowProc(_In_ HWND hwnd, [[nodiscard]] static LRESULT CALLBACK s_PseudoWindowProc(_In_ HWND hwnd,
@@ -41,7 +41,7 @@ namespace Microsoft::Console::Interactivity
_In_ LPARAM lParam); _In_ LPARAM lParam);
private: private:
void _WritePseudoWindowCallback(std::wstring_view text); void _WritePseudoWindowCallback(bool showOrHide);
std::function<void(std::wstring_view)> _pseudoWindowMessageCallback; std::function<void(bool)> _pseudoWindowMessageCallback;
}; };
} }

View File

@@ -296,7 +296,7 @@ Globals& ServiceLocator::LocateGlobals()
return s_globals; return s_globals;
} }
void ServiceLocator::SetPseudoWindowCallback(std::function<void(std::wstring_view)> func) void ServiceLocator::SetPseudoWindowCallback(std::function<void(bool)> func)
{ {
// Force the whole window to be put together first. // Force the whole window to be put together first.
// We don't really need the handle, we just want to leverage the setup steps. // We don't really need the handle, we just want to leverage the setup steps.

View File

@@ -42,7 +42,7 @@ namespace Microsoft::Console::Interactivity
[[nodiscard]] virtual NTSTATUS CreateSystemConfigurationProvider(_Inout_ std::unique_ptr<ISystemConfigurationProvider>& provider) = 0; [[nodiscard]] virtual NTSTATUS CreateSystemConfigurationProvider(_Inout_ std::unique_ptr<ISystemConfigurationProvider>& provider) = 0;
[[nodiscard]] virtual NTSTATUS CreateInputServices(_Inout_ std::unique_ptr<IInputServices>& services) = 0; [[nodiscard]] virtual NTSTATUS CreateInputServices(_Inout_ std::unique_ptr<IInputServices>& services) = 0;
virtual void SetPseudoWindowCallback(std::function<void(std::wstring_view)> func) = 0; virtual void SetPseudoWindowCallback(std::function<void(bool)> func) = 0;
[[nodiscard]] virtual NTSTATUS CreatePseudoWindow(HWND& hwnd) = 0; [[nodiscard]] virtual NTSTATUS CreatePseudoWindow(HWND& hwnd) = 0;
}; };

View File

@@ -89,7 +89,7 @@ namespace Microsoft::Console::Interactivity
static Globals& LocateGlobals(); static Globals& LocateGlobals();
static void SetPseudoWindowCallback(std::function<void(std::wstring_view)> func); static void SetPseudoWindowCallback(std::function<void(bool)> func);
static HWND LocatePseudoWindow(); static HWND LocatePseudoWindow();
protected: protected:

View File

@@ -530,6 +530,25 @@ CATCH_RETURN();
return _Flush(); return _Flush();
} }
[[nodiscard]] HRESULT XtermEngine::SetWindowVisibility(const bool showOrHide) noexcept
{
if (showOrHide)
{
RETURN_IF_FAILED(_Write("\x1b[1t"));
}
else
{
RETURN_IF_FAILED(_Write("\x1b[2t"));
}
return _Flush();
}
[[nodiscard]] HRESULT XtermEngine::RequestWindowVisibility() noexcept
{
RETURN_IF_FAILED(_Write("\x1b[11t"));
return _Flush();
}
// Method Description: // Method Description:
// - Updates the window's title string. Emits the VT sequence to SetWindowTitle. // - Updates the window's title string. Emits the VT sequence to SetWindowTitle.
// Arguments: // Arguments:

View File

@@ -53,6 +53,9 @@ namespace Microsoft::Console::Render
[[nodiscard]] HRESULT WriteTerminalW(const std::wstring_view str) noexcept override; [[nodiscard]] HRESULT WriteTerminalW(const std::wstring_view str) noexcept override;
[[nodiscard]] HRESULT SetWindowVisibility(const bool showOrHide) noexcept override;
[[nodiscard]] HRESULT RequestWindowVisibility() noexcept override;
protected: protected:
// I'm using a non-class enum here, so that the values // I'm using a non-class enum here, so that the values
// are trivially convertible and comparable to bool. // are trivially convertible and comparable to bool.

View File

@@ -82,6 +82,8 @@ namespace Microsoft::Console::Render
void SetResizeQuirk(const bool resizeQuirk); void SetResizeQuirk(const bool resizeQuirk);
[[nodiscard]] virtual HRESULT ManuallyClearScrollback() noexcept; [[nodiscard]] virtual HRESULT ManuallyClearScrollback() noexcept;
[[nodiscard]] HRESULT RequestWin32Input() noexcept; [[nodiscard]] HRESULT RequestWin32Input() noexcept;
[[nodiscard]] virtual HRESULT SetWindowVisibility(const bool showOrHide) noexcept = 0;
[[nodiscard]] virtual HRESULT RequestWindowVisibility() noexcept = 0;
protected: protected:
wil::unique_hfile _hFile; wil::unique_hfile _hFile;