mirror of
https://github.com/microsoft/terminal.git
synced 2026-04-06 14:19:45 +00:00
Compare commits
16 Commits
dev/migrie
...
v1.14.1451
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
997b4acce5 | ||
|
|
287db8a483 | ||
|
|
07f7717112 | ||
|
|
39c71d6421 | ||
|
|
c0e6c259fc | ||
|
|
6d636056a0 | ||
|
|
20a6c7078b | ||
|
|
eec6a882d6 | ||
|
|
bc9e43a19d | ||
|
|
858359e62e | ||
|
|
5fbd5392e7 | ||
|
|
28284e824f | ||
|
|
61e6927f34 | ||
|
|
95693e9079 | ||
|
|
eb40b51b79 | ||
|
|
521d968a75 |
2
.github/actions/spelling/allow/apis.txt
vendored
2
.github/actions/spelling/allow/apis.txt
vendored
@@ -30,7 +30,6 @@ DERR
|
||||
dlldata
|
||||
DONTADDTORECENT
|
||||
DWORDLONG
|
||||
DWMWA
|
||||
endfor
|
||||
enumset
|
||||
environstrings
|
||||
@@ -155,7 +154,6 @@ serializer
|
||||
SETVERSION
|
||||
SHELLEXECUTEINFOW
|
||||
shobjidl
|
||||
SHOWDEFAULT
|
||||
SHOWHIDE
|
||||
SHOWMINIMIZED
|
||||
SHOWTIP
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- Optional, defaults to main. Name of the branch which will be used for calculating branch point. -->
|
||||
<PGOBranch>main</PGOBranch>
|
||||
<PGOBranch>release-1.14</PGOBranch>
|
||||
|
||||
<!-- Mandatory. Name of the NuGet package which will contain PGO databases for consumption by build system. -->
|
||||
<PGOPackageName>Microsoft.Internal.Windows.Terminal.PGODatabase</PGOPackageName>
|
||||
|
||||
@@ -1708,6 +1708,11 @@
|
||||
"description": "Force the terminal to use the legacy input encoding. Certain keys in some applications may stop working when enabling this setting.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"experimental.useBackgroundImageForWindow": {
|
||||
"default": false,
|
||||
"description": "When set to true, the background image for the currently focused profile is expanded to encompass the entire window, beneath other panes.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"initialCols": {
|
||||
"default": 120,
|
||||
"description": "The number of columns displayed in the window upon first load. If \"launchMode\" is set to \"maximized\" (or \"maximizedFocus\"), this property is ignored.",
|
||||
|
||||
@@ -153,10 +153,6 @@
|
||||
|
||||
<StaticResource x:Key="UnfocusedBorderBrush"
|
||||
ResourceKey="ApplicationPageBackgroundThemeBrush" />
|
||||
|
||||
<StaticResource x:Key="SettingsPageBackground"
|
||||
ResourceKey="SolidBackgroundFillColorTertiary" />
|
||||
|
||||
</ResourceDictionary>
|
||||
|
||||
<ResourceDictionary x:Key="Light">
|
||||
@@ -170,9 +166,6 @@
|
||||
|
||||
<StaticResource x:Key="UnfocusedBorderBrush"
|
||||
ResourceKey="ApplicationPageBackgroundThemeBrush" />
|
||||
|
||||
<StaticResource x:Key="SettingsPageBackground"
|
||||
ResourceKey="SolidBackgroundFillColorTertiary" />
|
||||
</ResourceDictionary>
|
||||
|
||||
<ResourceDictionary x:Key="HighContrast">
|
||||
@@ -190,9 +183,6 @@
|
||||
-->
|
||||
<StaticResource x:Key="TabViewBackground"
|
||||
ResourceKey="SystemColorButtonFaceColorBrush" />
|
||||
|
||||
<StaticResource x:Key="SettingsPageBackground"
|
||||
ResourceKey="SystemColorWindowColorBrush" />
|
||||
</ResourceDictionary>
|
||||
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
|
||||
@@ -199,7 +199,6 @@ namespace winrt::TerminalApp::implementation
|
||||
FORWARDED_TYPED_EVENT(FullscreenChanged, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable, _root, FullscreenChanged);
|
||||
FORWARDED_TYPED_EVENT(ChangeMaximizeRequested, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable, _root, ChangeMaximizeRequested);
|
||||
FORWARDED_TYPED_EVENT(AlwaysOnTopChanged, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable, _root, AlwaysOnTopChanged);
|
||||
FORWARDED_TYPED_EVENT(Initialized, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable, _root, Initialized);
|
||||
FORWARDED_TYPED_EVENT(RaiseVisualBell, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable, _root, RaiseVisualBell);
|
||||
FORWARDED_TYPED_EVENT(SetTaskbarProgress, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable, _root, SetTaskbarProgress);
|
||||
FORWARDED_TYPED_EVENT(IdentifyWindowsRequested, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable, _root, IdentifyWindowsRequested);
|
||||
|
||||
@@ -122,7 +122,6 @@ namespace TerminalApp
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> FullscreenChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> ChangeMaximizeRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> AlwaysOnTopChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> Initialized;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> RaiseVisualBell;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> SetTaskbarProgress;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> IdentifyWindowsRequested;
|
||||
|
||||
@@ -9,8 +9,11 @@
|
||||
xmlns:local="using:TerminalApp"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:mux="using:Microsoft.UI.Xaml.Controls"
|
||||
Background="{ThemeResource TabViewBackground}"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<!-- GH#13143: Make sure that the Background is actually TabViewBackground here, not Transparent. This is load bearing, for showTabsInTitlebar=false. -->
|
||||
|
||||
<mux:TabView x:Name="TabView"
|
||||
VerticalAlignment="Bottom"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
|
||||
@@ -218,6 +218,24 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
// Inform the host that our titlebar content has changed.
|
||||
_SetTitleBarContentHandlers(*this, _tabRow);
|
||||
|
||||
// GH#13143 Manually set the tab row's background to transparent here.
|
||||
//
|
||||
// We're doing it this way because ThemeResources are tricky. We
|
||||
// default in XAML to using the appropriate ThemeResource background
|
||||
// color for our TabRow. When tabs in the titlebar are _disabled_,
|
||||
// this will ensure that the tab row has the correct theme-dependent
|
||||
// value. When tabs in the titlebar are _enabled_ (the default),
|
||||
// we'll switch the BG to Transparent, to let the Titlebar Control's
|
||||
// background be used as the BG for the tab row.
|
||||
//
|
||||
// We can't do it the other way around (default to Transparent, only
|
||||
// switch to a color when disabling tabs in the titlebar), because
|
||||
// looking up the correct ThemeResource from and App dictionary is a
|
||||
// capital-H Hard problem.
|
||||
const auto transparent = Media::SolidColorBrush();
|
||||
transparent.Color(Windows::UI::Colors::Transparent());
|
||||
_tabRow.Background(transparent);
|
||||
}
|
||||
|
||||
// Hookup our event handlers to the ShortcutActionDispatch
|
||||
@@ -659,7 +677,7 @@ namespace winrt::TerminalApp::implementation
|
||||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
winrt::fire_and_forget TerminalPage::_CompleteInitialization()
|
||||
void TerminalPage::_CompleteInitialization()
|
||||
{
|
||||
_startupState = StartupState::Initialized;
|
||||
|
||||
@@ -679,55 +697,10 @@ namespace winrt::TerminalApp::implementation
|
||||
if (_tabs.Size() == 0 && !(_shouldStartInboundListener || _isEmbeddingInboundListener))
|
||||
{
|
||||
_LastTabClosedHandlers(*this, nullptr);
|
||||
co_return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// GH#11561: When we start up, our window is initially just a frame
|
||||
// with a transparent content area. We're gonna do all this startup
|
||||
// init on the UI thread, so the UI won't actually paint till it's
|
||||
// all done. This results in a few frames where the frame is
|
||||
// visible, before the page paints for the first time, before any
|
||||
// tabs appears, etc.
|
||||
//
|
||||
// To mitigate this, we're gonna wait for the UI thread to finish
|
||||
// everything it's gotta do for the initial init, and _then_ fire
|
||||
// our Initialized event. By waiting for everything else to finish
|
||||
// (CoreDispatcherPriority::Low), we let all the tabs and panes
|
||||
// actually get created. In the window layer, we're gonna cloak the
|
||||
// window till this event is fired, so we don't actually see this
|
||||
// frame until we're actually all ready to go.
|
||||
//
|
||||
// This will result in the window seemingly not loading as fast, but
|
||||
// it will actually take exactly the same amount of time before it's
|
||||
// usable.
|
||||
//
|
||||
// We also experimented with drawing a solid BG color before the
|
||||
// initialization is finished. However, there are still a few frames
|
||||
// after the frame is displayed before the XAML content first draws,
|
||||
// so that didn't actually resolve any issues.
|
||||
|
||||
auto weak{ get_weak() };
|
||||
|
||||
// Switch to the BG thread -
|
||||
co_await winrt::resume_background();
|
||||
|
||||
if (auto self{ weak.get() })
|
||||
{
|
||||
// Then enqueue the rest of this function for after the UI thread settles.
|
||||
co_await wil::resume_foreground(self->Dispatcher(), CoreDispatcherPriority::Low);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We don't exist anymore? Well, we probably don't need to fire
|
||||
// off an Initialized event then...
|
||||
co_return;
|
||||
}
|
||||
|
||||
if (auto self{ weak.get() })
|
||||
{
|
||||
self->_InitializedHandlers(*self, nullptr);
|
||||
}
|
||||
_InitializedHandlers(*this, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1849,9 +1822,17 @@ namespace winrt::TerminalApp::implementation
|
||||
// Instead, let's just promote this first split to be a tab instead.
|
||||
// Crash avoided, and we don't need to worry about inserting a new-tab
|
||||
// command in at the start.
|
||||
if (!focusedTab && _tabs.Size() == 0)
|
||||
if (!focusedTab)
|
||||
{
|
||||
_CreateNewTabFromPane(newPane);
|
||||
if (_tabs.Size() == 0)
|
||||
{
|
||||
_CreateNewTabFromPane(newPane);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The focused tab isn't a terminal tab
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2476,7 +2457,10 @@ namespace winrt::TerminalApp::implementation
|
||||
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 (_visible)
|
||||
{
|
||||
term.WindowVisibilityChanged(_visible);
|
||||
}
|
||||
|
||||
if (_hostingHwnd.has_value())
|
||||
{
|
||||
@@ -2596,7 +2580,8 @@ namespace winrt::TerminalApp::implementation
|
||||
// - <none>
|
||||
void TerminalPage::_SetBackgroundImage(const winrt::Microsoft::Terminal::Settings::Model::IAppearanceConfig& newAppearance)
|
||||
{
|
||||
if (newAppearance.BackgroundImagePath().empty())
|
||||
const auto path = newAppearance.ExpandedBackgroundImagePath();
|
||||
if (path.empty())
|
||||
{
|
||||
_tabContent.Background(nullptr);
|
||||
return;
|
||||
@@ -2605,7 +2590,7 @@ namespace winrt::TerminalApp::implementation
|
||||
Windows::Foundation::Uri imageUri{ nullptr };
|
||||
try
|
||||
{
|
||||
imageUri = Windows::Foundation::Uri{ newAppearance.BackgroundImagePath() };
|
||||
imageUri = Windows::Foundation::Uri{ path };
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
@@ -2622,7 +2607,7 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
if (imageSource == nullptr ||
|
||||
imageSource.UriSource() == nullptr ||
|
||||
imageSource.UriSource().RawUri() != imageUri.RawUri())
|
||||
!imageSource.UriSource().Equals(imageUri))
|
||||
{
|
||||
Media::ImageBrush b{};
|
||||
// Note that BitmapImage handles the image load asynchronously,
|
||||
|
||||
@@ -147,7 +147,7 @@ namespace winrt::TerminalApp::implementation
|
||||
TYPED_EVENT(AlwaysOnTopChanged, IInspectable, IInspectable);
|
||||
TYPED_EVENT(RaiseVisualBell, IInspectable, IInspectable);
|
||||
TYPED_EVENT(SetTaskbarProgress, IInspectable, IInspectable);
|
||||
TYPED_EVENT(Initialized, IInspectable, IInspectable);
|
||||
TYPED_EVENT(Initialized, IInspectable, winrt::Windows::UI::Xaml::RoutedEventArgs);
|
||||
TYPED_EVENT(IdentifyWindowsRequested, IInspectable, IInspectable);
|
||||
TYPED_EVENT(RenameWindowRequested, Windows::Foundation::IInspectable, winrt::TerminalApp::RenameWindowRequestedArgs);
|
||||
TYPED_EVENT(IsQuakeWindowChanged, IInspectable, IInspectable);
|
||||
@@ -390,7 +390,7 @@ namespace winrt::TerminalApp::implementation
|
||||
|
||||
void _StartInboundListener();
|
||||
|
||||
winrt::fire_and_forget _CompleteInitialization();
|
||||
void _CompleteInitialization();
|
||||
|
||||
void _FocusActiveControl(IInspectable sender, IInspectable eventArgs);
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace TerminalApp
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> FocusModeChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> FullscreenChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> AlwaysOnTopChanged;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> Initialized;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Windows.UI.Xaml.RoutedEventArgs> Initialized;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> SetTaskbarProgress;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> IdentifyWindowsRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, RenameWindowRequestedArgs> RenameWindowRequested;
|
||||
|
||||
@@ -311,13 +311,17 @@ 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)));
|
||||
}
|
||||
|
||||
// GH#12515: The conpty assumes it's hidden at the start. If we're visible, let it know now.
|
||||
if (_initialVisibility)
|
||||
{
|
||||
THROW_IF_FAILED(ConptyShowHidePseudoConsole(_hPC.get(), _initialVisibility));
|
||||
}
|
||||
|
||||
THROW_IF_FAILED(_LaunchAttachedClient());
|
||||
}
|
||||
// But if it was an inbound handoff... attempt to synchronize the size of it with what our connection
|
||||
@@ -336,6 +340,11 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
|
||||
THROW_IF_FAILED(ConptyResizePseudoConsole(_hPC.get(), dimensions));
|
||||
THROW_IF_FAILED(ConptyReparentPseudoConsole(_hPC.get(), reinterpret_cast<HWND>(_initialParentHwnd)));
|
||||
|
||||
if (_initialVisibility)
|
||||
{
|
||||
THROW_IF_FAILED(ConptyShowHidePseudoConsole(_hPC.get(), _initialVisibility));
|
||||
}
|
||||
}
|
||||
|
||||
_startTime = std::chrono::high_resolution_clock::now();
|
||||
|
||||
@@ -73,7 +73,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
|
||||
hstring _commandline{};
|
||||
hstring _startingDirectory{};
|
||||
hstring _startingTitle{};
|
||||
bool _initialVisibility{ false };
|
||||
bool _initialVisibility{ true };
|
||||
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).
|
||||
|
||||
@@ -1210,8 +1210,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
void ControlCore::_terminalShowWindowChanged(bool showOrHide)
|
||||
{
|
||||
auto showWindow = winrt::make_self<implementation::ShowWindowArgs>(showOrHide);
|
||||
_ShowWindowChangedHandlers(*this, *showWindow);
|
||||
if (_initializedTerminal)
|
||||
{
|
||||
auto showWindow = winrt::make_self<implementation::ShowWindowArgs>(showOrHide);
|
||||
_ShowWindowChangedHandlers(*this, *showWindow);
|
||||
}
|
||||
}
|
||||
|
||||
bool ControlCore::HasSelection() const
|
||||
@@ -1712,10 +1715,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
// - <none>
|
||||
void ControlCore::WindowVisibilityChanged(const bool showOrHide)
|
||||
{
|
||||
// show is true, hide is false
|
||||
if (auto conpty{ _connection.try_as<TerminalConnection::ConptyConnection>() })
|
||||
if (_initializedTerminal)
|
||||
{
|
||||
conpty.ShowHide(showOrHide);
|
||||
// show is true, hide is false
|
||||
if (auto conpty{ _connection.try_as<TerminalConnection::ConptyConnection>() })
|
||||
{
|
||||
conpty.ShowHide(showOrHide);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -426,7 +426,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
|
||||
|
||||
if (imageSource == nullptr ||
|
||||
imageSource.UriSource() == nullptr ||
|
||||
imageSource.UriSource().RawUri() != imageUri.RawUri())
|
||||
!imageSource.UriSource().Equals(imageUri))
|
||||
{
|
||||
// Note that BitmapImage handles the image load asynchronously,
|
||||
// which is especially important since the image
|
||||
|
||||
@@ -37,8 +37,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
L"qps-PLOCA",
|
||||
L"qps-PLOCM",
|
||||
L"ru",
|
||||
L"zh-Hans-CN",
|
||||
L"zh-Hant-TW",
|
||||
L"zh-Hans",
|
||||
L"zh-Hant",
|
||||
};
|
||||
|
||||
GlobalAppearance::GlobalAppearance()
|
||||
|
||||
@@ -9,13 +9,43 @@
|
||||
xmlns:local="using:Microsoft.Terminal.Settings.Editor"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
|
||||
Background="{ThemeResource SettingsPageBackground}"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Page.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="CommonResources.xaml" />
|
||||
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
|
||||
<!--
|
||||
These two values are "SolidBackgroundFillColorTertiary".
|
||||
We can't just put those here though as
|
||||
StaticResources, because XAML will evaluate their
|
||||
values when the App is first loaded, and we'll
|
||||
always use the value from the OS theme, regardless
|
||||
of the requested theme. Kinda the same thing we've
|
||||
had to do with TabViewBackground in the past.
|
||||
-->
|
||||
|
||||
<ResourceDictionary x:Key="Dark">
|
||||
<Color x:Key="SettingsPageBackground">#282828</Color>
|
||||
</ResourceDictionary>
|
||||
|
||||
<ResourceDictionary x:Key="Light">
|
||||
<Color x:Key="SettingsPageBackground">#F9F9F9</Color>
|
||||
</ResourceDictionary>
|
||||
|
||||
<ResourceDictionary x:Key="HighContrast">
|
||||
<!-- Define resources for HighContrast mode here -->
|
||||
<StaticResource x:Key="SettingsPageBackground"
|
||||
ResourceKey="SystemColorWindowColorBrush" />
|
||||
</ResourceDictionary>
|
||||
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
</ResourceDictionary>
|
||||
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<SolidColorBrush x:Key="NavigationViewExpandedPaneBackground"
|
||||
@@ -30,7 +60,7 @@
|
||||
</Page.Resources>
|
||||
|
||||
<muxc:NavigationView x:Name="SettingsNav"
|
||||
Background="Transparent"
|
||||
Background="{ThemeResource SettingsPageBackground}"
|
||||
IsBackButtonVisible="Collapsed"
|
||||
IsSettingsVisible="False"
|
||||
ItemInvoked="SettingsNav_ItemInvoked"
|
||||
|
||||
@@ -107,7 +107,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
|
||||
Model::TerminalSettings ProfileViewModel::TermSettings() const
|
||||
{
|
||||
return Model::TerminalSettings::CreateWithProfile(_appSettings, _profile, nullptr).DefaultSettings();
|
||||
return Model::TerminalSettings::CreateForPreview(_appSettings, _profile);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
||||
@@ -50,6 +50,25 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
return { horizAlign, vertAlign };
|
||||
}
|
||||
|
||||
winrt::com_ptr<implementation::TerminalSettings> TerminalSettings::_CreateWithProfileCommon(const Model::CascadiaSettings& appSettings, const Model::Profile& profile)
|
||||
{
|
||||
auto settings{ winrt::make_self<TerminalSettings>() };
|
||||
|
||||
const auto globals = appSettings.GlobalSettings();
|
||||
settings->_ApplyProfileSettings(profile);
|
||||
settings->_ApplyGlobalSettings(globals);
|
||||
settings->_ApplyAppearanceSettings(profile.DefaultAppearance(), globals.ColorSchemes());
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
Model::TerminalSettings TerminalSettings::CreateForPreview(const Model::CascadiaSettings& appSettings, const Model::Profile& profile)
|
||||
{
|
||||
const auto settings = _CreateWithProfileCommon(appSettings, profile);
|
||||
settings->UseBackgroundImageForWindow(false);
|
||||
return *settings;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Create a TerminalSettingsCreateResult for the provided profile guid. We'll
|
||||
// use the guid to look up the profile that should be used to
|
||||
@@ -64,17 +83,13 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
// one for when the terminal is focused and the other for when the terminal is unfocused
|
||||
Model::TerminalSettingsCreateResult TerminalSettings::CreateWithProfile(const Model::CascadiaSettings& appSettings, const Model::Profile& profile, const IKeyBindings& keybindings)
|
||||
{
|
||||
auto settings{ winrt::make_self<TerminalSettings>() };
|
||||
const auto settings = _CreateWithProfileCommon(appSettings, profile);
|
||||
settings->_KeyBindings = keybindings;
|
||||
|
||||
const auto globals = appSettings.GlobalSettings();
|
||||
settings->_ApplyProfileSettings(profile);
|
||||
settings->_ApplyGlobalSettings(globals);
|
||||
settings->_ApplyAppearanceSettings(profile.DefaultAppearance(), globals.ColorSchemes());
|
||||
|
||||
Model::TerminalSettings child{ nullptr };
|
||||
if (const auto& unfocusedAppearance{ profile.UnfocusedAppearance() })
|
||||
{
|
||||
const auto globals = appSettings.GlobalSettings();
|
||||
auto childImpl = settings->CreateChild();
|
||||
childImpl->_ApplyAppearanceSettings(unfocusedAppearance, globals.ColorSchemes());
|
||||
child = *childImpl;
|
||||
|
||||
@@ -55,6 +55,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
{
|
||||
TerminalSettings() = default;
|
||||
|
||||
static Model::TerminalSettings CreateForPreview(const Model::CascadiaSettings& appSettings, const Model::Profile& profile);
|
||||
|
||||
static Model::TerminalSettingsCreateResult CreateWithProfile(const Model::CascadiaSettings& appSettings,
|
||||
const Model::Profile& profile,
|
||||
const Control::IKeyBindings& keybindings);
|
||||
@@ -159,6 +161,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
|
||||
private:
|
||||
std::optional<std::array<Microsoft::Terminal::Core::Color, COLOR_TABLE_SIZE>> _ColorTable;
|
||||
gsl::span<Microsoft::Terminal::Core::Color> _getColorTableImpl();
|
||||
|
||||
static winrt::com_ptr<implementation::TerminalSettings> _CreateWithProfileCommon(const Model::CascadiaSettings& appSettings, const Model::Profile& profile);
|
||||
void _ApplyProfileSettings(const Model::Profile& profile);
|
||||
|
||||
void _ApplyGlobalSettings(const Model::GlobalAppSettings& globalSettings) noexcept;
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace Microsoft.Terminal.Settings.Model
|
||||
{
|
||||
TerminalSettings();
|
||||
|
||||
static TerminalSettings CreateForPreview(CascadiaSettings appSettings, Profile profile);
|
||||
static TerminalSettingsCreateResult CreateWithProfile(CascadiaSettings appSettings, Profile profile, Microsoft.Terminal.Control.IKeyBindings keybindings);
|
||||
static TerminalSettingsCreateResult CreateWithNewTerminalArgs(CascadiaSettings appSettings, NewTerminalArgs newTerminalArgs, Microsoft.Terminal.Control.IKeyBindings keybindings);
|
||||
|
||||
|
||||
@@ -73,7 +73,8 @@ AppHost::AppHost() noexcept :
|
||||
auto pfn = std::bind(&AppHost::_HandleCreateWindow,
|
||||
this,
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2);
|
||||
std::placeholders::_2,
|
||||
std::placeholders::_3);
|
||||
_window->SetCreateCallback(pfn);
|
||||
|
||||
_window->SetSnapDimensionCallback(std::bind(&winrt::TerminalApp::AppLogic::CalcSnappedDimension,
|
||||
@@ -116,6 +117,19 @@ AppHost::AppHost() noexcept :
|
||||
{
|
||||
_BecomeMonarch(nullptr, nullptr);
|
||||
}
|
||||
|
||||
// Create a throttled function for updating the window state, to match the
|
||||
// one requested by the pty. A 200ms delay was chosen because it's the
|
||||
// typical animation timeout in Windows. This does result in a delay between
|
||||
// the PTY requesting a change to the window state and the Terminal
|
||||
// realizing it, but should mitigate issues where the Terminal and PTY get
|
||||
// de-sync'd.
|
||||
_showHideWindowThrottler = std::make_shared<ThrottledFuncTrailing<bool>>(
|
||||
winrt::Windows::System::DispatcherQueue::GetForCurrentThread(),
|
||||
std::chrono::milliseconds(200),
|
||||
[this](const bool show) {
|
||||
_window->ShowWindowChanged(show);
|
||||
});
|
||||
}
|
||||
|
||||
AppHost::~AppHost()
|
||||
@@ -128,6 +142,8 @@ AppHost::~AppHost()
|
||||
// out the window, then close the app.
|
||||
_revokers = {};
|
||||
|
||||
_showHideWindowThrottler.reset();
|
||||
|
||||
_window = nullptr;
|
||||
_app.Close();
|
||||
_app = nullptr;
|
||||
@@ -378,7 +394,6 @@ void AppHost::Initialize()
|
||||
_revokers.FullscreenChanged = _logic.FullscreenChanged(winrt::auto_revoke, { this, &AppHost::_FullscreenChanged });
|
||||
_revokers.FocusModeChanged = _logic.FocusModeChanged(winrt::auto_revoke, { this, &AppHost::_FocusModeChanged });
|
||||
_revokers.AlwaysOnTopChanged = _logic.AlwaysOnTopChanged(winrt::auto_revoke, { this, &AppHost::_AlwaysOnTopChanged });
|
||||
_revokers.Initialized = _logic.Initialized(winrt::auto_revoke, { this, &AppHost::_AppInitializedHandler });
|
||||
_revokers.RaiseVisualBell = _logic.RaiseVisualBell(winrt::auto_revoke, { this, &AppHost::_RaiseVisualBell });
|
||||
_revokers.SystemMenuChangeRequested = _logic.SystemMenuChangeRequested(winrt::auto_revoke, { this, &AppHost::_SystemMenuChangeRequested });
|
||||
_revokers.ChangeMaximizeRequested = _logic.ChangeMaximizeRequested(winrt::auto_revoke, { this, &AppHost::_ChangeMaximizeRequested });
|
||||
@@ -520,31 +535,12 @@ LaunchPosition AppHost::_GetWindowLaunchPosition()
|
||||
return pos;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Callback for when the window is first being created (during WM_CREATE).
|
||||
// Stash the proposed size for later. We'll need that once we're totally
|
||||
// initialized, so that we can show the window in the right position *when we
|
||||
// want to show it*. If we did the _initialResizeAndRepositionWindow work now,
|
||||
// it would have no effect, because the window is not yet visible.
|
||||
// Arguments:
|
||||
// - hwnd: The HWND of the window we're about to create.
|
||||
// - proposedRect: The location and size of the window that we're about to
|
||||
// create. We'll use this rect to determine which monitor the window is about
|
||||
// to appear on.
|
||||
void AppHost::_HandleCreateWindow(const HWND /* hwnd */, RECT proposedRect)
|
||||
{
|
||||
// GH#11561: Hide the window until we're totally done being initialized.
|
||||
// More commentary in TerminalPage::_CompleteInitialization
|
||||
_proposedRect = proposedRect;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Resize the window we're about to create to the appropriate dimensions, as
|
||||
// specified in the settings. This is called once the app has finished it's
|
||||
// initial setup, once we have created all the tabs, panes, etc. We'll load
|
||||
// the settings for the app, then get the proposed size of the terminal from
|
||||
// the app. Using that proposed size, we'll resize the window we're creating,
|
||||
// so that it'll match the values in the settings.
|
||||
// specified in the settings. This will be called during the handling of
|
||||
// WM_CREATE. We'll load the settings for the app, then get the proposed size
|
||||
// of the terminal from the app. Using that proposed size, we'll resize the
|
||||
// window we're creating, so that it'll match the values in the settings.
|
||||
// Arguments:
|
||||
// - hwnd: The HWND of the window we're about to create.
|
||||
// - proposedRect: The location and size of the window that we're about to
|
||||
@@ -553,7 +549,7 @@ void AppHost::_HandleCreateWindow(const HWND /* hwnd */, RECT proposedRect)
|
||||
// - launchMode: A LaunchMode enum reference that indicates the launch mode
|
||||
// Return Value:
|
||||
// - None
|
||||
void AppHost::_initialResizeAndRepositionWindow(const HWND hwnd, RECT proposedRect, LaunchMode& launchMode)
|
||||
void AppHost::_HandleCreateWindow(const HWND hwnd, RECT proposedRect, LaunchMode& launchMode)
|
||||
{
|
||||
launchMode = _logic.GetLaunchMode();
|
||||
|
||||
@@ -1416,7 +1412,14 @@ void AppHost::_QuitAllRequested(const winrt::Windows::Foundation::IInspectable&,
|
||||
void AppHost::_ShowWindowChanged(const winrt::Windows::Foundation::IInspectable&,
|
||||
const winrt::Microsoft::Terminal::Control::ShowWindowArgs& args)
|
||||
{
|
||||
_window->ShowWindowChanged(args.ShowOrHide());
|
||||
// GH#13147: Enqueue a throttled update to our window state. Throttling
|
||||
// should prevent scenarios where the Terminal window state and PTY window
|
||||
// state get de-sync'd, and cause the window to minimize/restore constantly
|
||||
// in a loop.
|
||||
if (_showHideWindowThrottler)
|
||||
{
|
||||
_showHideWindowThrottler->Run(args.ShowOrHide());
|
||||
}
|
||||
}
|
||||
|
||||
void AppHost::_SummonWindowRequested(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
@@ -1575,22 +1578,3 @@ void AppHost::_CloseRequested(const winrt::Windows::Foundation::IInspectable& /*
|
||||
const auto pos = _GetWindowLaunchPosition();
|
||||
_logic.CloseWindow(pos);
|
||||
}
|
||||
|
||||
void AppHost::_AppInitializedHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/,
|
||||
const winrt::Windows::Foundation::IInspectable& /*arg*/)
|
||||
{
|
||||
// GH#11561: We're totally done being initialized. Resize the window to
|
||||
// match the initial settings, and then call ShowWindow to finally make us
|
||||
// visible.
|
||||
|
||||
LaunchMode launchMode{};
|
||||
_initialResizeAndRepositionWindow(_window->GetHandle(), _proposedRect, launchMode);
|
||||
|
||||
auto nCmdShow = SW_SHOWDEFAULT;
|
||||
if (WI_IsFlagSet(launchMode, LaunchMode::MaximizedMode))
|
||||
{
|
||||
nCmdShow = SW_MAXIMIZE;
|
||||
}
|
||||
|
||||
ShowWindow(_window->GetHandle(), nCmdShow);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "pch.h"
|
||||
#include "NonClientIslandWindow.h"
|
||||
#include "NotificationIcon.h"
|
||||
#include <til/throttled_func.h>
|
||||
#include <ThrottledFunc.h>
|
||||
|
||||
class AppHost
|
||||
{
|
||||
@@ -31,16 +31,16 @@ private:
|
||||
|
||||
bool _shouldCreateWindow{ false };
|
||||
bool _useNonClientArea{ false };
|
||||
RECT _proposedRect{};
|
||||
|
||||
std::optional<til::throttled_func_trailing<>> _getWindowLayoutThrottler;
|
||||
std::shared_ptr<ThrottledFuncTrailing<bool>> _showHideWindowThrottler;
|
||||
winrt::Windows::Foundation::IAsyncAction _SaveWindowLayouts();
|
||||
winrt::fire_and_forget _SaveWindowLayoutsRepeat();
|
||||
|
||||
void _HandleCommandlineArgs();
|
||||
winrt::Microsoft::Terminal::Settings::Model::LaunchPosition _GetWindowLaunchPosition();
|
||||
|
||||
void _HandleCreateWindow(const HWND hwnd, RECT proposedRect);
|
||||
void _HandleCreateWindow(const HWND hwnd, RECT proposedRect, winrt::Microsoft::Terminal::Settings::Model::LaunchMode& launchMode);
|
||||
void _UpdateTitleBarContent(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Windows::UI::Xaml::UIElement& arg);
|
||||
void _UpdateTheme(const winrt::Windows::Foundation::IInspectable&,
|
||||
@@ -53,9 +53,6 @@ private:
|
||||
const winrt::Windows::Foundation::IInspectable& arg);
|
||||
void _AlwaysOnTopChanged(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Windows::Foundation::IInspectable& arg);
|
||||
void _AppInitializedHandler(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Windows::Foundation::IInspectable& arg);
|
||||
|
||||
void _RaiseVisualBell(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Windows::Foundation::IInspectable& arg);
|
||||
void _WindowMouseWheeled(const til::point coord, const int32_t delta);
|
||||
@@ -125,9 +122,6 @@ private:
|
||||
const winrt::Windows::Foundation::IInspectable& args);
|
||||
void _HideNotificationIconRequested(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Windows::Foundation::IInspectable& args);
|
||||
|
||||
void _initialResizeAndRepositionWindow(const HWND hwnd, RECT proposedRect, winrt::Microsoft::Terminal::Settings::Model::LaunchMode& launchMode);
|
||||
|
||||
std::unique_ptr<NotificationIcon> _notificationIcon;
|
||||
winrt::event_token _ReAddNotificationIconToken;
|
||||
winrt::event_token _NotificationIconPressedToken;
|
||||
@@ -154,7 +148,6 @@ private:
|
||||
winrt::TerminalApp::AppLogic::FullscreenChanged_revoker FullscreenChanged;
|
||||
winrt::TerminalApp::AppLogic::FocusModeChanged_revoker FocusModeChanged;
|
||||
winrt::TerminalApp::AppLogic::AlwaysOnTopChanged_revoker AlwaysOnTopChanged;
|
||||
winrt::TerminalApp::AppLogic::Initialized_revoker Initialized;
|
||||
winrt::TerminalApp::AppLogic::RaiseVisualBell_revoker RaiseVisualBell;
|
||||
winrt::TerminalApp::AppLogic::SystemMenuChangeRequested_revoker SystemMenuChangeRequested;
|
||||
winrt::TerminalApp::AppLogic::ChangeMaximizeRequested_revoker ChangeMaximizeRequested;
|
||||
|
||||
@@ -112,7 +112,7 @@ void IslandWindow::Close()
|
||||
// window.
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void IslandWindow::SetCreateCallback(std::function<void(const HWND, const RECT)> pfn) noexcept
|
||||
void IslandWindow::SetCreateCallback(std::function<void(const HWND, const RECT, LaunchMode& launchMode)> pfn) noexcept
|
||||
{
|
||||
_pfnCreateCallback = pfn;
|
||||
}
|
||||
@@ -154,13 +154,19 @@ void IslandWindow::_HandleCreateWindow(const WPARAM, const LPARAM lParam) noexce
|
||||
rc.right = rc.left + pcs->cx;
|
||||
rc.bottom = rc.top + pcs->cy;
|
||||
|
||||
auto launchMode = LaunchMode::DefaultMode;
|
||||
if (_pfnCreateCallback)
|
||||
{
|
||||
_pfnCreateCallback(_window.get(), rc);
|
||||
_pfnCreateCallback(_window.get(), rc, launchMode);
|
||||
}
|
||||
|
||||
// GH#11561: DO NOT call ShowWindow here. The AppHost will call ShowWindow
|
||||
// once the app has completed its initialization.
|
||||
auto nCmdShow = SW_SHOW;
|
||||
if (WI_IsFlagSet(launchMode, LaunchMode::MaximizedMode))
|
||||
{
|
||||
nCmdShow = SW_MAXIMIZE;
|
||||
}
|
||||
|
||||
ShowWindow(_window.get(), nCmdShow);
|
||||
|
||||
UpdateWindow(_window.get());
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ public:
|
||||
|
||||
virtual void Initialize();
|
||||
|
||||
void SetCreateCallback(std::function<void(const HWND, const RECT)> pfn) noexcept;
|
||||
void SetCreateCallback(std::function<void(const HWND, const RECT, winrt::Microsoft::Terminal::Settings::Model::LaunchMode& launchMode)> pfn) noexcept;
|
||||
void SetSnapDimensionCallback(std::function<float(bool widthOrHeight, float dimension)> pfn) noexcept;
|
||||
|
||||
void FocusModeChanged(const bool focusMode);
|
||||
@@ -94,7 +94,7 @@ protected:
|
||||
winrt::Windows::UI::Xaml::Controls::Grid _rootGrid;
|
||||
wil::com_ptr<ITaskbarList3> _taskbar;
|
||||
|
||||
std::function<void(const HWND, const RECT)> _pfnCreateCallback;
|
||||
std::function<void(const HWND, const RECT, winrt::Microsoft::Terminal::Settings::Model::LaunchMode& launchMode)> _pfnCreateCallback;
|
||||
std::function<float(bool, float)> _pfnSnapDimensionCallback;
|
||||
|
||||
void _HandleCreateWindow(const WPARAM wParam, const LPARAM lParam) noexcept;
|
||||
|
||||
@@ -155,13 +155,13 @@ namespace WindowsTerminal.UIA.Tests
|
||||
{
|
||||
var root = app.GetRoot();
|
||||
|
||||
root.SendKeys(Keys.LeftAlt + Keys.LeftShift + "T");
|
||||
root.SendKeys(Keys.LeftControl + Keys.LeftShift + "T");
|
||||
Globals.WaitForTimeout();
|
||||
root.SendKeys(Keys.LeftAlt + Keys.LeftShift + "T");
|
||||
root.SendKeys(Keys.LeftControl + Keys.LeftShift + "T");
|
||||
Globals.WaitForTimeout();
|
||||
root.SendKeys(Keys.LeftAlt + Keys.LeftShift + "T");
|
||||
root.SendKeys(Keys.LeftControl + Keys.LeftShift + "T");
|
||||
Globals.WaitForTimeout();
|
||||
root.SendKeys(Keys.LeftAlt + Keys.LeftShift + "T");
|
||||
root.SendKeys(Keys.LeftControl + Keys.LeftShift + "T");
|
||||
Globals.WaitForTimeout();
|
||||
root.SendKeys(Keys.LeftControl + Keys.LeftShift + "W");
|
||||
Globals.WaitForTimeout();
|
||||
|
||||
@@ -75,11 +75,20 @@ void PtySignalInputThread::ConnectConsole() noexcept
|
||||
_DoShowHide(_initialShowHide->show);
|
||||
}
|
||||
|
||||
// If we were given a owner HWND, then manually start the pseudo window now.
|
||||
if (_earlyReparent)
|
||||
{
|
||||
_DoSetWindowParent(*_earlyReparent);
|
||||
}
|
||||
// We should have successfully used the _earlyReparent message in CreatePseudoWindow.
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Create our pseudo window. We're doing this here, instead of in
|
||||
// ConnectConsole, because the window is created in
|
||||
// ConsoleInputThreadProcWin32, before ConnectConsole is first called. Doing
|
||||
// this here ensures that the window is first created with the initial owner
|
||||
// set up (if so specified).
|
||||
// - Refer to GH#13066 for details.
|
||||
void PtySignalInputThread::CreatePseudoWindow()
|
||||
{
|
||||
HWND owner = _earlyReparent.has_value() ? reinterpret_cast<HWND>((*_earlyReparent).handle) : HWND_DESKTOP;
|
||||
ServiceLocator::LocatePseudoWindow(owner);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
@@ -227,15 +236,28 @@ void PtySignalInputThread::_DoShowHide(const bool show)
|
||||
// - <none>
|
||||
void PtySignalInputThread::_DoSetWindowParent(const SetParentData& data)
|
||||
{
|
||||
const auto owner{ reinterpret_cast<HWND>(data.handle) };
|
||||
// This will initialize s_interactivityFactory for us. It will also
|
||||
// conveniently return 0 when we're on OneCore.
|
||||
//
|
||||
// If the window hasn't been created yet, by some other call to
|
||||
// LocatePseudoWindow, then this will also initialize the owner of the
|
||||
// window.
|
||||
if (const auto pseudoHwnd{ ServiceLocator::LocatePseudoWindow(reinterpret_cast<HWND>(data.handle)) })
|
||||
if (const auto pseudoHwnd{ ServiceLocator::LocatePseudoWindow(owner) })
|
||||
{
|
||||
LOG_LAST_ERROR_IF_NULL(::SetParent(pseudoHwnd, reinterpret_cast<HWND>(data.handle)));
|
||||
// DO NOT USE SetParent HERE!
|
||||
//
|
||||
// Calling SetParent on a window that is WS_VISIBLE will cause the OS to
|
||||
// hide the window, make it a _child_ window, then call SW_SHOW on the
|
||||
// window to re-show it. SW_SHOW, however, will cause the OS to also set
|
||||
// that window as the _foreground_ window, which would result in the
|
||||
// pty's hwnd stealing the foreground away from the owning terminal
|
||||
// window. That's bad.
|
||||
//
|
||||
// SetWindowLongPtr seems to do the job of changing who the window owner
|
||||
// is, without all the other side effects of reparenting the window.
|
||||
// See #13066
|
||||
::SetWindowLongPtr(pseudoHwnd, GWLP_HWNDPARENT, reinterpret_cast<LONG_PTR>(owner));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ namespace Microsoft::Console
|
||||
PtySignalInputThread& operator=(const PtySignalInputThread&) = delete;
|
||||
|
||||
void ConnectConsole() noexcept;
|
||||
void CreatePseudoWindow();
|
||||
|
||||
private:
|
||||
enum class PtySignal : unsigned short
|
||||
|
||||
@@ -300,18 +300,34 @@ bool VtIo::IsUsingVt() const
|
||||
|
||||
if (_pPtySignalInputThread)
|
||||
{
|
||||
// IMPORTANT! Start the pseudo window on this thread. This thread has a
|
||||
// message pump. If you DON'T, then a DPI change in the owning hwnd will
|
||||
// cause us to get a dpi change as well, which we'll never deque and
|
||||
// handle, effectively HANGING THE OWNER HWND.
|
||||
// Let the signal thread know that the console is connected.
|
||||
//
|
||||
// Let the signal thread know that the console is connected
|
||||
// By this point, the pseudo window should have already been created, by
|
||||
// ConsoleInputThreadProcWin32. That thread has a message pump, which is
|
||||
// needed to ensure that DPI change messages to the owning terminal
|
||||
// window don't end up hanging because the pty didn't also process it.
|
||||
_pPtySignalInputThread->ConnectConsole();
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Create our pseudo window. This is exclusively called by
|
||||
// ConsoleInputThreadProcWin32 on the console input thread.
|
||||
// * It needs to be called on that thread, before any other calls to
|
||||
// LocatePseudoWindow, to make sure that the input thread is the HWND's
|
||||
// message thread.
|
||||
// * It needs to be plumbed through the signal thread, because the signal
|
||||
// thread knows if someone should be marked as the window's owner. It's
|
||||
// VERY IMPORTANT that any initial owners are set up when the window is
|
||||
// first created.
|
||||
// - Refer to GH#13066 for details.
|
||||
void VtIo::CreatePseudoWindow()
|
||||
{
|
||||
_pPtySignalInputThread->CreatePseudoWindow();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Create and start the signal thread. The signal thread can be created
|
||||
// independent of the i/o threads, and doesn't require a client first
|
||||
|
||||
@@ -52,6 +52,8 @@ namespace Microsoft::Console::VirtualTerminal
|
||||
|
||||
[[nodiscard]] HRESULT ManuallyClearScrollback() const noexcept;
|
||||
|
||||
void CreatePseudoWindow();
|
||||
|
||||
private:
|
||||
// After CreateIoHandlers is called, these will be invalid.
|
||||
wil::unique_hfile _hInput;
|
||||
|
||||
@@ -719,6 +719,10 @@ void ApiRoutines::GetLargestConsoleWindowSizeImpl(const SCREEN_INFORMATION& cont
|
||||
position.Y < 0));
|
||||
// clang-format on
|
||||
|
||||
// MSFT: 15813316 - Try to use this SetCursorPosition call to inherit the cursor position.
|
||||
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||
RETURN_IF_FAILED(gci.GetVtIo()->SetCursorPosition(position));
|
||||
|
||||
RETURN_IF_NTSTATUS_FAILED(buffer.SetCursorPosition(position, true));
|
||||
|
||||
LOG_IF_FAILED(ConsoleImeResizeCompStrView());
|
||||
|
||||
@@ -285,7 +285,7 @@ void ConhostInternalGetSet::ShowWindow(bool showOrHide)
|
||||
{
|
||||
const auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||
const auto hwnd = gci.IsInVtIoMode() ? ServiceLocator::LocatePseudoWindow() : ServiceLocator::LocateConsoleWindow()->GetWindowHandle();
|
||||
::ShowWindow(hwnd, showOrHide ? SW_NORMAL : SW_MINIMIZE);
|
||||
::ShowWindow(hwnd, showOrHide ? SW_SHOWNOACTIVATE : SW_MINIMIZE);
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
|
||||
@@ -1453,6 +1453,8 @@ bool SCREEN_INFORMATION::IsMaximizedY() const
|
||||
|
||||
// Save cursor's relative height versus the viewport
|
||||
const auto sCursorHeightInViewportBefore = _textBuffer->GetCursor().GetPosition().Y - _viewport.Top();
|
||||
// Also save the distance to the virtual bottom so it can be restored after the resize
|
||||
const auto cursorDistanceFromBottom = _virtualBottom - _textBuffer->GetCursor().GetPosition().Y;
|
||||
|
||||
// skip any drawing updates that might occur until we swap _textBuffer with the new buffer or we exit early.
|
||||
newTextBuffer->GetCursor().StartDeferDrawing();
|
||||
@@ -1464,14 +1466,20 @@ bool SCREEN_INFORMATION::IsMaximizedY() const
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
// Make sure the new virtual bottom is far enough down to include both
|
||||
// the cursor row and the last non-space row. It also shouldn't be less
|
||||
// than the height of the viewport, otherwise the top of the virtual
|
||||
// viewport would end up negative.
|
||||
// Since the reflow doesn't preserve the virtual bottom, we try and
|
||||
// estimate where it ought to be by making it the same distance from
|
||||
// the cursor row as it was before the resize. However, we also need
|
||||
// to make sure it is far enough down to include the last non-space
|
||||
// row, and it shouldn't be less than the height of the viewport,
|
||||
// otherwise the top of the virtual viewport would end up negative.
|
||||
const auto cursorRow = newTextBuffer->GetCursor().GetPosition().Y;
|
||||
const auto lastNonSpaceRow = newTextBuffer->GetLastNonSpaceCharacter().Y;
|
||||
const auto estimatedBottom = gsl::narrow_cast<short>(cursorRow + cursorDistanceFromBottom);
|
||||
const auto viewportBottom = gsl::narrow_cast<short>(_viewport.Height() - 1);
|
||||
_virtualBottom = std::max({ cursorRow, lastNonSpaceRow, viewportBottom });
|
||||
_virtualBottom = std::max({ lastNonSpaceRow, estimatedBottom, viewportBottom });
|
||||
|
||||
// We can't let it extend past the bottom of the buffer either.
|
||||
_virtualBottom = std::min(_virtualBottom, newTextBuffer->GetSize().BottomInclusive());
|
||||
|
||||
// Adjust the viewport so the cursor doesn't wildly fly off up or down.
|
||||
const auto sCursorHeightInViewportAfter = cursorRow - _viewport.Top();
|
||||
|
||||
@@ -6291,6 +6291,18 @@ void ScreenBufferTests::UpdateVirtualBottomAfterResizeWithReflow()
|
||||
Log::Comment(L"Confirm that the virtual viewport includes the last non-space row");
|
||||
const auto lastNonSpaceRow = si.GetTextBuffer().GetLastNonSpaceCharacter().Y;
|
||||
VERIFY_IS_GREATER_THAN_OR_EQUAL(si._virtualBottom, lastNonSpaceRow);
|
||||
|
||||
Log::Comment(L"Clear the screen and note the cursor distance to the virtual bottom");
|
||||
stateMachine.ProcessString(L"\033[H\033[2J");
|
||||
const auto cursorDistanceFromBottom = si._virtualBottom - si.GetTextBuffer().GetCursor().GetPosition().Y;
|
||||
VERIFY_ARE_EQUAL(si.GetViewport().Height() - 1, cursorDistanceFromBottom);
|
||||
|
||||
Log::Comment(L"Stretch the viewport back to full width");
|
||||
bufferSize.X *= 2;
|
||||
VERIFY_NT_SUCCESS(si.ResizeWithReflow(bufferSize));
|
||||
|
||||
Log::Comment(L"Confirm cursor distance to the virtual bottom is unchanged");
|
||||
VERIFY_ARE_EQUAL(cursorDistanceFromBottom, si._virtualBottom - si.GetTextBuffer().GetCursor().GetPosition().Y);
|
||||
}
|
||||
|
||||
void ScreenBufferTests::DontShrinkVirtualBottomDuringResizeWithReflowAtTop()
|
||||
|
||||
@@ -320,8 +320,14 @@ using namespace Microsoft::Console::Interactivity;
|
||||
// as far as the difference between parent/child and owner/owned
|
||||
// windows). Evan K said we should do it this way, and he
|
||||
// definitely knows.
|
||||
const auto windowStyle = WS_OVERLAPPEDWINDOW;
|
||||
const auto exStyles = WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT | WS_EX_LAYERED;
|
||||
//
|
||||
// GH#13066: Load-bearing: Make sure to set WS_POPUP. If you
|
||||
// don't, then GetAncestor(GetConsoleWindow(), GA_ROOTOWNER)
|
||||
// will return the console handle again, not the owning
|
||||
// terminal's handle. It's not entirely clear why, but WS_POPUP
|
||||
// is absolutely vital for this to work correctly.
|
||||
const auto windowStyle = WS_OVERLAPPEDWINDOW | WS_POPUP;
|
||||
const auto exStyles = WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT | WS_EX_LAYERED | WS_EX_NOACTIVATE;
|
||||
|
||||
// Attempt to create window.
|
||||
hwnd = CreateWindowExW(exStyles,
|
||||
@@ -335,7 +341,7 @@ using namespace Microsoft::Console::Interactivity;
|
||||
owner,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr);
|
||||
this);
|
||||
|
||||
if (hwnd == nullptr)
|
||||
{
|
||||
@@ -472,7 +478,18 @@ void InteractivityFactory::SetPseudoWindowCallback(std::function<void(bool)> fun
|
||||
// - <none>
|
||||
void InteractivityFactory::_WritePseudoWindowCallback(bool showOrHide)
|
||||
{
|
||||
if (_pseudoWindowMessageCallback)
|
||||
// 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.
|
||||
//
|
||||
// Should we need to restore this functionality in the future, we should
|
||||
// only do so with great caution.
|
||||
if (_pseudoWindowMessageCallback && showOrHide == false)
|
||||
{
|
||||
_pseudoWindowMessageCallback(showOrHide);
|
||||
}
|
||||
|
||||
@@ -1036,9 +1036,18 @@ DWORD WINAPI ConsoleInputThreadProcWin32(LPVOID /*lpParameter*/)
|
||||
// If we are headless (because we're a pseudo console), we
|
||||
// will still need a window handle in the win32 environment
|
||||
// in case anyone sends messages at that HWND (vim.exe is an example.)
|
||||
// We have to CreateWindow on the same thread that will pump the messages
|
||||
// which is this thread.
|
||||
ServiceLocator::LocatePseudoWindow();
|
||||
//
|
||||
// IMPORTANT! We have to CreateWindow on the same thread that will pump
|
||||
// the messages, which is this thread. If you DON'T, then a DPI change
|
||||
// in the owning hwnd will cause us to get a dpi change as well, which
|
||||
// we'll never deque and handle, effectively HANGING THE OWNER HWND.
|
||||
// ServiceLocator::LocatePseudoWindow();
|
||||
//
|
||||
// Instead of just calling LocatePseudoWindow, make sure to go through
|
||||
// VtIo's CreatePseudoWindow, which will make sure that the window is
|
||||
// successfully created with the owner configured when the window is
|
||||
// first created. See GH#13066 for details.
|
||||
ServiceLocator::LocateGlobals().getConsoleInformation().GetVtIo()->CreatePseudoWindow();
|
||||
}
|
||||
|
||||
UnlockConsole();
|
||||
|
||||
@@ -174,9 +174,15 @@ constexpr HRESULT vec2_narrow(U x, U y, AtlasEngine::vec2<T>& out) noexcept
|
||||
|
||||
[[nodiscard]] HRESULT AtlasEngine::UpdateViewport(const SMALL_RECT srNewViewport) noexcept
|
||||
{
|
||||
_api.cellCount.x = gsl::narrow_cast<u16>(srNewViewport.Right - srNewViewport.Left + 1);
|
||||
_api.cellCount.y = gsl::narrow_cast<u16>(srNewViewport.Bottom - srNewViewport.Top + 1);
|
||||
WI_SetFlag(_api.invalidations, ApiInvalidations::Size);
|
||||
const u16x2 cellCount{
|
||||
gsl::narrow_cast<u16>(srNewViewport.Right - srNewViewport.Left + 1),
|
||||
gsl::narrow_cast<u16>(srNewViewport.Bottom - srNewViewport.Top + 1),
|
||||
};
|
||||
if (_api.cellCount != cellCount)
|
||||
{
|
||||
_api.cellCount = cellCount;
|
||||
WI_SetFlag(_api.invalidations, ApiInvalidations::Size);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -150,15 +150,10 @@ bool InteractDispatch::MoveCursor(const VTInt row, const VTInt col)
|
||||
|
||||
const auto coordCursorShort = til::unwrap_coord(coordCursor);
|
||||
|
||||
// MSFT: 15813316 - Try to use this MoveCursor call to inherit the cursor position.
|
||||
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||
RETURN_IF_FAILED(gci.GetVtIo()->SetCursorPosition(coordCursorShort));
|
||||
|
||||
// Finally, attempt to set the adjusted cursor position back into the console.
|
||||
auto& cursor = _api.GetTextBuffer().GetCursor();
|
||||
cursor.SetPosition(coordCursorShort);
|
||||
cursor.SetHasMoved(true);
|
||||
return true;
|
||||
const auto api = gsl::not_null{ ServiceLocator::LocateGlobals().api };
|
||||
auto& info = ServiceLocator::LocateGlobals().getConsoleInformation().GetActiveOutputBuffer();
|
||||
return SUCCEEDED(api->SetConsoleCursorPositionImpl(info, coordCursorShort));
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
@@ -204,11 +199,19 @@ bool InteractDispatch::FocusChanged(const bool focused) const
|
||||
{
|
||||
// They want focus, we found a pseudo hwnd.
|
||||
|
||||
// Note: ::GetParent(pseudoHwnd) will return 0. GetAncestor works though.
|
||||
// GA_PARENT and GA_ROOT seemingly return the same thing for
|
||||
// Terminal. We're going with GA_ROOT since it seems
|
||||
// semantically more correct here.
|
||||
if (const auto ownerHwnd{ ::GetAncestor(pseudoHwnd, GA_ROOT) })
|
||||
// BODGY
|
||||
//
|
||||
// This needs to be GA_ROOTOWNER here. Not GA_ROOT, GA_PARENT,
|
||||
// or GetParent. The ConPTY hwnd is an owned, top-level, popup,
|
||||
// non-parented window. It does not have a parent set. It does
|
||||
// have an owner set. It is not a WS_CHILD window. This
|
||||
// combination of things allows us to find the owning window
|
||||
// with GA_ROOTOWNER. GA_ROOT will get us ourselves, and
|
||||
// GA_PARENT will return the desktop HWND.
|
||||
//
|
||||
// See GH#13066
|
||||
|
||||
if (const auto ownerHwnd{ ::GetAncestor(pseudoHwnd, GA_ROOTOWNER) })
|
||||
{
|
||||
// We have an owner from a previous call to ReparentWindow
|
||||
|
||||
|
||||
Reference in New Issue
Block a user