Skip to content

Commit

Permalink
Propagate show/hide window calls against the ConPTY pseudo window to …
Browse files Browse the repository at this point in the history
…the Terminal (#12515)

Propagate show/hide window calls against the ConPTY pseudo window to the Terminal

## PR Checklist
* [x] Closes #12570 
* [x] I work here
* [x] Manual Tests passed
* [x] Spec Link: →[Doc Link](https://github.com/microsoft/terminal/blob/dev/miniksa/msgs/doc/specs/%2312570%20-%20Show%20Hide%20operations%20on%20GetConsoleWindow%20via%20PTY.md)←

## Detailed Description of the Pull Request / Additional comments
- See the spec. It's pretty much everything I went through deciding on this.

## Validation Steps Performed
- [x] Manual validation against scratch application calling all of the `::ShowWindow` commands against the pseudo console "fake window" and observing the real terminal window state
  • Loading branch information
miniksa authored Apr 27, 2022
1 parent d891e05 commit 6b936d9
Show file tree
Hide file tree
Showing 52 changed files with 940 additions and 8 deletions.
1 change: 1 addition & 0 deletions .github/actions/spelling/allow/apis.txt
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ serializer
SETVERSION
SHELLEXECUTEINFOW
shobjidl
SHOWHIDE
SHOWMINIMIZED
SHOWTIP
SINGLEUSE
Expand Down
11 changes: 11 additions & 0 deletions .github/actions/spelling/expect/expect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,7 @@ DEFFACE
defing
DEFPUSHBUTTON
defterm
deiconify
DELAYLOAD
deletable
DELETEONRELEASE
Expand Down Expand Up @@ -670,6 +671,7 @@ dwl
DWLP
dwm
dwmapi
DWMWA
dword
dwrite
dwriteglyphrundescriptionclustermap
Expand Down Expand Up @@ -1062,6 +1064,7 @@ ico
IComponent
ICONERROR
Iconified
Iconify
ICONINFORMATION
IConsole
ICONSTOP
Expand Down Expand Up @@ -1200,6 +1203,7 @@ IWin
IWindow
IXaml
IXMP
IXP
ixx
jconcpp
JOBOBJECT
Expand Down Expand Up @@ -1936,6 +1940,7 @@ qos
QRSTU
qsort
queryable
QUERYOPEN
QUESTIONMARK
quickedit
QUZ
Expand Down Expand Up @@ -2191,8 +2196,10 @@ shlobj
shlwapi
SHORTPATH
SHOWCURSOR
SHOWDEFAULT
SHOWMAXIMIZED
SHOWMINNOACTIVE
SHOWNA
SHOWNOACTIVATE
SHOWNORMAL
SHOWWINDOW
Expand Down Expand Up @@ -2424,10 +2431,12 @@ tofrom
tokenhelpers
tokenized
tokenizing
toolbar
toolbars
TOOLINFO
Toolset
tooltip
TOOLWINDOW
TOPDOWNDIB
TOPLEFT
toplevel
Expand Down Expand Up @@ -2738,6 +2747,7 @@ windowsdeveloper
windowsinternalstring
WINDOWSIZE
windowsx
windowsterminal
WINDOWTEXT
windowtheme
WINDOWTITLE
Expand Down Expand Up @@ -2880,6 +2890,7 @@ xutr
xvalue
XVIRTUALSCREEN
XWalk
XTWINOPS
Xzn
yact
YAML
Expand Down
370 changes: 370 additions & 0 deletions doc/specs/#12570 - Show Hide operations on GetConsoleWindow via PTY.md

Large diffs are not rendered by default.

16 changes: 16 additions & 0 deletions src/cascadia/TerminalApp/AppLogic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1123,6 +1123,22 @@ namespace winrt::TerminalApp::implementation
}
}

// Method Description:
// - Used to tell the PTY connection that the window visibility has changed.
// The underlying PTY might need to expose window visibility status to the
// client application for the `::GetConsoleWindow()` API.
// Arguments:
// - showOrHide - True is show; false is hide.
// Return Value:
// - <none>
void AppLogic::WindowVisibilityChanged(const bool showOrHide)
{
if (_root)
{
_root->WindowVisibilityChanged(showOrHide);
}
}

// Method Description:
// - Implements the F7 handler (per GH#638)
// - Implements the Alt handler (per GH#6421)
Expand Down
2 changes: 2 additions & 0 deletions src/cascadia/TerminalApp/AppLogic.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ namespace winrt::TerminalApp::implementation
bool OnDirectKeyEvent(const uint32_t vkey, const uint8_t scanCode, const bool down);

void CloseWindow(Microsoft::Terminal::Settings::Model::LaunchPosition position);
void WindowVisibilityChanged(const bool showOrHide);

winrt::TerminalApp::TaskbarState TaskbarState();

Expand Down Expand Up @@ -207,6 +208,7 @@ namespace winrt::TerminalApp::implementation
FORWARDED_TYPED_EVENT(CloseRequested, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable, _root, CloseRequested);
FORWARDED_TYPED_EVENT(OpenSystemMenu, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable, _root, OpenSystemMenu);
FORWARDED_TYPED_EVENT(QuitRequested, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable, _root, QuitRequested);
FORWARDED_TYPED_EVENT(ShowWindowChanged, Windows::Foundation::IInspectable, winrt::Microsoft::Terminal::Control::ShowWindowArgs, _root, ShowWindowChanged);

#ifdef UNIT_TESTING
friend class TerminalAppLocalTests::CommandlineTest;
Expand Down
2 changes: 2 additions & 0 deletions src/cascadia/TerminalApp/AppLogic.idl
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ namespace TerminalApp
Single CalcSnappedDimension(Boolean widthOrHeight, Single dimension);
void TitlebarClicked();
void CloseWindow(Microsoft.Terminal.Settings.Model.LaunchPosition position);
void WindowVisibilityChanged(Boolean showOrHide);

TaskbarState TaskbarState{ get; };

Expand Down Expand Up @@ -132,5 +133,6 @@ namespace TerminalApp
event Windows.Foundation.TypedEventHandler<Object, Object> OpenSystemMenu;
event Windows.Foundation.TypedEventHandler<Object, Object> QuitRequested;
event Windows.Foundation.TypedEventHandler<Object, TerminalApp.SystemMenuChangeArgs> SystemMenuChangeRequested;
event Windows.Foundation.TypedEventHandler<Object, Microsoft.Terminal.Control.ShowWindowArgs> ShowWindowChanged;
}
}
44 changes: 44 additions & 0 deletions src/cascadia/TerminalApp/TerminalPage.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

Expand Down Expand Up @@ -1428,6 +1429,8 @@ namespace winrt::TerminalApp::implementation
term.SetTaskbarProgress({ get_weak(), &TerminalPage::_SetTaskbarProgressHandler });

term.ConnectionStateChanged({ get_weak(), &TerminalPage::_ConnectionStateChangedHandler });

term.ShowWindowChanged({ get_weak(), &TerminalPage::_ShowWindowChangedHandler });
}

// Method Description:
Expand Down Expand Up @@ -2340,6 +2343,17 @@ namespace winrt::TerminalApp::implementation
_SetTaskbarProgressHandlers(*this, nullptr);
}

// Method Description:
// - Send an event (which will be caught by AppHost) to change the show window state of the entire hosting window
// Arguments:
// - sender (not used)
// - args: the arguments specifying how to set the display status to ShowWindow for our window handle
winrt::fire_and_forget TerminalPage::_ShowWindowChangedHandler(const IInspectable /*sender*/, const Microsoft::Terminal::Control::ShowWindowArgs args)
{
co_await resume_foreground(Dispatcher());
_ShowWindowChangedHandlers(*this, args);
}

// Method Description:
// - Paste text from the Windows Clipboard to the focused terminal
void TerminalPage::_PasteText()
Expand Down Expand Up @@ -2416,6 +2430,9 @@ namespace winrt::TerminalApp::implementation
// TermControl will copy the settings out of the settings passed to it.
TermControl term{ settings.DefaultSettings(), settings.UnfocusedSettings(), connection };

// GH#12515: ConPTY assumes it's hidden at the start. If we're not, let it know now.
term.WindowVisibilityChanged(_visible);

if (_hostingHwnd.has_value())
{
term.OwningHwnd(reinterpret_cast<uint64_t>(*_hostingHwnd));
Expand Down Expand Up @@ -2848,6 +2865,33 @@ namespace winrt::TerminalApp::implementation
_DismissTabContextMenus();
}

// Method Description:
// - Notifies all attached console controls that the visibility of the
// hosting window has changed. The underlying PTYs may need to know this
// for the proper response to `::GetConsoleWindow()` from a Win32 console app.
// Arguments:
// - showOrHide: Show is true; hide is false.
// Return Value:
// - <none>
void TerminalPage::WindowVisibilityChanged(const bool showOrHide)
{
_visible = 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 (auto control = pane->GetTerminalControl())
{
control.WindowVisibilityChanged(showOrHide);
}
});
}
}
}

// Method Description:
// - Called when the user tries to do a search using keybindings.
// This will tell the current focused terminal control to create
Expand Down
5 changes: 5 additions & 0 deletions src/cascadia/TerminalApp/TerminalPage.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ namespace winrt::TerminalApp::implementation
hstring Title();

void TitlebarClicked();
void WindowVisibilityChanged(const bool showOrHide);

float CalcSnappedDimension(const bool widthOrHeight, const float dimension) const;

Expand Down Expand Up @@ -154,6 +155,7 @@ namespace winrt::TerminalApp::implementation
TYPED_EVENT(CloseRequested, IInspectable, IInspectable);
TYPED_EVENT(OpenSystemMenu, IInspectable, IInspectable);
TYPED_EVENT(QuitRequested, IInspectable, IInspectable);
TYPED_EVENT(ShowWindowChanged, IInspectable, winrt::Microsoft::Terminal::Control::ShowWindowArgs)

private:
friend struct TerminalPageT<TerminalPage>; // for Xaml to bind events
Expand Down Expand Up @@ -194,6 +196,7 @@ namespace winrt::TerminalApp::implementation
std::optional<int> _rearrangeFrom{};
std::optional<int> _rearrangeTo{};
bool _removing{ false };
bool _visible{ true };

std::vector<std::vector<Microsoft::Terminal::Settings::Model::ActionAndArgs>> _previouslyClosedPanesAndTabs{};

Expand Down Expand Up @@ -439,6 +442,8 @@ namespace winrt::TerminalApp::implementation
static bool _IsMessageDismissed(const winrt::Microsoft::Terminal::Settings::Model::InfoBarMessage& message);
static void _DismissMessage(const winrt::Microsoft::Terminal::Settings::Model::InfoBarMessage& message);

winrt::fire_and_forget _ShowWindowChangedHandler(const IInspectable sender, const winrt::Microsoft::Terminal::Control::ShowWindowArgs args);

#pragma region ActionHandlers
// These are all defined in AppActionHandlers.cpp
#define ON_ALL_ACTIONS(action) DECLARE_ACTION_HANDLER(action);
Expand Down
1 change: 1 addition & 0 deletions src/cascadia/TerminalApp/TerminalPage.idl
Original file line number Diff line number Diff line change
Expand Up @@ -59,5 +59,6 @@ namespace TerminalApp
event Windows.Foundation.TypedEventHandler<Object, Object> SummonWindowRequested;
event Windows.Foundation.TypedEventHandler<Object, Object> CloseRequested;
event Windows.Foundation.TypedEventHandler<Object, Object> OpenSystemMenu;
event Windows.Foundation.TypedEventHandler<Object, Microsoft.Terminal.Control.ShowWindowArgs> ShowWindowChanged;
}
}
15 changes: 15 additions & 0 deletions src/cascadia/TerminalConnection/ConptyConnection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,8 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation

THROW_IF_FAILED(_CreatePseudoConsoleAndPipes(dimensions, flags, &_inPipe, &_outPipe, &_hPC));

// GH#12515: The conpty assumes it's hidden at the start. If we're visible, let it know now.
THROW_IF_FAILED(ConptyShowHidePseudoConsole(_hPC.get(), _initialVisibility));
if (_initialParentHwnd != 0)
{
THROW_IF_FAILED(ConptyReparentPseudoConsole(_hPC.get(), reinterpret_cast<HWND>(_initialParentHwnd)));
Expand Down Expand Up @@ -489,6 +491,19 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
}
}

void ConptyConnection::ShowHide(const bool show)
{
// If we haven't connected yet, then stash for when we do connect.
if (_isConnected())
{
THROW_IF_FAILED(ConptyShowHidePseudoConsole(_hPC.get(), show));
}
else
{
_initialVisibility = show;
}
}

void ConptyConnection::ReparentWindow(const uint64_t newParent)
{
// If we haven't started connecting at all, stash this HWND to use once we have started.
Expand Down
4 changes: 4 additions & 0 deletions src/cascadia/TerminalConnection/ConptyConnection.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
void Resize(uint32_t rows, uint32_t columns);
void Close() noexcept;
void ClearBuffer();

void ShowHide(const bool show);

void ReparentWindow(const uint64_t newParent);

winrt::guid Guid() const noexcept;
Expand Down Expand Up @@ -70,6 +73,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
hstring _commandline{};
hstring _startingDirectory{};
hstring _startingTitle{};
bool _initialVisibility{ false };
Windows::Foundation::Collections::ValueSet _environment{ nullptr };
guid _guid{}; // A unique session identifier for connected client
hstring _clientName{}; // The name of the process hosted by this ConPTY connection (as of launch).
Expand Down
4 changes: 4 additions & 0 deletions src/cascadia/TerminalConnection/ConptyConnection.idl
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ namespace Microsoft.Terminal.TerminalConnection
ConptyConnection();
Guid Guid { get; };
String Commandline { get; };

void ClearBuffer();

void ShowHide(Boolean show);

void ReparentWindow(UInt64 newParent);

static event NewConnectionHandler NewConnection;
Expand Down
28 changes: 28 additions & 0 deletions src/cascadia/TerminalControl/ControlCore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
auto pfnTerminalTaskbarProgressChanged = std::bind(&ControlCore::_terminalTaskbarProgressChanged, this);
_terminal->TaskbarProgressChangedCallback(pfnTerminalTaskbarProgressChanged);

auto pfnShowWindowChanged = std::bind(&ControlCore::_terminalShowWindowChanged, this, std::placeholders::_1);
_terminal->SetShowWindowCallback(pfnShowWindowChanged);

// MSFT 33353327: Initialize the renderer in the ctor instead of Initialize().
// We need the renderer to be ready to accept new engines before the SwapChainPanel is ready to go.
// If we wait, a screen reader may try to get the AutomationPeer (aka the UIA Engine), and we won't be able to attach
Expand Down Expand Up @@ -1214,6 +1217,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_TaskbarProgressChangedHandlers(*this, nullptr);
}

void ControlCore::_terminalShowWindowChanged(bool showOrHide)
{
auto showWindow = winrt::make_self<implementation::ShowWindowArgs>(showOrHide);
_ShowWindowChangedHandlers(*this, *showWindow);
}

bool ControlCore::HasSelection() const
{
return _terminal->IsSelectionActive();
Expand Down Expand Up @@ -1696,6 +1705,25 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
}

// Method Description:
// - Notifies the attached PTY that the window has changed visibility state
// - NOTE: Most VT commands are generated in `TerminalDispatch` and sent to this
// class as the target for transmission. But since this message isn't
// coming in via VT parsing (and rather from a window state transition)
// we generate and send it here.
// Arguments:
// - visible: True for visible; false for not visible.
// Return Value:
// - <none>
void ControlCore::WindowVisibilityChanged(const bool showOrHide)
{
// show is true, hide is false
if (auto conpty{ _connection.try_as<TerminalConnection::ConptyConnection>() })
{
conpty.ShowHide(showOrHide);
}
}

// Method Description:
// - When the control gains focus, it needs to tell ConPTY about this.
// Usually, these sequences are reserved for applications that
Expand Down
4 changes: 4 additions & 0 deletions src/cascadia/TerminalControl/ControlCore.h
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation

void AdjustOpacity(const double opacity, const bool relative);

void WindowVisibilityChanged(const bool showOrHide);

// TODO:GH#1256 - When a tab can be torn out or otherwise reparented to
// another window, this value will need a custom setter, so that we can
// also update the connection.
Expand Down Expand Up @@ -201,6 +203,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
TYPED_EVENT(TransparencyChanged, IInspectable, Control::TransparencyChangedEventArgs);
TYPED_EVENT(ReceivedOutput, IInspectable, IInspectable);
TYPED_EVENT(FoundMatch, IInspectable, Control::FoundResultsArgs);
TYPED_EVENT(ShowWindowChanged, IInspectable, Control::ShowWindowArgs);
// clang-format on

private:
Expand Down Expand Up @@ -268,6 +271,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
const int bufferSize);
void _terminalCursorPositionChanged();
void _terminalTaskbarProgressChanged();
void _terminalShowWindowChanged(bool showOrHide);
#pragma endregion

#pragma region RendererCallbacks
Expand Down
Loading

0 comments on commit 6b936d9

Please sign in to comment.