Skip to content

Commit 69b77ca

Browse files
committed
Merge commit '26d67d9c0af0a05b0e65aa76537006862d39535b' into dev/miniksa/msgs
2 parents 6bdc8c9 + 26d67d9 commit 69b77ca

27 files changed

+231
-15
lines changed

.github/actions/spelling/allow/apis.txt

+1
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ REGCLS
145145
RETURNCMD
146146
rfind
147147
roundf
148+
ROOTOWNER
148149
RSHIFT
149150
SACL
150151
schandle

src/cascadia/TerminalApp/TerminalPage.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,12 @@ namespace winrt::TerminalApp::implementation
6060

6161
// Method Description:
6262
// - implements the IInitializeWithWindow interface from shobjidl_core.
63+
// - We're going to use this HWND as the owner for the ConPTY windows, via
64+
// ConptyConnection::ReparentWindow. We need this for applications that
65+
// call GetConsoleWindow, and attempt to open a MessageBox for the
66+
// console. By marking the conpty windows as owned by the Terminal HWND,
67+
// the message box will be owned by the Terminal window as well.
68+
// - see GH#2988
6369
HRESULT TerminalPage::Initialize(HWND hwnd)
6470
{
6571
_hostingHwnd = hwnd;
@@ -2429,6 +2435,10 @@ namespace winrt::TerminalApp::implementation
24292435
term.WindowVisibilityChanged(_visible);
24302436
}
24312437

2438+
if (_hostingHwnd.has_value())
2439+
{
2440+
term.OwningHwnd(reinterpret_cast<uint64_t>(*_hostingHwnd));
2441+
}
24322442
return term;
24332443
}
24342444

src/cascadia/TerminalConnection/ConptyConnection.cpp

+21
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,10 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
316316
{
317317
THROW_IF_FAILED(ConptyShowHidePseudoConsole(_hPC.get(), _initialVisibility));
318318
}
319+
if (_initialParentHwnd != 0)
320+
{
321+
THROW_IF_FAILED(ConptyReparentPseudoConsole(_hPC.get(), reinterpret_cast<HWND>(_initialParentHwnd)));
322+
}
319323

320324
THROW_IF_FAILED(_LaunchAttachedClient());
321325
}
@@ -334,6 +338,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
334338
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
335339

336340
THROW_IF_FAILED(ConptyResizePseudoConsole(_hPC.get(), dimensions));
341+
THROW_IF_FAILED(ConptyReparentPseudoConsole(_hPC.get(), reinterpret_cast<HWND>(_initialParentHwnd)));
337342
}
338343

339344
_startTime = std::chrono::high_resolution_clock::now();
@@ -502,6 +507,22 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
502507
}
503508
}
504509

510+
void ConptyConnection::ReparentWindow(const uint64_t newParent)
511+
{
512+
// If we haven't started connecting at all, stash this HWND to use once we have started.
513+
if (!_isStateAtOrBeyond(ConnectionState::Connecting))
514+
{
515+
_initialParentHwnd = newParent;
516+
}
517+
// Otherwise, just inform the conpty of the new owner window handle.
518+
// This shouldn't be hittable until GH#5000 / GH#1256, when it's
519+
// possible to reparent terminals to different windows.
520+
else if (_isConnected())
521+
{
522+
THROW_IF_FAILED(ConptyReparentPseudoConsole(_hPC.get(), reinterpret_cast<HWND>(newParent)));
523+
}
524+
}
525+
505526
void ConptyConnection::Close() noexcept
506527
try
507528
{

src/cascadia/TerminalConnection/ConptyConnection.h

+4
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,11 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
3535
void Resize(uint32_t rows, uint32_t columns);
3636
void Close() noexcept;
3737
void ClearBuffer();
38+
3839
void ShowHide(const bool show);
3940

41+
void ReparentWindow(const uint64_t newParent);
42+
4043
winrt::guid Guid() const noexcept;
4144
winrt::hstring Commandline() const;
4245

@@ -66,6 +69,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
6669

6770
uint32_t _initialRows{};
6871
uint32_t _initialCols{};
72+
uint64_t _initialParentHwnd{ 0 };
6973
hstring _commandline{};
7074
hstring _startingDirectory{};
7175
hstring _startingTitle{};

src/cascadia/TerminalConnection/ConptyConnection.idl

+3
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,11 @@ namespace Microsoft.Terminal.TerminalConnection
1414
String Commandline { get; };
1515

1616
void ClearBuffer();
17+
1718
void ShowHide(Boolean show);
1819

20+
void ReparentWindow(UInt64 newParent);
21+
1922
static event NewConnectionHandler NewConnection;
2023
static void StartInboundListener();
2124
static void StopInboundListener();

src/cascadia/TerminalControl/ControlCore.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation
265265
const auto height = vp.Height();
266266
_connection.Resize(height, width);
267267

268+
if (_OwningHwnd != 0)
269+
{
270+
if (auto conpty{ _connection.try_as<TerminalConnection::ConptyConnection>() })
271+
{
272+
conpty.ReparentWindow(_OwningHwnd);
273+
}
274+
}
275+
268276
// Override the default width and height to match the size of the swapChainPanel
269277
_settings->InitialCols(width);
270278
_settings->InitialRows(height);

src/cascadia/TerminalControl/ControlCore.h

+5
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
170170

171171
void WindowVisibilityChanged(const bool showOrHide);
172172

173+
// TODO:GH#1256 - When a tab can be torn out or otherwise reparented to
174+
// another window, this value will need a custom setter, so that we can
175+
// also update the connection.
176+
WINRT_PROPERTY(uint64_t, OwningHwnd, 0);
177+
173178
RUNTIME_SETTING(double, Opacity, _settings->Opacity());
174179
RUNTIME_SETTING(bool, UseAcrylic, _settings->UseAcrylic());
175180

src/cascadia/TerminalControl/ICoreState.idl

+3
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,8 @@ namespace Microsoft.Terminal.Control
2424
Microsoft.Terminal.TerminalConnection.ConnectionState ConnectionState { get; };
2525

2626
Microsoft.Terminal.Core.Scheme ColorScheme { get; set; };
27+
28+
UInt64 OwningHwnd;
29+
2730
};
2831
}

src/cascadia/TerminalControl/TermControl.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -2807,4 +2807,14 @@ namespace winrt::Microsoft::Terminal::Control::implementation
28072807
}
28082808
}
28092809

2810+
void TermControl::OwningHwnd(uint64_t owner)
2811+
{
2812+
_core.OwningHwnd(owner);
2813+
}
2814+
2815+
uint64_t TermControl::OwningHwnd()
2816+
{
2817+
return _core.OwningHwnd();
2818+
}
2819+
28102820
}

src/cascadia/TerminalControl/TermControl.h

+3
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
6161
bool BracketedPasteEnabled() const noexcept;
6262

6363
double BackgroundOpacity() const;
64+
65+
uint64_t OwningHwnd();
66+
void OwningHwnd(uint64_t owner);
6467
#pragma endregion
6568

6669
void ScrollViewport(int viewTop);

src/cascadia/WindowsTerminal/IslandWindow.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@ IslandWindow::~IslandWindow()
4141
_source.Close();
4242
}
4343

44+
HWND IslandWindow::GetInteropHandle() const
45+
{
46+
return _interopWindowHandle;
47+
}
48+
4449
// Method Description:
4550
// - Create the actual window that we'll use for the application.
4651
// Arguments:

src/cascadia/WindowsTerminal/IslandWindow.h

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ class IslandWindow :
2323
virtual void MakeWindow() noexcept;
2424
void Close();
2525
virtual void OnSize(const UINT width, const UINT height);
26+
HWND GetInteropHandle() const;
2627

2728
[[nodiscard]] virtual LRESULT MessageHandler(UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept override;
2829
void OnResize(const UINT width, const UINT height) override;

src/host/PtySignalInputThread.cpp

+46
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ DWORD WINAPI PtySignalInputThread::StaticThreadProc(_In_ LPVOID lpParameter)
5656
// (in and screen buffers) haven't yet been initialized.
5757
// - NOTE: Call under LockConsole() to ensure other threads have an opportunity
5858
// to set early-work state.
59+
// - We need to do this specifically on the thread with the message pump. If the
60+
// window is created on another thread, then the window won't have a message
61+
// pump associated with it, and a DPI change in the connected terminal could
62+
// end up HANGING THE CONPTY (for example).
5963
// Arguments:
6064
// - <none>
6165
// Return Value:
@@ -71,6 +75,12 @@ void PtySignalInputThread::ConnectConsole() noexcept
7175
{
7276
_DoShowHide(_initialShowHide->show);
7377
}
78+
79+
// If we were given a owner HWND, then manually start the pseudo window now.
80+
if (_earlyReparent)
81+
{
82+
_DoSetWindowParent(*_earlyReparent);
83+
}
7484
}
7585

7686
// Method Description:
@@ -150,6 +160,28 @@ void PtySignalInputThread::ConnectConsole() noexcept
150160

151161
break;
152162
}
163+
case PtySignal::SetParent:
164+
{
165+
SetParentData reparentMessage = { 0 };
166+
_GetData(&reparentMessage, sizeof(reparentMessage));
167+
168+
LockConsole();
169+
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
170+
171+
// If the client app hasn't yet connected, stash the new owner.
172+
// We'll later (PtySignalInputThread::ConnectConsole) use the value
173+
// to set up the owner of the conpty window.
174+
if (!_consoleConnected)
175+
{
176+
_earlyReparent = reparentMessage;
177+
}
178+
else
179+
{
180+
_DoSetWindowParent(reparentMessage);
181+
}
182+
183+
break;
184+
}
153185
default:
154186
{
155187
THROW_HR(E_UNEXPECTED);
@@ -183,6 +215,20 @@ void PtySignalInputThread::_DoShowHide(const bool show)
183215
_pConApi->ShowWindow(show);
184216
}
185217

218+
// Method Description:
219+
// - Update the owner of the pseudo-window we're using for the conpty HWND. This
220+
// allows to mark the pseudoconsole windows as "owner" by the terminal HWND
221+
// that's actually hosting them.
222+
// - Refer to GH#2988
223+
// Arguments:
224+
// - data - Packet information containing owner HWND information
225+
// Return Value:
226+
// - <none>
227+
void PtySignalInputThread::_DoSetWindowParent(const SetParentData& data)
228+
{
229+
_pConApi->ReparentWindow(data.handle);
230+
}
231+
186232
// Method Description:
187233
// - Retrieves bytes from the file stream and exits or throws errors should the pipe state
188234
// be compromised.

src/host/PtySignalInputThread.hpp

+11
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ namespace Microsoft::Console
4242
{
4343
ShowHideWindow = 1,
4444
ClearBuffer = 2,
45+
SetParent = 3,
4546
ResizeWindow = 8
4647
};
4748

@@ -50,14 +51,21 @@ namespace Microsoft::Console
5051
unsigned short sx;
5152
unsigned short sy;
5253
};
54+
5355
struct ShowHideData
5456
{
5557
unsigned short show; // used as a bool, but passed as a ushort
5658
};
5759

60+
struct SetParentData
61+
{
62+
uint64_t handle;
63+
};
64+
5865
[[nodiscard]] HRESULT _InputThread();
5966
bool _GetData(_Out_writes_bytes_(cbBuffer) void* const pBuffer, const DWORD cbBuffer);
6067
void _DoResizeWindow(const ResizeWindowData& data);
68+
void _DoSetWindowParent(const SetParentData& data);
6169
void _DoClearBuffer();
6270
void _DoShowHide(const bool show);
6371
void _Shutdown();
@@ -69,5 +77,8 @@ namespace Microsoft::Console
6977
std::optional<ResizeWindowData> _earlyResize;
7078
std::optional<ShowHideData> _initialShowHide;
7179
std::unique_ptr<Microsoft::Console::VirtualTerminal::ConGetSet> _pConApi;
80+
81+
public:
82+
std::optional<SetParentData> _earlyReparent;
7283
};
7384
}

src/host/VtIo.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,11 @@ bool VtIo::IsUsingVt() const
300300

301301
if (_pPtySignalInputThread)
302302
{
303+
// IMPORTANT! Start the pseudo window on this thread. This thread has a
304+
// message pump. If you DON'T, then a DPI change in the owning hwnd will
305+
// cause us to get a dpi change as well, which we'll never deque and
306+
// handle, effectively HANGING THE OWNER HWND.
307+
//
303308
// Let the signal thread know that the console is connected
304309
_pPtySignalInputThread->ConnectConsole();
305310
}

src/host/outputStream.cpp

+14
Original file line numberDiff line numberDiff line change
@@ -905,3 +905,17 @@ void ConhostInternalGetSet::UpdateSoftFont(const gsl::span<const uint16_t> bitPa
905905
pRender->UpdateSoftFont(bitPattern, cellSize, centeringHint);
906906
}
907907
}
908+
909+
void ConhostInternalGetSet::ReparentWindow(const uint64_t handle)
910+
{
911+
// This will initialize s_interactivityFactory for us. It will also
912+
// conveniently return 0 when we're on OneCore.
913+
//
914+
// If the window hasn't been created yet, by some other call to
915+
// LocatePseudoWindow, then this will also initialize the owner of the
916+
// window.
917+
if (const auto psuedoHwnd{ ServiceLocator::LocatePseudoWindow(reinterpret_cast<HWND>(handle)) })
918+
{
919+
LOG_LAST_ERROR_IF_NULL(::SetParent(psuedoHwnd, reinterpret_cast<HWND>(handle)));
920+
}
921+
}

src/host/outputStream.hpp

+2
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@ class ConhostInternalGetSet final : public Microsoft::Console::VirtualTerminal::
117117
const SIZE cellSize,
118118
const size_t centeringHint) override;
119119

120+
void ReparentWindow(const uint64_t handle);
121+
120122
private:
121123
void _modifyLines(const size_t count, const bool insert);
122124

src/inc/conpty-static.h

+2
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ HRESULT WINAPI ConptyClearPseudoConsole(HPCON hPC);
2727

2828
HRESULT WINAPI ConptyShowHidePseudoConsole(HPCON hPC, bool show);
2929

30+
HRESULT WINAPI ConptyReparentPseudoConsole(HPCON hPC, HWND newParent);
31+
3032
VOID WINAPI ConptyClosePseudoConsole(HPCON hPC);
3133

3234
HRESULT WINAPI ConptyPackPseudoConsole(HANDLE hServerProcess, HANDLE hRef, HANDLE hSignal, HPCON* phPC);

0 commit comments

Comments
 (0)