Merge remote-tracking branch 'origin/main' into dev/migrie/f/653-QUAKE-MODE

This commit is contained in:
Mike Griese 2021-04-14 16:03:21 -05:00
commit 784ec731f8
88 changed files with 489 additions and 301 deletions

View file

@ -6,15 +6,19 @@ bitfields
CLASSNOTAVAILABLE
cmdletbinding
COLORPROPERTY
COMDLG
CXICON
CYICON
D2DERR_SHADER_COMPILE_FAILED
dataobject
DERR
dlldata
DONTADDTORECENT
environstrings
EXPCMDFLAGS
EXPCMDSTATE
FILTERSPEC
FORCEFILESYSTEM
FORCEMINIMIZE
frac
fullkbd
@ -24,6 +28,7 @@ GETHIGHCONTRAST
Hashtable
HIGHCONTRASTON
HIGHCONTRASTW
hotkeys
href
IActivation
IApp
@ -32,12 +37,13 @@ IAsync
IBind
IBox
IClass
IConnection
IComparable
IConnection
ICustom
IDialog
IDirect
IExplorer
IFile
IInheritable
IMap
IObject
@ -63,6 +69,7 @@ NCLBUTTONDBLCLK
NCRBUTTONDBLCLK
NOAGGREGATION
NOASYNC
NOCHANGEDIR
NOPROGRESS
NOREDIRECTIONBITMAP
ntprivapi
@ -72,10 +79,11 @@ otms
OUTLINETEXTMETRICW
overridable
PAGESCROLL
PICKFOLDERS
pmr
REGCLS
RETURNCMD
REGCLS
RETURNCMD
rfind
roundf
RSHIFT

View file

@ -2397,6 +2397,7 @@ titlebar
TITLEISLINKNAME
TJson
tl
TLambda
TLEN
Tlg
Tlgdata

View file

@ -5,7 +5,7 @@
<XesUseOneStoreVersioning>true</XesUseOneStoreVersioning>
<XesBaseYearForStoreVersion>2021</XesBaseYearForStoreVersion>
<VersionMajor>1</VersionMajor>
<VersionMinor>8</VersionMinor>
<VersionMinor>9</VersionMinor>
<VersionInfoProductName>Windows Terminal</VersionInfoProductName>
</PropertyGroup>
</Project>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

View file

@ -281,9 +281,9 @@ bool TextBuffer::_AssertValidDoubleByteSequence(const DbcsAttribute dbcsAttribut
// - false otherwise (out of memory)
bool TextBuffer::_PrepareForDoubleByteSequence(const DbcsAttribute dbcsAttribute)
{
// Assert the buffer state is ready for this character
// This function corrects most errors. If this is false, we had an uncorrectable one.
FAIL_FAST_IF(!(_AssertValidDoubleByteSequence(dbcsAttribute))); // Shouldn't be uncorrectable sequences unless something is very wrong.
// This function corrects most errors. If this is false, we had an uncorrectable one which
// older versions of conhost simply let pass by unflinching.
LOG_HR_IF(E_NOT_VALID_STATE, !(_AssertValidDoubleByteSequence(dbcsAttribute))); // Shouldn't be uncorrectable sequences unless something is very wrong.
bool fSuccess = true;
// Now compensate if we don't have enough space for the upcoming double byte sequence

View file

@ -54,7 +54,6 @@
<uap:ShowOn Tile="square310x310Logo"/>
</uap:ShowNameOnTiles>
</uap:DefaultTile>
<uap:SplashScreen Image="Images\SplashScreen.png"/>
</uap:VisualElements>
<Extensions>

View file

@ -55,7 +55,6 @@
<uap:ShowOn Tile="square310x310Logo"/>
</uap:ShowNameOnTiles>
</uap:DefaultTile>
<uap:SplashScreen Image="Images\SplashScreen.png"/>
</uap:VisualElements>
<Extensions>

View file

@ -55,7 +55,6 @@
<uap:ShowOn Tile="square310x310Logo"/>
</uap:ShowNameOnTiles>
</uap:DefaultTile>
<uap:SplashScreen Image="Images\SplashScreen.png"/>
</uap:VisualElements>
<Extensions>

View file

@ -954,6 +954,10 @@ namespace TerminalAppLocalTests
void TabTests::TestWindowRenameSuccessful()
{
BEGIN_TEST_METHOD_PROPERTIES()
TEST_METHOD_PROPERTY(L"IsolationLevel", L"Method")
END_TEST_METHOD_PROPERTIES()
auto page = _commonSetup();
page->RenameWindowRequested([&page](auto&&, const winrt::TerminalApp::RenameWindowRequestedArgs args) {
// In the real terminal, this would bounce up to the monarch and
@ -980,6 +984,10 @@ namespace TerminalAppLocalTests
}
void TabTests::TestWindowRenameFailure()
{
BEGIN_TEST_METHOD_PROPERTIES()
TEST_METHOD_PROPERTY(L"IsolationLevel", L"Method")
END_TEST_METHOD_PROPERTIES()
auto page = _commonSetup();
page->RenameWindowRequested([&page](auto&&, auto&&) {
// In the real terminal, this would bounce up to the monarch and

View file

@ -252,8 +252,8 @@ namespace winrt::TerminalApp::implementation
{
if (const auto& realArgs = args.ActionArgs().try_as<SwitchToTabArgs>())
{
const auto handled = _SelectTab({ realArgs.TabIndex() });
args.Handled(handled);
_SelectTab({ realArgs.TabIndex() });
args.Handled(true);
}
}
@ -719,9 +719,9 @@ namespace winrt::TerminalApp::implementation
const auto newName = realArgs.Name();
const auto request = winrt::make_self<implementation::RenameWindowRequestedArgs>(newName);
_RenameWindowRequestedHandlers(*this, *request);
args.Handled(true);
}
}
args.Handled(false);
}
void TerminalPage::_HandleOpenWindowRenamer(const IInspectable& /*sender*/,

View file

@ -43,6 +43,9 @@
Color="#f1707a" />
<SolidColorBrush x:Key="CloseButtonStrokePressed"
Color="Black" />
<SolidColorBrush x:Key="CloseButtonBackground"
Color="#00e81123" />
<Color x:Key="CloseButtonBackgroundColor">#00e81123</Color>
</ResourceDictionary>
<ResourceDictionary x:Key="Dark">
<x:Double x:Key="CaptionButtonStrokeWidth">1.0</x:Double>
@ -69,6 +72,9 @@
Color="#f1707a" />
<SolidColorBrush x:Key="CloseButtonStrokePressed"
Color="Black" />
<SolidColorBrush x:Key="CloseButtonBackground"
Color="#00e81123" />
<Color x:Key="CloseButtonBackgroundColor">#00e81123</Color>
</ResourceDictionary>
<ResourceDictionary x:Key="HighContrast">
<x:Double x:Key="CaptionButtonStrokeWidth">3.0</x:Double>
@ -268,6 +274,10 @@
ResourceKey="CloseButtonStrokePointerOver" />
<StaticResource x:Key="CaptionButtonStrokePressed"
ResourceKey="CloseButtonStrokePressed" />
<StaticResource x:Key="CaptionButtonBackground"
ResourceKey="CloseButtonBackground" />
<StaticResource x:Key="CaptionButtonBackgroundColor"
ResourceKey="CloseButtonBackgroundColor" />
</ResourceDictionary>
<ResourceDictionary x:Key="Dark">
<StaticResource x:Key="CaptionButtonBackgroundPointerOver"
@ -278,6 +288,10 @@
ResourceKey="CloseButtonStrokePointerOver" />
<StaticResource x:Key="CaptionButtonStrokePressed"
ResourceKey="CloseButtonStrokePressed" />
<StaticResource x:Key="CaptionButtonBackground"
ResourceKey="CloseButtonBackground" />
<StaticResource x:Key="CaptionButtonBackgroundColor"
ResourceKey="CloseButtonBackgroundColor" />
</ResourceDictionary>
<ResourceDictionary x:Key="HighContrast">
<StaticResource x:Key="CaptionButtonBackgroundPointerOver"

View file

@ -2708,8 +2708,12 @@ namespace winrt::TerminalApp::implementation
void TerminalPage::_RequestWindowRename(const winrt::hstring& newName)
{
auto request = winrt::make<implementation::RenameWindowRequestedArgs>(newName);
// The WindowRenamer is _not_ a Toast - we want it to stay open until the user dismisses it.
WindowRenamer().IsOpen(false);
// The WindowRenamer is _not_ a Toast - we want it to stay open until
// the user dismisses it.
if (WindowRenamer())
{
WindowRenamer().IsOpen(false);
}
_RenameWindowRequestedHandlers(*this, request);
// We can't just use request.Successful here, because the handler might
// (will) be handling this asynchronously, so when control returns to

View file

@ -666,6 +666,11 @@ namespace winrt::TerminalApp::implementation
_RecalculateAndApplyReadOnly();
if (const auto control{ pane->GetTerminalControl() })
{
control.TaskbarProgressChanged();
}
// Raise our own ActivePaneChanged event.
_ActivePaneChangedHandlers();
}

View file

@ -132,6 +132,8 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
THROW_LAST_ERROR_IF_NULL(_hOutputThread);
LOG_IF_FAILED(SetThreadDescription(_hOutputThread.get(), L"AzureConnection Output Thread"));
_transitionToState(ConnectionState::Connecting);
}

View file

@ -278,6 +278,8 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
THROW_LAST_ERROR_IF_NULL(_hOutputThread);
LOG_IF_FAILED(SetThreadDescription(_hOutputThread.get(), L"ConptyConnection Output Thread"));
_clientExitWait.reset(CreateThreadpoolWait(
[](PTP_CALLBACK_INSTANCE /*callbackInstance*/, PVOID context, PTP_WAIT /*wait*/, TP_WAIT_RESULT /*waitResult*/) noexcept {
ConptyConnection* const pInstance = static_cast<ConptyConnection*>(context);

View file

@ -39,6 +39,9 @@ constexpr const auto TsfRedrawInterval = std::chrono::milliseconds(100);
// The minimum delay between updating the locations of regex patterns
constexpr const auto UpdatePatternLocationsInterval = std::chrono::milliseconds(500);
// The minimum delay between emitting warning bells
constexpr const auto TerminalWarningBellInterval = std::chrono::milliseconds(1000);
DEFINE_ENUM_FLAG_OPERATORS(winrt::Microsoft::Terminal::Control::CopyFormat);
namespace winrt::Microsoft::Terminal::Control::implementation
@ -91,7 +94,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// GH#8969: pre-seed working directory to prevent potential races
_terminal->SetWorkingDirectory(_settings.StartingDirectory());
auto pfnWarningBell = std::bind(&TermControl::_TerminalWarningBell, this);
auto pfnWarningBell = [this]() {
_playWarningBell->Run();
};
_terminal->SetWarningBellCallback(pfnWarningBell);
auto pfnTitleChanged = std::bind(&TermControl::_TerminalTitleChanged, this, std::placeholders::_1);
@ -167,6 +172,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation
UpdatePatternLocationsInterval,
Dispatcher());
_playWarningBell = std::make_shared<ThrottledFunc<>>(
[weakThis = get_weak()]() {
if (auto control{ weakThis.get() })
{
control->_TerminalWarningBell();
}
},
TerminalWarningBellInterval,
Dispatcher());
_updateScrollBar = std::make_shared<ThrottledFunc<ScrollBarUpdate>>(
[weakThis = get_weak()](const auto& update) {
if (auto control{ weakThis.get() })
@ -306,13 +321,17 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// terminal.
co_await winrt::resume_foreground(Dispatcher());
_UpdateSettingsFromUIThread(_settings);
// Take the lock before calling the helper functions to update the settings and appearance
auto lock = _terminal->LockForWriting();
_UpdateSettingsFromUIThreadUnderLock(_settings);
auto appearance = _settings.try_as<IControlAppearance>();
if (!_focused && _UnfocusedAppearance)
{
appearance = _UnfocusedAppearance;
}
_UpdateAppearanceFromUIThread(appearance);
_UpdateAppearanceFromUIThreadUnderLock(appearance);
}
// Method Description:
@ -323,7 +342,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
// Dispatch a call to the UI thread
co_await winrt::resume_foreground(Dispatcher());
_UpdateAppearanceFromUIThread(newAppearance);
// Take the lock before calling the helper function to update the appearance
auto lock = _terminal->LockForWriting();
_UpdateAppearanceFromUIThreadUnderLock(newAppearance);
}
// Method Description:
@ -366,17 +388,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// issue that causes one of our hstring -> wstring_view conversions to result in garbage,
// but only from a coroutine context. See GH#8723.
// - INVARIANT: This method must be called from the UI thread.
// - INVARIANT: This method can only be called if the caller has the writing lock on the terminal.
// Arguments:
// - newSettings: the new settings to set
void TermControl::_UpdateSettingsFromUIThread(IControlSettings newSettings)
void TermControl::_UpdateSettingsFromUIThreadUnderLock(IControlSettings newSettings)
{
if (_closing)
{
return;
}
auto lock = _terminal->LockForWriting();
// Update our control settings
_ApplyUISettings(_settings);
@ -420,10 +441,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// Method Description:
// - Updates the appearance
// - This should only be called from the UI thread
// - INVARIANT: This method must be called from the UI thread.
// - INVARIANT: This method can only be called if the caller has the writing lock on the terminal.
// Arguments:
// - newAppearance: the new appearance to set
void TermControl::_UpdateAppearanceFromUIThread(IControlAppearance newAppearance)
void TermControl::_UpdateAppearanceFromUIThreadUnderLock(IControlAppearance newAppearance)
{
if (_closing)
{
@ -472,14 +494,16 @@ namespace winrt::Microsoft::Terminal::Control::implementation
TSFInputControl().Foreground(foregroundBrush);
// Update the terminal core with its new Core settings
auto lock = _terminal->LockForWriting();
_terminal->UpdateAppearance(newAppearance);
// Update DxEngine settings under the lock
_renderEngine->SetSelectionBackground(til::color{ newAppearance.SelectionBackground() });
_renderEngine->SetRetroTerminalEffect(newAppearance.RetroTerminalEffect());
_renderEngine->SetPixelShaderPath(newAppearance.PixelShaderPath());
_renderer->TriggerRedrawAll();
if (_renderEngine)
{
// Update DxEngine settings under the lock
_renderEngine->SetSelectionBackground(til::color{ newAppearance.SelectionBackground() });
_renderEngine->SetRetroTerminalEffect(newAppearance.RetroTerminalEffect());
_renderEngine->SetPixelShaderPath(newAppearance.PixelShaderPath());
_renderer->TriggerRedrawAll();
}
}
// Method Description:
@ -800,9 +824,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
const auto viewInPixels = Viewport::FromDimensions({ 0, 0 }, windowSize);
LOG_IF_FAILED(dxEngine->SetWindowSize({ viewInPixels.Width(), viewInPixels.Height() }));
// Update DxEngine's SelectionBackground
dxEngine->SetSelectionBackground(til::color{ _settings.SelectionBackground() });
const auto vp = dxEngine->GetViewportInCharacters(viewInPixels);
const auto width = vp.Width();
const auto height = vp.Height();
@ -820,8 +841,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// the first paint will be ignored!
dxEngine->SetWarningCallback(std::bind(&TermControl::_RendererWarning, this, std::placeholders::_1));
dxEngine->SetRetroTerminalEffect(_settings.RetroTerminalEffect());
dxEngine->SetPixelShaderPath(_settings.PixelShaderPath());
dxEngine->SetForceFullRepaintRendering(_settings.ForceFullRepaintRendering());
dxEngine->SetSoftwareRendering(_settings.SoftwareRendering());
@ -910,6 +929,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// becomes a no-op.
this->Focus(FocusState::Programmatic);
// Now that the renderer is set up, update the appearance for initialization
_UpdateAppearanceFromUIThreadUnderLock(_settings);
_initializedTerminal = true;
} // scope for TerminalLock
@ -1418,6 +1440,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_selectionNeedsToBeCopied = true;
}
if (_terminal->IsSelectionActive())
{
// GH#9787: if selection is active we don't want to track the touchdown position
// so that dragging the mouse will extend the selection rather than starting the new one
_singleClickTouchdownPos = std::nullopt;
}
_renderer->TriggerSelection();
}
else if (point.Properties().IsRightButtonPressed())

View file

@ -145,6 +145,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
std::shared_ptr<ThrottledFunc<>> _updatePatternLocations;
std::shared_ptr<ThrottledFunc<>> _playWarningBell;
struct ScrollBarUpdate
{
std::optional<double> newValue;
@ -198,8 +200,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
winrt::Windows::UI::Xaml::Controls::SwapChainPanel::LayoutUpdated_revoker _layoutUpdatedRevoker;
void _UpdateSettingsFromUIThread(IControlSettings newSettings);
void _UpdateAppearanceFromUIThread(IControlAppearance newAppearance);
void _UpdateSettingsFromUIThreadUnderLock(IControlSettings newSettings);
void _UpdateAppearanceFromUIThreadUnderLock(IControlAppearance newAppearance);
bool _isReadOnly{ false };
void _ApplyUISettings(const IControlSettings&);

View file

@ -49,8 +49,6 @@
<Grid HorizontalAlignment="Stretch"
ColumnSpacing="8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="16" />
<!-- icon -->
<ColumnDefinition Width="Auto" />
<!-- command label -->
<ColumnDefinition Width="*" />
@ -59,7 +57,7 @@
<!-- gutter for scrollbar -->
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="1"
<TextBlock Grid.Column="0"
HorizontalAlignment="Left"
Text="{x:Bind Name, Mode=OneWay}" />
@ -71,7 +69,7 @@
AutomationProperties to Raw here, unlike in the
CommandPalette. We're not quite sure why.
-->
<Border Grid.Column="2"
<Border Grid.Column="1"
Padding="2,0,2,0"
HorizontalAlignment="Right"
VerticalAlignment="Center"

View file

@ -182,6 +182,11 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
return false;
}
uint64_t MainPage::GetHostingWindow() const noexcept
{
return reinterpret_cast<uint64_t>(_hostingHwnd.value_or(nullptr));
}
// Function Description:
// - Called when the NavigationView is loaded. Navigates to the first item in the NavigationView, if no item is selected
// Arguments:

View file

@ -24,6 +24,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
void SetHostingWindow(uint64_t hostingWindow) noexcept;
bool TryPropagateHostingWindow(IInspectable object) noexcept;
uint64_t GetHostingWindow() const noexcept;
TYPED_EVENT(OpenJson, Windows::Foundation::IInspectable, Model::SettingsTarget);

View file

@ -10,6 +10,7 @@ namespace Microsoft.Terminal.Settings.Editor
interface IHostedInWindow
{
Boolean TryPropagateHostingWindow(IInspectable i);
UInt64 GetHostingWindow();
}
[default_interface] runtimeclass MainPage : Windows.UI.Xaml.Controls.Page, IHostedInWindow

View file

@ -300,6 +300,12 @@
</Reference>
</ItemGroup>
<ItemDefinitionGroup>
<Link>
<AdditionalDependencies>shell32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">

View file

@ -15,9 +15,6 @@ using namespace winrt::Windows::UI::Xaml::Data;
using namespace winrt::Windows::UI::Xaml::Navigation;
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Foundation::Collections;
using namespace winrt::Windows::Storage;
using namespace winrt::Windows::Storage::AccessCache;
using namespace winrt::Windows::Storage::Pickers;
using namespace winrt::Microsoft::Terminal::Settings::Model;
static const std::array<winrt::guid, 2> InBoxProfileGuids{
@ -25,6 +22,64 @@ static const std::array<winrt::guid, 2> InBoxProfileGuids{
winrt::guid{ 0x0caa0dad, 0x35be, 0x5f56, { 0xa8, 0xff, 0xaf, 0xce, 0xee, 0xaa, 0x61, 0x01 } } // Command Prompt
};
// Function Description:
// - This function presents a File Open "common dialog" and returns its selected file asynchronously.
// Parameters:
// - customize: A lambda that receives an IFileDialog* to customize.
// Return value:
// (async) path to the selected item.
template<typename TLambda>
static winrt::Windows::Foundation::IAsyncOperation<winrt::hstring> OpenFilePicker(HWND parentHwnd, TLambda&& customize)
{
auto fileDialog{ winrt::create_instance<IFileDialog>(CLSID_FileOpenDialog) };
DWORD flags{};
THROW_IF_FAILED(fileDialog->GetOptions(&flags));
THROW_IF_FAILED(fileDialog->SetOptions(flags | FOS_FORCEFILESYSTEM | FOS_NOCHANGEDIR | FOS_DONTADDTORECENT)); // filesystem objects only; no recent places
customize(fileDialog.get());
auto hr{ fileDialog->Show(parentHwnd) };
if (!SUCCEEDED(hr))
{
if (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED))
{
co_return winrt::hstring{};
}
THROW_HR(hr);
}
winrt::com_ptr<IShellItem> result;
THROW_IF_FAILED(fileDialog->GetResult(result.put()));
wil::unique_cotaskmem_string filePath;
THROW_IF_FAILED(result->GetDisplayName(SIGDN_FILESYSPATH, &filePath));
co_return winrt::hstring{ filePath.get() };
}
// Function Description:
// - Helper that opens a file picker pre-seeded with image file types.
static winrt::Windows::Foundation::IAsyncOperation<winrt::hstring> OpenImagePicker(HWND parentHwnd)
{
static constexpr COMDLG_FILTERSPEC supportedImageFileTypes[] = {
{ L"All Supported Bitmap Types (*.jpg, *.jpeg, *.png, *.bmp, *.gif, *.tiff, *.ico)", L"*.jpg;*.jpeg;*.png;*.bmp;*.gif;*.tiff;*.ico" },
{ L"All Files (*.*)", L"*.*" }
};
static constexpr winrt::guid clientGuidImagePicker{ 0x55675F54, 0x74A1, 0x4552, { 0xA3, 0x9D, 0x94, 0xAE, 0x85, 0xD8, 0xF2, 0x7A } };
return OpenFilePicker(parentHwnd, [](auto&& dialog) {
THROW_IF_FAILED(dialog->SetClientGuid(clientGuidImagePicker));
try
{
auto pictureFolderShellItem{ winrt::capture<IShellItem>(&SHGetKnownFolderItem, FOLDERID_PicturesLibrary, KF_FLAG_DEFAULT, nullptr) };
dialog->SetDefaultFolder(pictureFolderShellItem.get());
}
CATCH_LOG(); // non-fatal
THROW_IF_FAILED(dialog->SetFileTypes(ARRAYSIZE(supportedImageFileTypes), supportedImageFileTypes));
THROW_IF_FAILED(dialog->SetFileTypeIndex(1)); // the array is 1-indexed
THROW_IF_FAILED(dialog->SetDefaultExtension(L"jpg;jpeg;png;bmp;gif;tiff;ico"));
});
}
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
Windows::Foundation::Collections::IObservableVector<Editor::Font> ProfileViewModel::_MonospaceFontList{ nullptr };
@ -582,20 +637,11 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
auto lifetime = get_strong();
FileOpenPicker picker;
_State.WindowRoot().TryPropagateHostingWindow(picker); // if we don't do this, there's no HWND for it to attach to
picker.ViewMode(PickerViewMode::Thumbnail);
picker.SuggestedStartLocation(PickerLocationId::PicturesLibrary);
// Converted into a BitmapImage. This list of supported image file formats is from BitmapImage documentation
// https://docs.microsoft.com/en-us/uwp/api/Windows.UI.Xaml.Media.Imaging.BitmapImage?view=winrt-19041#remarks
picker.FileTypeFilter().ReplaceAll({ L".jpg", L".jpeg", L".png", L".bmp", L".gif", L".tiff", L".ico" });
StorageFile file = co_await picker.PickSingleFileAsync();
if (file != nullptr)
const auto parentHwnd{ reinterpret_cast<HWND>(_State.WindowRoot().GetHostingWindow()) };
auto file = co_await OpenImagePicker(parentHwnd);
if (!file.empty())
{
_State.Profile().BackgroundImagePath(file.Path());
_State.Profile().BackgroundImagePath(file);
}
}
@ -603,20 +649,11 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
auto lifetime = get_strong();
FileOpenPicker picker;
_State.WindowRoot().TryPropagateHostingWindow(picker); // if we don't do this, there's no HWND for it to attach to
picker.ViewMode(PickerViewMode::Thumbnail);
picker.SuggestedStartLocation(PickerLocationId::PicturesLibrary);
// Converted into a BitmapIconSource. This list of supported image file formats is from BitmapImage documentation
// https://docs.microsoft.com/en-us/uwp/api/Windows.UI.Xaml.Media.Imaging.BitmapImage?view=winrt-19041#remarks
picker.FileTypeFilter().ReplaceAll({ L".jpg", L".jpeg", L".png", L".bmp", L".gif", L".tiff", L".ico" });
StorageFile file = co_await picker.PickSingleFileAsync();
if (file != nullptr)
const auto parentHwnd{ reinterpret_cast<HWND>(_State.WindowRoot().GetHostingWindow()) };
auto file = co_await OpenImagePicker(parentHwnd);
if (!file.empty())
{
_State.Profile().Icon(file.Path());
_State.Profile().Icon(file);
}
}
@ -624,32 +661,54 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
auto lifetime = get_strong();
FileOpenPicker picker;
static constexpr COMDLG_FILTERSPEC supportedFileTypes[] = {
{ L"Executable Files (*.exe, *.cmd, *.bat)", L"*.exe;*.cmd;*.bat" },
{ L"All Files (*.*)", L"*.*" }
};
_State.WindowRoot().TryPropagateHostingWindow(picker); // if we don't do this, there's no HWND for it to attach to
picker.ViewMode(PickerViewMode::Thumbnail);
picker.SuggestedStartLocation(PickerLocationId::ComputerFolder);
picker.FileTypeFilter().ReplaceAll({ L".bat", L".exe", L".cmd" });
static constexpr winrt::guid clientGuidExecutables{ 0x2E7E4331, 0x0800, 0x48E6, { 0xB0, 0x17, 0xA1, 0x4C, 0xD8, 0x73, 0xDD, 0x58 } };
const auto parentHwnd{ reinterpret_cast<HWND>(_State.WindowRoot().GetHostingWindow()) };
auto path = co_await OpenFilePicker(parentHwnd, [](auto&& dialog) {
THROW_IF_FAILED(dialog->SetClientGuid(clientGuidExecutables));
try
{
auto folderShellItem{ winrt::capture<IShellItem>(&SHGetKnownFolderItem, FOLDERID_ComputerFolder, KF_FLAG_DEFAULT, nullptr) };
dialog->SetDefaultFolder(folderShellItem.get());
}
CATCH_LOG(); // non-fatal
THROW_IF_FAILED(dialog->SetFileTypes(ARRAYSIZE(supportedFileTypes), supportedFileTypes));
THROW_IF_FAILED(dialog->SetFileTypeIndex(1)); // the array is 1-indexed
THROW_IF_FAILED(dialog->SetDefaultExtension(L"exe;cmd;bat"));
});
StorageFile file = co_await picker.PickSingleFileAsync();
if (file != nullptr)
if (!path.empty())
{
_State.Profile().Commandline(file.Path());
_State.Profile().Commandline(path);
}
}
fire_and_forget Profiles::StartingDirectory_Click(IInspectable const&, RoutedEventArgs const&)
{
auto lifetime = get_strong();
FolderPicker picker;
_State.WindowRoot().TryPropagateHostingWindow(picker); // if we don't do this, there's no HWND for it to attach to
picker.SuggestedStartLocation(PickerLocationId::DocumentsLibrary);
picker.FileTypeFilter().ReplaceAll({ L"*" });
StorageFolder folder = co_await picker.PickSingleFolderAsync();
if (folder != nullptr)
const auto parentHwnd{ reinterpret_cast<HWND>(_State.WindowRoot().GetHostingWindow()) };
auto folder = co_await OpenFilePicker(parentHwnd, [](auto&& dialog) {
static constexpr winrt::guid clientGuidFolderPicker{ 0xAADAA433, 0xB04D, 0x4BAE, { 0xB1, 0xEA, 0x1E, 0x6C, 0xD1, 0xCD, 0xA6, 0x8B } };
THROW_IF_FAILED(dialog->SetClientGuid(clientGuidFolderPicker));
try
{
auto folderShellItem{ winrt::capture<IShellItem>(&SHGetKnownFolderItem, FOLDERID_ComputerFolder, KF_FLAG_DEFAULT, nullptr) };
dialog->SetDefaultFolder(folderShellItem.get());
}
CATCH_LOG(); // non-fatal
DWORD flags{};
THROW_IF_FAILED(dialog->GetOptions(&flags));
THROW_IF_FAILED(dialog->SetOptions(flags | FOS_PICKFOLDERS)); // folders only
});
if (!folder.empty())
{
StorageApplicationPermissions::FutureAccessList().AddOrReplace(L"PickedFolderToken", folder);
_State.Profile().StartingDirectory(folder.Path());
_State.Profile().StartingDirectory(folder);
}
}

View file

@ -29,7 +29,6 @@
#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.Storage.h>
#include <winrt/Windows.Storage.AccessCache.h>
#include <winrt/Windows.Storage.Pickers.h>
#include <winrt/Windows.UI.h>
#include <winrt/Windows.UI.Core.h>
@ -54,7 +53,8 @@
#include <winrt/Microsoft.Terminal.Control.h>
#include <winrt/Microsoft.Terminal.Settings.Model.h>
#include "shobjidl_core.h"
#include <shlobj.h>
#include <shobjidl_core.h>
#include <dwrite.h>
#include <dwrite_1.h>

View file

@ -221,13 +221,26 @@ winrt::Microsoft::Terminal::Settings::Model::Profile CascadiaSettings::ProfileDe
// - a reference to the new profile
winrt::Microsoft::Terminal::Settings::Model::Profile CascadiaSettings::CreateNewProfile()
{
if (_allProfiles.Size() == std::numeric_limits<uint32_t>::max())
{
// Shouldn't really happen
return nullptr;
}
winrt::hstring newName{};
for (uint32_t candidateIndex = 0; candidateIndex < _allProfiles.Size() + 1; candidateIndex++)
{
// There is a theoretical unsigned integer wraparound, which is OK
newName = fmt::format(L"Profile {}", _allProfiles.Size() + 1 + candidateIndex);
if (std::none_of(begin(_allProfiles), end(_allProfiles), [&](auto&& profile) { return profile.Name() == newName; }))
{
break;
}
}
auto newProfile{ _userDefaultProfileSettings->CreateChild() };
_allProfiles.Append(*newProfile);
// Give the new profile a distinct name so a guid is properly generated
const winrt::hstring newName{ fmt::format(L"Profile {}", _allProfiles.Size()) };
newProfile->Name(newName);
_allProfiles.Append(*newProfile);
return *newProfile;
}

View file

@ -381,6 +381,9 @@ void Profile::_FinalizeInheritance()
{
if (auto defaultAppearanceImpl = get_self<AppearanceConfig>(_DefaultAppearance))
{
// Clear any existing parents first, we don't want duplicates from any previous
// calls to this function
defaultAppearanceImpl->ClearParents();
for (auto& parent : _parents)
{
if (auto parentDefaultAppearanceImpl = parent->_DefaultAppearance.try_as<AppearanceConfig>())

View file

@ -362,6 +362,8 @@
// Visual Adjustments
{ "command": { "action": "adjustFontSize", "delta": 1 }, "keys": "ctrl+=" },
{ "command": { "action": "adjustFontSize", "delta": -1 }, "keys": "ctrl+-" },
{ "command": { "action": "adjustFontSize", "delta": 1 }, "keys": "ctrl+numpad_plus" },
{ "command": { "action": "adjustFontSize", "delta": -1 }, "keys": "ctrl+numpad_minus" },
{ "command": "resetFontSize", "keys": "ctrl+0" },
// Other commands

View file

@ -765,6 +765,91 @@ void IslandWindow::_SetIsBorderless(const bool borderlessEnabled)
SWP_SHOWWINDOW | SWP_FRAMECHANGED | SWP_NOACTIVATE);
}
// Method Description:
// - Called when entering fullscreen, with the window's current monitor rect and work area.
// - The current window position, dpi, work area, and maximized state are stored, and the
// window is positioned to the monitor rect.
void IslandWindow::_SetFullscreenPosition(const RECT rcMonitor, const RECT rcWork)
{
HWND const hWnd = GetHandle();
::GetWindowRect(hWnd, &_rcWindowBeforeFullscreen);
_dpiBeforeFullscreen = GetDpiForWindow(hWnd);
_fWasMaximizedBeforeFullscreen = IsZoomed(hWnd);
_rcWorkBeforeFullscreen = rcWork;
SetWindowPos(hWnd,
HWND_TOP,
rcMonitor.left,
rcMonitor.top,
rcMonitor.right - rcMonitor.left,
rcMonitor.bottom - rcMonitor.top,
SWP_FRAMECHANGED);
}
// Method Description:
// - Called when exiting fullscreen, with the window's current monitor work area.
// - The window is restored to its previous position, migrating that previous position to the
// window's current monitor (if the current work area or window DPI have changed).
// - A fullscreen window's monitor can be changed by win+shift+left/right hotkeys or monitor
// topology changes (for example unplugging a monitor or disconnecting a remote session).
void IslandWindow::_RestoreFullscreenPosition(const RECT rcWork)
{
HWND const hWnd = GetHandle();
// If the window was previously maximized, re-maximize the window.
if (_fWasMaximizedBeforeFullscreen)
{
ShowWindow(hWnd, SW_SHOWMAXIMIZED);
SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
return;
}
// Start with the stored window position.
RECT rcRestore = _rcWindowBeforeFullscreen;
// If the window DPI has changed, re-size the stored position by the change in DPI. This
// ensures the window restores to the same logical size (even if to a monitor with a different
// DPI/ scale factor).
UINT dpiWindow = GetDpiForWindow(hWnd);
rcRestore.right = rcRestore.left + MulDiv(rcRestore.right - rcRestore.left, dpiWindow, _dpiBeforeFullscreen);
rcRestore.bottom = rcRestore.top + MulDiv(rcRestore.bottom - rcRestore.top, dpiWindow, _dpiBeforeFullscreen);
// Offset the stored position by the difference in work area.
OffsetRect(&rcRestore,
rcWork.left - _rcWorkBeforeFullscreen.left,
rcWork.top - _rcWorkBeforeFullscreen.top);
// Enforce that our position is entirely within the bounds of our work area.
// Prefer the top-left be on-screen rather than bottom-right (right before left, bottom before top).
if (rcRestore.right > rcWork.right)
{
OffsetRect(&rcRestore, rcWork.right - rcRestore.right, 0);
}
if (rcRestore.left < rcWork.left)
{
OffsetRect(&rcRestore, rcWork.left - rcRestore.left, 0);
}
if (rcRestore.bottom > rcWork.bottom)
{
OffsetRect(&rcRestore, 0, rcWork.bottom - rcRestore.bottom);
}
if (rcRestore.top < rcWork.top)
{
OffsetRect(&rcRestore, 0, rcWork.top - rcRestore.top);
}
// Show the window at the computed position.
SetWindowPos(hWnd,
HWND_TOP,
rcRestore.left,
rcRestore.top,
rcRestore.right - rcRestore.left,
rcRestore.bottom - rcRestore.top,
SWP_SHOWWINDOW | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
}
// Method Description:
// - Controls setting us into or out of fullscreen mode. Largely taken from
// Window::SetIsFullscreen in conhost.
@ -780,7 +865,7 @@ void IslandWindow::_SetIsFullscreen(const bool fullscreenEnabled)
// It is possible to enter _SetIsFullscreen even if we're already in full
// screen. Use the old is in fullscreen flag to gate checks that rely on the
// current state.
const auto oldIsInFullscreen = _fullscreen;
const bool fChangingFullscreen = (fullscreenEnabled != _fullscreen);
_fullscreen = fullscreenEnabled;
HWND const hWnd = GetHandle();
@ -796,61 +881,27 @@ void IslandWindow::_SetIsFullscreen(const bool fullscreenEnabled)
WI_UpdateFlag(exWindowStyle, WS_EX_WINDOWEDGE, !_fullscreen);
_SetWindowLongWHelper(hWnd, GWL_EXSTYLE, exWindowStyle);
// When entering/exiting fullscreen mode, we also need to backup/restore the
// current window size, and resize the window to match the new state.
_BackupWindowSizes(oldIsInFullscreen);
_ApplyWindowSize();
}
// Method Description:
// - Used in entering/exiting fullscreen mode. Saves the current window size,
// and the full size of the monitor, for use in _ApplyWindowSize.
// - Taken from conhost's Window::_BackupWindowSizes
// Arguments:
// - fCurrentIsInFullscreen: true if we're currently in fullscreen mode.
// Return Value:
// - <none>
void IslandWindow::_BackupWindowSizes(const bool fCurrentIsInFullscreen)
{
if (_fullscreen)
// Only change the window position if changing fullscreen state.
if (fChangingFullscreen)
{
// Note: the current window size depends on the current state of the
// window. So don't back it up if we're already in full screen.
if (!fCurrentIsInFullscreen)
{
_nonFullscreenWindowSize = GetWindowRect();
}
// Get the monitor info for the window's current monitor.
MONITORINFO mi = {};
mi.cbSize = sizeof(mi);
GetMonitorInfo(MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST), &mi);
// get and back up the current monitor's size
HMONITOR const hCurrentMonitor = MonitorFromWindow(GetHandle(), MONITOR_DEFAULTTONEAREST);
MONITORINFO currMonitorInfo;
currMonitorInfo.cbSize = sizeof(currMonitorInfo);
if (GetMonitorInfo(hCurrentMonitor, &currMonitorInfo))
if (_fullscreen)
{
_fullscreenWindowSize = currMonitorInfo.rcMonitor;
// Store the window's current position and size the window to the monitor.
_SetFullscreenPosition(mi.rcMonitor, mi.rcWork);
}
else
{
// Restore the stored window position.
_RestoreFullscreenPosition(mi.rcWork);
}
}
}
// Method Description:
// - Applies the appropriate window size for transitioning to/from fullscreen mode.
// - Taken from conhost's Window::_ApplyWindowSize
// Arguments:
// - <none>
// Return Value:
// - <none>
void IslandWindow::_ApplyWindowSize()
{
const auto newSize = _fullscreen ? _fullscreenWindowSize : _nonFullscreenWindowSize;
LOG_IF_WIN32_BOOL_FALSE(SetWindowPos(GetHandle(),
HWND_TOP,
newSize.left,
newSize.top,
newSize.right - newSize.left,
newSize.bottom - newSize.top,
SWP_FRAMECHANGED | SWP_NOACTIVATE));
}
void IslandWindow::UnsetHotkeys(const std::vector<winrt::Microsoft::Terminal::Control::KeyChord>& hotkeyList)
{
for (int i = 0; i < hotkeyList.size(); i++)

View file

@ -72,15 +72,17 @@ protected:
[[nodiscard]] LRESULT _OnSizing(const WPARAM wParam, const LPARAM lParam);
bool _borderless{ false };
bool _fullscreen{ false };
bool _alwaysOnTop{ false };
RECT _fullscreenWindowSize;
RECT _nonFullscreenWindowSize;
bool _fullscreen{ false };
bool _fWasMaximizedBeforeFullscreen{ false };
RECT _rcWindowBeforeFullscreen;
RECT _rcWorkBeforeFullscreen;
UINT _dpiBeforeFullscreen;
virtual void _SetIsBorderless(const bool borderlessEnabled);
virtual void _SetIsFullscreen(const bool fullscreenEnabled);
void _BackupWindowSizes(const bool currentIsInFullscreen);
void _ApplyWindowSize();
void _RestoreFullscreenPosition(const RECT rcWork);
void _SetFullscreenPosition(const RECT rcMonitor, const RECT rcWork);
LONG _getDesiredWindowStyle() const;

View file

@ -182,6 +182,7 @@ bool PtySignalInputThread::_GetData(_Out_writes_bytes_(cbBuffer) void* const pBu
RETURN_LAST_ERROR_IF_NULL(hThread);
_hThread.reset(hThread);
_dwThreadId = dwThreadId;
LOG_IF_FAILED(SetThreadDescription(hThread, L"ConPTY Signal Handler Thread"));
return S_OK;
}

View file

@ -176,6 +176,7 @@ DWORD VtInputThread::_InputThread()
RETURN_LAST_ERROR_IF_NULL(hThread);
_hThread.reset(hThread);
_dwThreadId = dwThreadId;
LOG_IF_FAILED(SetThreadDescription(hThread, L"ConPTY Input Handler Thread"));
return S_OK;
}

View file

@ -130,35 +130,6 @@ bool ConhostInternalGetSet::SetConsoleCursorPosition(const COORD position)
return SUCCEEDED(ServiceLocator::LocateGlobals().api.SetConsoleCursorPositionImpl(info, clampedPosition));
}
// Routine Description:
// - Connects the GetConsoleCursorInfo API call directly into our Driver Message servicing call inside Conhost.exe
// Arguments:
// - cursorInfo - Structure to receive console cursor rendering info
// Return Value:
// - true if successful (see DoSrvGetConsoleCursorInfo). false otherwise.
bool ConhostInternalGetSet::GetConsoleCursorInfo(CONSOLE_CURSOR_INFO& cursorInfo) const
{
bool visible;
DWORD size;
ServiceLocator::LocateGlobals().api.GetConsoleCursorInfoImpl(_io.GetActiveOutputBuffer(), size, visible);
cursorInfo.bVisible = visible;
cursorInfo.dwSize = size;
return true;
}
// Routine Description:
// - Connects the SetConsoleCursorInfo API call directly into our Driver Message servicing call inside Conhost.exe
// Arguments:
// - cursorInfo - Updated size/visibility information to modify the cursor rendering behavior.
// Return Value:
// - true if successful (see DoSrvSetConsoleCursorInfo). false otherwise.
bool ConhostInternalGetSet::SetConsoleCursorInfo(const CONSOLE_CURSOR_INFO& cursorInfo)
{
const bool visible = !!cursorInfo.bVisible;
return SUCCEEDED(ServiceLocator::LocateGlobals().api.SetConsoleCursorInfoImpl(_io.GetActiveOutputBuffer(), cursorInfo.dwSize, visible));
}
// Method Description:
// - Retrieves the current TextAttribute of the active screen buffer.
// Arguments:

View file

@ -59,9 +59,6 @@ public:
bool SetConsoleCursorPosition(const COORD position) override;
bool GetConsoleCursorInfo(CONSOLE_CURSOR_INFO& cursorInfo) const override;
bool SetConsoleCursorInfo(const CONSOLE_CURSOR_INFO& cursorInfo) override;
bool PrivateGetTextAttributes(TextAttribute& attrs) const override;
bool PrivateSetTextAttributes(const TextAttribute& attrs) override;

View file

@ -2684,26 +2684,6 @@ bool SCREEN_INFORMATION::IsCursorInMargins(const COORD cursorPosition) const noe
return cursorPosition.Y <= margins.Bottom && cursorPosition.Y >= margins.Top;
}
// Method Description:
// - Gets the region of the buffer that should be used for scrolling within the
// scroll margins. If the scroll margins aren't set, it returns the entire
// buffer size.
// Arguments:
// - <none>
// Return Value:
// - The area of the buffer within the scroll margins
Viewport SCREEN_INFORMATION::GetScrollingRegion() const noexcept
{
const auto buffer = GetBufferSize();
const bool marginsSet = AreMarginsSet();
const auto marginRect = GetAbsoluteScrollMargins().ToInclusive();
const auto margin = Viewport::FromInclusive({ buffer.Left(),
marginsSet ? marginRect.Top : buffer.Top(),
buffer.RightInclusive(),
marginsSet ? marginRect.Bottom : buffer.BottomInclusive() });
return margin;
}
// Routine Description:
// - Engages the legacy VT handling quirk; see TextAttribute::StripErroneousVT16VersionsOfLegacyDefaults
void SCREEN_INFORMATION::SetIgnoreLegacyEquivalentVTAttributes() noexcept

View file

@ -202,7 +202,6 @@ public:
void SetScrollMargins(const Microsoft::Console::Types::Viewport margins);
bool AreMarginsSet() const noexcept;
bool IsCursorInMargins(const COORD cursorPosition) const noexcept;
Microsoft::Console::Types::Viewport GetScrollingRegion() const noexcept;
[[nodiscard]] NTSTATUS UseAlternateScreenBuffer();
void UseMainScreenBuffer();

View file

@ -322,6 +322,7 @@ HRESULT ConsoleCreateIoThread(_In_ HANDLE Server,
HANDLE const hThread = CreateThread(nullptr, 0, ConsoleIoThread, connectMessage, 0, nullptr);
RETURN_HR_IF(E_HANDLE, hThread == nullptr);
LOG_IF_FAILED(SetThreadDescription(hThread, L"Console Driver Message IO Thread"));
LOG_IF_WIN32_BOOL_FALSE(CloseHandle(hThread)); // The thread will run on its own and close itself. Free the associated handle.
// See MSFT:19918626

View file

@ -27,6 +27,7 @@ HANDLE ConsoleInputThread::Start()
{
_hThread = hThread;
_dwThreadId = dwThreadId;
LOG_IF_FAILED(SetThreadDescription(hThread, L"Win32 Window Message Input Thread"));
}
return hThread;

View file

@ -60,11 +60,13 @@ Window::Window() :
_fIsInFullscreen(false),
_pSettings(nullptr),
_hWnd(nullptr),
_pUiaProvider(nullptr)
_pUiaProvider(nullptr),
_fWasMaximizedBeforeFullscreen(false),
_dpiBeforeFullscreen(0)
{
ZeroMemory((void*)&_rcClientLast, sizeof(_rcClientLast));
ZeroMemory((void*)&_rcNonFullscreenWindowSize, sizeof(_rcNonFullscreenWindowSize));
ZeroMemory((void*)&_rcFullscreenWindowSize, sizeof(_rcFullscreenWindowSize));
ZeroMemory((void*)&_rcWindowBeforeFullscreen, sizeof(_rcWindowBeforeFullscreen));
ZeroMemory((void*)&_rcWorkBeforeFullscreen, sizeof(_rcWorkBeforeFullscreen));
}
Window::~Window()
@ -1095,11 +1097,90 @@ bool Window::IsInFullscreen() const
return _fIsInFullscreen;
}
// Routine Description:
// - Called when entering fullscreen, with the window's current monitor rect and work area.
// - The current window position, dpi, work area, and maximized state are stored, and the
// window is positioned to the monitor rect.
void Window::_SetFullscreenPosition(const RECT rcMonitor, const RECT rcWork)
{
::GetWindowRect(GetWindowHandle(), &_rcWindowBeforeFullscreen);
_dpiBeforeFullscreen = GetDpiForWindow(GetWindowHandle());
_fWasMaximizedBeforeFullscreen = IsZoomed(GetWindowHandle());
_rcWorkBeforeFullscreen = rcWork;
SetWindowPos(GetWindowHandle(),
HWND_TOP,
rcMonitor.left,
rcMonitor.top,
rcMonitor.right - rcMonitor.left,
rcMonitor.bottom - rcMonitor.top,
SWP_FRAMECHANGED);
}
// Routine Description:
// - Called when exiting fullscreen, with the window's current monitor work area.
// - The window is restored to its previous position, migrating that previous position to the
// window's current monitor (if the current work area or window DPI have changed).
// - A fullscreen window's monitor can be changed by win+shift+left/right hotkeys or monitor
// topology changes (for example unplugging a monitor or disconnecting a remote session).
void Window::_RestoreFullscreenPosition(const RECT rcWork)
{
// If the window was previously maximized, re-maximize the window.
if (_fWasMaximizedBeforeFullscreen)
{
ShowWindow(GetWindowHandle(), SW_SHOWMAXIMIZED);
SetWindowPos(GetWindowHandle(), HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
return;
}
// Start with the stored window position.
RECT rcRestore = _rcWindowBeforeFullscreen;
// If the window DPI has changed, re-size the stored position by the change in DPI. This
// ensures the window restores to the same logical size (even if to a monitor with a different
// DPI/ scale factor).
UINT dpiWindow = GetDpiForWindow(GetWindowHandle());
rcRestore.right = rcRestore.left + MulDiv(rcRestore.right - rcRestore.left, dpiWindow, _dpiBeforeFullscreen);
rcRestore.bottom = rcRestore.top + MulDiv(rcRestore.bottom - rcRestore.top, dpiWindow, _dpiBeforeFullscreen);
// Offset the stored position by the difference in work area.
OffsetRect(&rcRestore,
rcWork.left - _rcWorkBeforeFullscreen.left,
rcWork.top - _rcWorkBeforeFullscreen.top);
// Enforce that our position is entirely within the bounds of our work area.
// Prefer the top-left be on-screen rather than bottom-right (right before left, bottom before top).
if (rcRestore.right > rcWork.right)
{
OffsetRect(&rcRestore, rcWork.right - rcRestore.right, 0);
}
if (rcRestore.left < rcWork.left)
{
OffsetRect(&rcRestore, rcWork.left - rcRestore.left, 0);
}
if (rcRestore.bottom > rcWork.bottom)
{
OffsetRect(&rcRestore, 0, rcWork.bottom - rcRestore.bottom);
}
if (rcRestore.top < rcWork.top)
{
OffsetRect(&rcRestore, 0, rcWork.top - rcRestore.top);
}
// Show the window at the computed position.
SetWindowPos(GetWindowHandle(),
HWND_TOP,
rcRestore.left,
rcRestore.top,
rcRestore.right - rcRestore.left,
rcRestore.bottom - rcRestore.top,
SWP_SHOWWINDOW | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
}
void Window::SetIsFullscreen(const bool fFullscreenEnabled)
{
// It is possible to enter SetIsFullScreen even if we're already in full screen.
// Use the old is in fullscreen flag to gate checks that rely on the current state.
bool fOldIsInFullscreen = _fIsInFullscreen;
const bool fChangingFullscreen = (fFullscreenEnabled != _fIsInFullscreen);
_fIsInFullscreen = fFullscreenEnabled;
HWND const hWnd = GetWindowHandle();
@ -1135,48 +1216,30 @@ void Window::SetIsFullscreen(const bool fFullscreenEnabled)
}
SetWindowLongW(hWnd, GWL_EXSTYLE, dwExWindowStyle);
_BackupWindowSizes(fOldIsInFullscreen);
_ApplyWindowSize();
}
void Window::_BackupWindowSizes(const bool fCurrentIsInFullscreen)
{
if (_fIsInFullscreen)
// Only change the window position if changing fullscreen state.
if (fChangingFullscreen)
{
// Note: the current window size depends on the current state of the window.
// So don't back it up if we're already in full screen.
if (!fCurrentIsInFullscreen)
{
_rcNonFullscreenWindowSize = GetWindowRect();
}
// Get the monitor info for the window's current monitor.
MONITORINFO mi = {};
mi.cbSize = sizeof(mi);
GetMonitorInfo(MonitorFromWindow(GetWindowHandle(), MONITOR_DEFAULTTONEAREST), &mi);
// get and back up the current monitor's size
HMONITOR const hCurrentMonitor = MonitorFromWindow(GetWindowHandle(), MONITOR_DEFAULTTONEAREST);
MONITORINFO currMonitorInfo;
currMonitorInfo.cbSize = sizeof(currMonitorInfo);
if (GetMonitorInfo(hCurrentMonitor, &currMonitorInfo))
if (_fIsInFullscreen)
{
_rcFullscreenWindowSize = currMonitorInfo.rcMonitor;
// Store the window's current position and size the window to the monitor.
_SetFullscreenPosition(mi.rcMonitor, mi.rcWork);
}
else
{
// Restore the stored window position.
_RestoreFullscreenPosition(mi.rcWork);
SCREEN_INFORMATION& siAttached = GetScreenInfo();
siAttached.MakeCurrentCursorVisible();
}
}
}
void Window::_ApplyWindowSize()
{
const RECT rcNewSize = _fIsInFullscreen ? _rcFullscreenWindowSize : _rcNonFullscreenWindowSize;
SetWindowPos(GetWindowHandle(),
HWND_TOP,
rcNewSize.left,
rcNewSize.top,
RECT_WIDTH(&rcNewSize),
RECT_HEIGHT(&rcNewSize),
SWP_FRAMECHANGED);
SCREEN_INFORMATION& siAttached = GetScreenInfo();
siAttached.MakeCurrentCursorVisible();
}
void Window::ToggleFullscreen()
{
SetIsFullscreen(!IsInFullscreen());

View file

@ -147,12 +147,13 @@ namespace Microsoft::Console::Interactivity::Win32
RECT _rcClientLast;
// Full screen
void _BackupWindowSizes(const bool fCurrentIsInFullscreen);
void _ApplyWindowSize();
void _RestoreFullscreenPosition(const RECT rcWork);
void _SetFullscreenPosition(const RECT rcMonitor, const RECT rcWork);
bool _fIsInFullscreen;
RECT _rcFullscreenWindowSize;
RECT _rcNonFullscreenWindowSize;
bool _fWasMaximizedBeforeFullscreen;
RECT _rcWindowBeforeFullscreen;
RECT _rcWorkBeforeFullscreen;
UINT _dpiBeforeFullscreen;
// math helpers
void _CalculateWindowRect(const COORD coordWindowInChars,

View file

@ -226,18 +226,15 @@ using namespace Microsoft::Console::Types;
_UpdateSystemMetrics();
s_ReinitializeFontsForDPIChange();
if (IsInFullscreen())
{
// If we're a full screen window, completely ignore what the DPICHANGED says as it will be bigger than the monitor and
// instead just ensure that the window is still taking up the full screen.
SetIsFullscreen(true);
}
else
{
// this is the RECT that the system suggests.
RECT* const prcNewScale = (RECT*)lParam;
SetWindowPos(hWnd, HWND_TOP, prcNewScale->left, prcNewScale->top, RECT_WIDTH(prcNewScale), RECT_HEIGHT(prcNewScale), SWP_NOZORDER | SWP_NOACTIVATE);
}
// This is the RECT that the system suggests.
RECT* const prcNewScale = (RECT*)lParam;
SetWindowPos(hWnd,
HWND_TOP,
prcNewScale->left,
prcNewScale->top,
RECT_WIDTH(prcNewScale),
RECT_HEIGHT(prcNewScale),
SWP_NOZORDER | SWP_NOACTIVATE);
_fInDPIChange = false;

View file

@ -136,6 +136,7 @@ RenderThread::~RenderThread()
else
{
_hThread = hThread;
LOG_IF_FAILED(SetThreadDescription(hThread, L"Rendering Output Thread"));
}
}

View file

@ -15,8 +15,8 @@
// Routine Description:
// - Initializes a ConsoleWaitBlock
// - ConsoleWaitBlocks will self-manage their position in their two queues.
// - They will push themselves into the tail and store the iterator for constant deletion time later.
// - ConsoleWaitBlocks will mostly self-manage their position in their two queues.
// - They will be pushed into the tail and the resulting iterator stored for constant deletion time later.
// Arguments:
// - pProcessQueue - The queue attached to the client process ID that requested this action
// - pObjectQueue - The queue attached to the console object that will service the action when data arrives
@ -30,9 +30,6 @@ ConsoleWaitBlock::ConsoleWaitBlock(_In_ ConsoleWaitQueue* const pProcessQueue,
_pObjectQueue(THROW_HR_IF_NULL(E_INVALIDARG, pObjectQueue)),
_pWaiter(THROW_HR_IF_NULL(E_INVALIDARG, pWaiter))
{
_itProcessQueue = _pProcessQueue->_blocks.insert(_pProcessQueue->_blocks.end(), this);
_itObjectQueue = _pObjectQueue->_blocks.insert(_pObjectQueue->_blocks.end(), this);
_WaitReplyMessage = *pWaitReplyMessage;
// We will write the original message back (with updated out parameters/payload) when the request is finally serviced.
@ -87,6 +84,10 @@ ConsoleWaitBlock::~ConsoleWaitBlock()
pObjectQueue,
pWaitReplyMessage,
pWaiter);
// Set the iterators on the wait block so that it can remove itself later.
pWaitBlock->_itProcessQueue = pProcessQueue->_blocks.insert(pProcessQueue->_blocks.end(), pWaitBlock);
pWaitBlock->_itObjectQueue = pObjectQueue->_blocks.insert(pObjectQueue->_blocks.end(), pWaitBlock);
}
catch (...)
{

View file

@ -29,10 +29,8 @@ namespace Microsoft::Console::VirtualTerminal
{
public:
virtual ~ConGetSet() = default;
virtual bool GetConsoleCursorInfo(CONSOLE_CURSOR_INFO& cursorInfo) const = 0;
virtual bool GetConsoleScreenBufferInfoEx(CONSOLE_SCREEN_BUFFER_INFOEX& screenBufferInfo) const = 0;
virtual bool SetConsoleScreenBufferInfoEx(const CONSOLE_SCREEN_BUFFER_INFOEX& screenBufferInfo) = 0;
virtual bool SetConsoleCursorInfo(const CONSOLE_CURSOR_INFO& cursorInfo) = 0;
virtual bool SetConsoleCursorPosition(const COORD position) = 0;
virtual bool PrivateIsVtInputEnabled() const = 0;

View file

@ -98,32 +98,6 @@ public:
return _setConsoleCursorPositionResult;
}
bool GetConsoleCursorInfo(CONSOLE_CURSOR_INFO& cursorInfo) const override
{
Log::Comment(L"GetConsoleCursorInfo MOCK called...");
if (_getConsoleCursorInfoResult)
{
cursorInfo.dwSize = _cursorSize;
cursorInfo.bVisible = _cursorVisible;
}
return _getConsoleCursorInfoResult;
}
bool SetConsoleCursorInfo(const CONSOLE_CURSOR_INFO& cursorInfo) override
{
Log::Comment(L"SetConsoleCursorInfo MOCK called...");
if (_setConsoleCursorInfoResult)
{
VERIFY_ARE_EQUAL(_expectedCursorSize, cursorInfo.dwSize);
VERIFY_ARE_EQUAL(_expectedCursorVisible, !!cursorInfo.bVisible);
}
return _setConsoleCursorInfoResult;
}
bool SetConsoleWindowInfo(const bool absolute, const SMALL_RECT& window) override
{
Log::Comment(L"SetConsoleWindowInfo MOCK called...");
@ -624,8 +598,6 @@ public:
// APIs succeed by default
_setConsoleCursorPositionResult = TRUE;
_getConsoleScreenBufferInfoExResult = TRUE;
_getConsoleCursorInfoResult = TRUE;
_setConsoleCursorInfoResult = TRUE;
_privateGetTextAttributesResult = TRUE;
_privateSetTextAttributesResult = TRUE;
_privateWriteConsoleInputWResult = TRUE;
@ -645,11 +617,7 @@ public:
// Call cursor positions separately
PrepCursor(xact, yact);
_cursorSize = 33;
_expectedCursorSize = _cursorSize;
_cursorVisible = TRUE;
_expectedCursorVisible = _cursorVisible;
// Attribute default is gray on black.
_attribute = TextAttribute{ FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED };
@ -775,12 +743,9 @@ public:
COORD _cursorPos = { 0, 0 };
SMALL_RECT _expectedScrollRegion = { 0, 0, 0, 0 };
DWORD _cursorSize = 0;
bool _cursorVisible = false;
COORD _expectedCursorPos = { 0, 0 };
DWORD _expectedCursorSize = 0;
bool _expectedCursorVisible = false;
TextAttribute _attribute = {};
TextAttribute _expectedAttribute = {};
@ -792,8 +757,6 @@ public:
bool _getConsoleScreenBufferInfoExResult = false;
bool _setConsoleCursorPositionResult = false;
bool _getConsoleCursorInfoResult = false;
bool _setConsoleCursorInfoResult = false;
bool _privateGetTextAttributesResult = false;
bool _privateSetTextAttributesResult = false;
bool _privateWriteConsoleInputWResult = false;