merge main

This commit is contained in:
Kayla Cinnamon 2021-08-10 16:02:49 -07:00
commit 08905d91ca
145 changed files with 3044 additions and 1226 deletions

View file

@ -133,6 +133,7 @@ SRWLOCK
STDCPP
STDMETHOD
strchr
strcpy
streambuf
strtoul
Stubless

View file

@ -169,6 +169,7 @@ brandings
BRK
Browsable
bsearch
Bspace
bstr
BTNFACE
buf
@ -270,10 +271,12 @@ cmder
CMDEXT
Cmdlet
cmdline
cmh
CMOUSEBUTTONS
cmp
cmpeq
cmt
cmw
cmyk
CNL
cnt
@ -406,11 +409,13 @@ csbiex
csharp
CSHORT
CSIDL
Cspace
csproj
Csr
csrmsg
CSRSS
csrutil
css
cstdarg
cstddef
cstdio
@ -509,6 +514,7 @@ DECAWM
DECCKM
DECCOLM
DECDHL
DECDLD
DECDWL
DECEKBD
DECID
@ -789,6 +795,7 @@ FONTENUMPROC
FONTFACE
FONTFAMILY
FONTHEIGHT
FONTINFO
fontlist
FONTOK
FONTSIZE
@ -902,6 +909,7 @@ github
gitlab
gle
globals
GLYPHENTRY
gmail
GMEM
GNUC
@ -950,6 +958,7 @@ hdrstop
HEIGHTSCROLL
hfile
hfont
hfontresource
hglobal
hhh
HHmm
@ -1272,6 +1281,7 @@ locsrc
locstudio
Loewen
LOGFONT
LOGFONTA
LOGFONTW
logissue
lowercased
@ -1935,6 +1945,7 @@ realloc
reamapping
rects
redef
redefinable
Redir
redirector
redist
@ -1980,6 +1991,7 @@ rfc
rftp
rgb
rgba
RGBCOLOR
rgbi
rgci
rgfae
@ -2149,6 +2161,7 @@ SIGDN
SINGLEFLAG
SINGLETHREADED
siup
sixel
SIZEBOX
sizeof
SIZESCROLL
@ -2754,6 +2767,7 @@ WTo
wtof
wtoi
WTs
WTSOFTFONT
wtw
wtypes
Wubi

View file

@ -2,8 +2,9 @@
trigger: none
pr: none
pool:
name: Package ES Standard Build
pool:
name: WinDevPool-L
demands: ImageOverride -equals WinDevVS16-latest
parameters:
- name: branding
@ -70,11 +71,9 @@ jobs:
clean: true
submodules: true
persistCredentials: True
- task: PkgESSetupBuild@10
- task: PkgESSetupBuild@12
displayName: Package ES - Setup Build
inputs:
useDfs: false
productName: OpenConsole
disableOutputRedirect: true
- task: PowerShell@2
displayName: Rationalize Build Platform
@ -275,11 +274,9 @@ jobs:
clean: true
submodules: true
persistCredentials: True
- task: PkgESSetupBuild@10
- task: PkgESSetupBuild@12
displayName: Package ES - Setup Build
inputs:
useDfs: false
productName: OpenConsole
disableOutputRedirect: true
- task: DownloadBuildArtifacts@0
displayName: Download Artifacts (*.appx, *.msix)
@ -354,11 +351,9 @@ jobs:
clean: true
submodules: true
persistCredentials: True
- task: PkgESSetupBuild@10
- task: PkgESSetupBuild@12
displayName: Package ES - Setup Build
inputs:
useDfs: false
productName: OpenConsole
disableOutputRedirect: true
- task: DownloadBuildArtifacts@0
displayName: Download x86 PublicTerminalCore
@ -480,7 +475,7 @@ jobs:
mv Microsoft.WindowsTerminal_8wekyb3d8bbwe.msixbundle .\WindowsTerminal.app\
workingDirectory: $(System.ArtifactsDirectory)\appxbundle-signed
- task: PkgESVPack@10
- task: PkgESVPack@12
displayName: 'Package ES - VPack'
env:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)

View file

@ -8,9 +8,12 @@ jobs:
variables:
BuildConfiguration: AuditMode
BuildPlatform: ${{ parameters.platform }}
pool: "windevbuildagents"
# The public pool is also an option!
# pool: { vmImage: windows-2019 }
pool:
${{ if eq(variables['System.CollectionUri'], 'https://dev.azure.com/ms/') }}:
name: WinDevPoolOSS-L
${{ if ne(variables['System.CollectionUri'], 'https://dev.azure.com/ms/') }}:
name: WinDevPool-L
demands: ImageOverride -equals WinDevVS16-latest
steps:
- checkout: self

View file

@ -11,9 +11,12 @@ jobs:
variables:
BuildConfiguration: ${{ parameters.configuration }}
BuildPlatform: ${{ parameters.platform }}
pool: "windevbuildagents"
# The public pool is also an option!
# pool: { vmImage: windows-2019 }
pool:
${{ if eq(variables['System.CollectionUri'], 'https://dev.azure.com/ms/') }}:
name: WinDevPoolOSS-L
${{ if ne(variables['System.CollectionUri'], 'https://dev.azure.com/ms/') }}:
name: WinDevPool-L
demands: ImageOverride -equals WinDevVS16-latest
steps:
- template: build-console-steps.yml

View file

@ -12,9 +12,12 @@ jobs:
BuildConfiguration: ${{ parameters.configuration }}
BuildPlatform: ${{ parameters.platform }}
PGOBuildMode: 'Instrument'
pool: "windevbuildagents"
# The public pool is also an option!
# pool: { vmImage: windows-2019 }
pool:
${{ if eq(variables['System.CollectionUri'], 'https://dev.azure.com/ms/') }}:
name: WinDevPoolOSS-L
${{ if ne(variables['System.CollectionUri'], 'https://dev.azure.com/ms/') }}:
name: WinDevPool-L
demands: ImageOverride -equals WinDevVS16-latest
steps:
- template: build-console-steps.yml

View file

@ -192,21 +192,24 @@ COLORREF TextColor::GetColor(const std::array<COLORREF, 256>& colorTable, const
unsigned long index;
return _BitScanForward(&index, mask) ? til::at(colorTable, static_cast<size_t>(index) + 8) : defaultColor; // 5.
#elif _M_AMD64
// If you look closely this SSE2 algorithm is the exact same as the AVX one.
// If you look closely this SSE2 algorithm is the same as the AVX one.
// The two differences are that we need to:
// * do everything twice, because SSE is limited to 128 bits and not 256.
// * use _mm_packs_epi32 to merge two 128 bits vectors into one in step 3.5.
// _mm_packs_epi32 takes two SSE registers and truncates all 8 DWORDs into 8 WORDs,
// the latter of which fits into a single register (which is then used in the identical step 4).
// * since the result are now 8 WORDs, we need to use _mm_movemask_epi8 (there's no 16-bit variant),
// which unlike AVX's step 4 results in in something like 0b0000110000000000.
// --> the index returned by _BitScanForward must be divided by 2.
const auto haystack1 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(colorTable.data() + 0));
const auto haystack2 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(colorTable.data() + 4));
const auto needle = _mm_set1_epi32(__builtin_bit_cast(int, defaultColor));
const auto result1 = _mm_cmpeq_epi32(haystack1, needle);
const auto result2 = _mm_cmpeq_epi32(haystack2, needle);
const auto result = _mm_packs_epi32(result1, result2); // 3.5
const auto mask = _mm_movemask_ps(_mm_castsi128_ps(result));
const auto mask = _mm_movemask_epi8(result);
unsigned long index;
return _BitScanForward(&index, mask) ? til::at(colorTable, static_cast<size_t>(index) + 8) : defaultColor;
return _BitScanForward(&index, mask) ? til::at(colorTable, static_cast<size_t>(index / 2) + 8) : defaultColor;
#else
for (size_t i = 0; i < 8; i++)
{

View file

@ -397,6 +397,10 @@ namespace SettingsModelLocalTests
"name":"action6",
"command": { "action": "newWindow", "startingDirectory":"C:\\foo", "commandline": "bar.exe" }
},
{
"name":"action7_startingDirectoryWithTrailingSlash",
"command": { "action": "newWindow", "startingDirectory":"C:\\", "commandline": "bar.exe" }
},
])" };
const auto commands0Json = VerifyParseSucceeded(commands0String);
@ -405,7 +409,7 @@ namespace SettingsModelLocalTests
VERIFY_ARE_EQUAL(0u, commands.Size());
auto warnings = implementation::Command::LayerJson(commands, commands0Json);
VERIFY_ARE_EQUAL(0u, warnings.size());
VERIFY_ARE_EQUAL(7u, commands.Size());
VERIFY_ARE_EQUAL(8u, commands.Size());
{
auto command = commands.Lookup(L"action0");
@ -503,5 +507,20 @@ namespace SettingsModelLocalTests
L"cmdline: \"%s\"", cmdline.c_str()));
VERIFY_ARE_EQUAL(L"--startingDirectory \"C:\\foo\" -- \"bar.exe\"", terminalArgs.ToCommandline());
}
{
auto command = commands.Lookup(L"action7_startingDirectoryWithTrailingSlash");
VERIFY_IS_NOT_NULL(command);
VERIFY_IS_NOT_NULL(command.ActionAndArgs());
VERIFY_ARE_EQUAL(ShortcutAction::NewWindow, command.ActionAndArgs().Action());
const auto& realArgs = command.ActionAndArgs().Args().try_as<NewWindowArgs>();
VERIFY_IS_NOT_NULL(realArgs);
const auto& terminalArgs = realArgs.TerminalArgs();
VERIFY_IS_NOT_NULL(terminalArgs);
auto cmdline = terminalArgs.ToCommandline();
Log::Comment(NoThrowString().Format(
L"cmdline: \"%s\"", cmdline.c_str()));
VERIFY_ARE_EQUAL(L"--startingDirectory \"C:\\\\\" -- \"bar.exe\"", terminalArgs.ToCommandline());
}
}
}

View file

@ -40,7 +40,7 @@ namespace SettingsModelLocalTests
TEST_METHOD(ManyKeysSameAction);
TEST_METHOD(LayerKeybindings);
TEST_METHOD(UnbindKeybindings);
TEST_METHOD(TestExplicitUnbind);
TEST_METHOD(TestArbitraryArgs);
TEST_METHOD(TestSplitPaneArgs);
@ -232,6 +232,31 @@ namespace SettingsModelLocalTests
VERIFY_IS_NULL(actionMap->GetActionByKeyChord({ VirtualKeyModifiers::Control, static_cast<int32_t>('C'), 0 }));
}
void KeyBindingsTests::TestExplicitUnbind()
{
const std::string bindings0String{ R"([ { "command": "copy", "keys": ["ctrl+c"] } ])" };
const std::string bindings1String{ R"([ { "command": "unbound", "keys": ["ctrl+c"] } ])" };
const std::string bindings2String{ R"([ { "command": "copy", "keys": ["ctrl+c"] } ])" };
const auto bindings0Json = VerifyParseSucceeded(bindings0String);
const auto bindings1Json = VerifyParseSucceeded(bindings1String);
const auto bindings2Json = VerifyParseSucceeded(bindings2String);
const KeyChord keyChord{ VirtualKeyModifiers::Control, static_cast<int32_t>('C'), 0 };
auto actionMap = winrt::make_self<implementation::ActionMap>();
VERIFY_IS_FALSE(actionMap->IsKeyChordExplicitlyUnbound(keyChord));
actionMap->LayerJson(bindings0Json);
VERIFY_IS_FALSE(actionMap->IsKeyChordExplicitlyUnbound(keyChord));
actionMap->LayerJson(bindings1Json);
VERIFY_IS_TRUE(actionMap->IsKeyChordExplicitlyUnbound(keyChord));
actionMap->LayerJson(bindings2Json);
VERIFY_IS_FALSE(actionMap->IsKeyChordExplicitlyUnbound(keyChord));
}
void KeyBindingsTests::TestArbitraryArgs()
{
const std::string bindings0String{ R"([

View file

@ -264,12 +264,12 @@ namespace winrt::TerminalApp::implementation
{
if (args == nullptr)
{
_OpenNewTab(nullptr);
LOG_IF_FAILED(_OpenNewTab(nullptr));
args.Handled(true);
}
else if (const auto& realArgs = args.ActionArgs().try_as<NewTabArgs>())
{
_OpenNewTab(realArgs.TerminalArgs());
LOG_IF_FAILED(_OpenNewTab(realArgs.TerminalArgs()));
args.Handled(true);
}
}

View file

@ -21,6 +21,11 @@ namespace winrt::TerminalApp::implementation
return false;
}
bool AppKeyBindings::IsKeyChordExplicitlyUnbound(const KeyChord& kc)
{
return _actionMap.IsKeyChordExplicitlyUnbound(kc);
}
void AppKeyBindings::SetDispatch(const winrt::TerminalApp::ShortcutActionDispatch& dispatch)
{
_dispatch = dispatch;

View file

@ -20,6 +20,7 @@ namespace winrt::TerminalApp::implementation
AppKeyBindings() = default;
bool TryKeyChord(winrt::Microsoft::Terminal::Control::KeyChord const& kc);
bool IsKeyChordExplicitlyUnbound(winrt::Microsoft::Terminal::Control::KeyChord const& kc);
void SetDispatch(const winrt::TerminalApp::ShortcutActionDispatch& dispatch);
void SetActionMap(const Microsoft::Terminal::Settings::Model::IActionMapView& actionMap);

View file

@ -203,12 +203,16 @@ namespace winrt::TerminalApp::implementation
_isElevated = _isUserAdmin();
_root = winrt::make_self<TerminalPage>();
_reloadSettings = std::make_shared<ThrottledFuncTrailing<>>(_root->Dispatcher(), std::chrono::milliseconds(100), [weakSelf = get_weak()]() {
_reloadSettings = std::make_shared<ThrottledFuncTrailing<>>(winrt::Windows::System::DispatcherQueue::GetForCurrentThread(), std::chrono::milliseconds(100), [weakSelf = get_weak()]() {
if (auto self{ weakSelf.get() })
{
self->_ReloadSettings();
}
});
_languageProfileNotifier = winrt::make_self<LanguageProfileNotifier>([this]() {
_reloadSettings->Run();
});
}
// Method Description:
@ -1125,28 +1129,11 @@ namespace winrt::TerminalApp::implementation
}
}
// Method Description:
// - Gets the taskbar state value from the last active control
// Return Value:
// - The taskbar state of the last active control
uint64_t AppLogic::GetLastActiveControlTaskbarState()
winrt::TerminalApp::TaskbarState AppLogic::TaskbarState()
{
if (_root)
{
return _root->GetLastActiveControlTaskbarState();
}
return {};
}
// Method Description:
// - Gets the taskbar progress value from the last active control
// Return Value:
// - The taskbar progress of the last active control
uint64_t AppLogic::GetLastActiveControlTaskbarProgress()
{
if (_root)
{
return _root->GetLastActiveControlTaskbarProgress();
return _root->TaskbarState();
}
return {};
}
@ -1229,6 +1216,11 @@ namespace winrt::TerminalApp::implementation
auto actions = winrt::single_threaded_vector<ActionAndArgs>(std::move(appArgs.GetStartupActions()));
_root->ProcessStartupActions(actions, false, cwd);
if (appArgs.IsHandoffListener())
{
_root->SetInboundListener(true);
}
}
// Return the result of parsing with commandline, though it may or may not be used.
return result;

View file

@ -5,8 +5,9 @@
#include "AppLogic.g.h"
#include "FindTargetWindowResult.g.h"
#include "TerminalPage.h"
#include "Jumplist.h"
#include "LanguageProfileNotifier.h"
#include "TerminalPage.h"
#include <inc/cppwinrt_utils.h>
#include <ThrottledFunc.h>
@ -89,8 +90,7 @@ namespace winrt::TerminalApp::implementation
void WindowCloseButtonClicked();
uint64_t GetLastActiveControlTaskbarState();
uint64_t GetLastActiveControlTaskbarProgress();
winrt::TerminalApp::TaskbarState TaskbarState();
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::UI::Xaml::Controls::ContentDialogResult> ShowDialog(winrt::Windows::UI::Xaml::Controls::ContentDialog dialog);
@ -110,12 +110,8 @@ namespace winrt::TerminalApp::implementation
// ALSO: If you add any UIElements as roots here, make sure they're
// updated in _ApplyTheme. The root currently is _root.
winrt::com_ptr<TerminalPage> _root{ nullptr };
Microsoft::Terminal::Settings::Model::CascadiaSettings _settings{ nullptr };
wil::unique_folder_change_reader_nothrow _reader;
std::shared_ptr<ThrottledFuncTrailing<>> _reloadSettings;
til::throttled_func_trailing<> _reloadState;
winrt::hstring _settingsLoadExceptionText;
HRESULT _settingsLoadedResult = S_OK;
bool _loadedInitialSettings = false;
@ -124,6 +120,15 @@ namespace winrt::TerminalApp::implementation
::TerminalApp::AppCommandlineArgs _appArgs;
::TerminalApp::AppCommandlineArgs _settingsAppArgs;
std::shared_ptr<ThrottledFuncTrailing<>> _reloadSettings;
til::throttled_func_trailing<> _reloadState;
// These fields invoke _reloadSettings and must be destroyed before _reloadSettings.
// (C++ destroys members in reverse-declaration-order.)
winrt::com_ptr<LanguageProfileNotifier> _languageProfileNotifier;
wil::unique_folder_change_reader_nothrow _reader;
static TerminalApp::FindTargetWindowResult _doFindTargetWindow(winrt::array_view<const hstring> args,
const Microsoft::Terminal::Settings::Model::WindowingMode& windowingBehavior);

View file

@ -68,8 +68,7 @@ namespace TerminalApp
void TitlebarClicked();
void WindowCloseButtonClicked();
UInt64 GetLastActiveControlTaskbarState();
UInt64 GetLastActiveControlTaskbarProgress();
TaskbarState TaskbarState{ get; };
FindTargetWindowResult FindTargetWindow(String[] args);

View file

@ -0,0 +1,42 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "LanguageProfileNotifier.h"
using namespace winrt::TerminalApp::implementation;
LanguageProfileNotifier::LanguageProfileNotifier(std::function<void()>&& callback) :
_callback{ std::move(callback) },
_currentKeyboardLayout{ GetKeyboardLayout(0) }
{
const auto manager = wil::CoCreateInstance<ITfThreadMgr>(CLSID_TF_ThreadMgr);
_source = manager.query<ITfSource>();
if (FAILED(_source->AdviseSink(IID_ITfInputProcessorProfileActivationSink, static_cast<ITfInputProcessorProfileActivationSink*>(this), &_cookie)))
{
_cookie = TF_INVALID_COOKIE;
THROW_LAST_ERROR();
}
}
LanguageProfileNotifier::~LanguageProfileNotifier()
{
if (_cookie != TF_INVALID_COOKIE)
{
_source->UnadviseSink(_cookie);
}
}
STDMETHODIMP LanguageProfileNotifier::OnActivated(DWORD /*dwProfileType*/, LANGID /*langid*/, REFCLSID /*clsid*/, REFGUID /*catid*/, REFGUID /*guidProfile*/, HKL hkl, DWORD /*dwFlags*/)
{
if (hkl && hkl != _currentKeyboardLayout)
{
_currentKeyboardLayout = hkl;
try
{
_callback();
}
CATCH_RETURN();
}
return S_OK;
}

View file

@ -0,0 +1,21 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
namespace winrt::TerminalApp::implementation
{
class LanguageProfileNotifier : public winrt::implements<LanguageProfileNotifier, ITfInputProcessorProfileActivationSink>
{
public:
explicit LanguageProfileNotifier(std::function<void()>&& callback);
~LanguageProfileNotifier();
STDMETHODIMP OnActivated(DWORD dwProfileType, LANGID langid, REFCLSID clsid, REFGUID catid, REFGUID guidProfile, HKL hkl, DWORD dwFlags);
private:
std::function<void()> _callback;
wil::com_ptr<ITfSource> _source;
DWORD _cookie = TF_INVALID_COOKIE;
HKL _currentKeyboardLayout;
};
}

View file

@ -2548,6 +2548,29 @@ bool Pane::ContainsReadOnly() const
return _IsLeaf() ? _control.ReadOnly() : (_firstChild->ContainsReadOnly() || _secondChild->ContainsReadOnly());
}
// Method Description:
// - If we're a parent, place the taskbar state for all our leaves into the
// provided vector.
// - If we're a leaf, place our own state into the vector.
// Arguments:
// - states: a vector that will receive all the states of all leaves in the tree
// Return Value:
// - <none>
void Pane::CollectTaskbarStates(std::vector<winrt::TerminalApp::TaskbarState>& states)
{
if (_IsLeaf())
{
auto tbState{ winrt::make<winrt::TerminalApp::implementation::TaskbarState>(_control.TaskbarState(),
_control.TaskbarProgress()) };
states.push_back(tbState);
}
else
{
_firstChild->CollectTaskbarStates(states);
_secondChild->CollectTaskbarStates(states);
}
}
DEFINE_EVENT(Pane, GotFocus, _GotFocusHandlers, winrt::delegate<std::shared_ptr<Pane>>);
DEFINE_EVENT(Pane, LostFocus, _LostFocusHandlers, winrt::delegate<std::shared_ptr<Pane>>);
DEFINE_EVENT(Pane, PaneRaiseBell, _PaneRaiseBellHandlers, winrt::Windows::Foundation::EventHandler<bool>);

View file

@ -21,6 +21,7 @@
#pragma once
#include "../../cascadia/inc/cppwinrt_utils.h"
#include "TaskbarState.h"
// fwdecl unittest classes
namespace TerminalAppLocalTests
@ -92,6 +93,8 @@ public:
bool ContainsReadOnly() const;
void CollectTaskbarStates(std::vector<winrt::TerminalApp::TaskbarState>& states);
WINRT_CALLBACK(Closed, winrt::Windows::Foundation::EventHandler<winrt::Windows::Foundation::IInspectable>);
DECLARE_EVENT(GotFocus, _GotFocusHandlers, winrt::delegate<std::shared_ptr<Pane>>);
DECLARE_EVENT(LostFocus, _LostFocusHandlers, winrt::delegate<std::shared_ptr<Pane>>);

View file

@ -665,6 +665,9 @@
<data name="FindText" xml:space="preserve">
<value>Find...</value>
</data>
<data name="SplitTabText" xml:space="preserve">
<value>Split Tab</value>
</data>
<data name="DropPathTabNewWindow.Text" xml:space="preserve">
<value>Open a new window with given starting directory</value>
</data>

View file

@ -56,7 +56,7 @@ namespace winrt::TerminalApp::implementation
// - existingConnection: An optional connection that is already established to a PTY
// for this tab to host instead of creating one.
// If not defined, the tab will create the connection.
void TerminalPage::_OpenNewTab(const NewTerminalArgs& newTerminalArgs, winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection existingConnection)
HRESULT TerminalPage::_OpenNewTab(const NewTerminalArgs& newTerminalArgs, winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection existingConnection)
try
{
const auto profileGuid{ _settings.GetProfileForArgs(newTerminalArgs) };
@ -89,8 +89,10 @@ namespace winrt::TerminalApp::implementation
TraceLoggingWideString(schemeName.data(), "SchemeName", "Color scheme set in the settings"),
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance));
return S_OK;
}
CATCH_LOG();
CATCH_RETURN();
// Method Description:
// - Creates a new tab with the given settings. If the tab bar is not being
@ -192,6 +194,16 @@ namespace winrt::TerminalApp::implementation
}
});
newTabImpl->SplitTabRequested([weakTab, weakThis{ get_weak() }]() {
auto page{ weakThis.get() };
auto tab{ weakTab.get() };
if (page && tab)
{
page->_SplitTab(*tab);
}
});
newTabImpl->FindRequested([weakTab, weakThis{ get_weak() }]() {
auto page{ weakThis.get() };
auto tab{ weakTab.get() };
@ -367,6 +379,20 @@ namespace winrt::TerminalApp::implementation
CATCH_LOG();
}
// Method Description:
// - Sets the specified tab as the focused tab and splits its active pane
// Arguments:
// - tab: tab to split
void TerminalPage::_SplitTab(TerminalTab& tab)
{
try
{
_SetFocusedTab(tab);
_SplitPane(tab, SplitState::Automatic, SplitType::Duplicate);
}
CATCH_LOG();
}
// Method Description:
// - Removes the tab (both TerminalControl and XAML) after prompting for approval
// Arguments:

View file

@ -0,0 +1,45 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "TaskbarState.h"
#include "TaskbarState.g.cpp"
namespace winrt::TerminalApp::implementation
{
// Default to unset, 0%.
TaskbarState::TaskbarState() :
TaskbarState(0, 0){};
TaskbarState::TaskbarState(const uint64_t dispatchTypesState, const uint64_t progressParam) :
_State{ dispatchTypesState },
_Progress{ progressParam } {}
uint64_t TaskbarState::Priority() const
{
// This seemingly nonsensical ordering is from
// https://docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-itaskbarlist3-setprogressstate#how-the-taskbar-button-chooses-the-progress-indicator-for-a-group
switch (_State)
{
case 0: // Clear = 0,
return 5;
case 1: // Set = 1,
return 3;
case 2: // Error = 2,
return 1;
case 3: // Indeterminate = 3,
return 4;
case 4: // Paused = 4
return 2;
}
// Here, return 6, to definitely be greater than all the other valid values.
// This should never really happen.
return 6;
}
int TaskbarState::ComparePriority(const winrt::TerminalApp::TaskbarState& lhs, const winrt::TerminalApp::TaskbarState& rhs)
{
return lhs.Priority() < rhs.Priority();
}
}

View file

@ -0,0 +1,34 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "inc/cppwinrt_utils.h"
#include "TaskbarState.g.h"
// fwdecl unittest classes
namespace TerminalAppLocalTests
{
class TabTests;
};
namespace winrt::TerminalApp::implementation
{
struct TaskbarState : TaskbarStateT<TaskbarState>
{
public:
TaskbarState();
TaskbarState(const uint64_t dispatchTypesState, const uint64_t progress);
static int ComparePriority(const winrt::TerminalApp::TaskbarState& lhs, const winrt::TerminalApp::TaskbarState& rhs);
uint64_t Priority() const;
WINRT_PROPERTY(uint64_t, State, 0);
WINRT_PROPERTY(uint64_t, Progress, 0);
};
}
namespace winrt::TerminalApp::factory_implementation
{
BASIC_FACTORY(TaskbarState);
}

View file

@ -0,0 +1,15 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
namespace TerminalApp
{
[default_interface] runtimeclass TaskbarState
{
TaskbarState();
TaskbarState(UInt64 dispatchTypesState, UInt64 progress);
UInt64 State{ get; };
UInt64 Progress{ get; };
UInt64 Priority { get; };
}
}

View file

@ -53,7 +53,7 @@
<Page Include="TabRowControl.xaml">
<SubType>Designer</SubType>
</Page>
<Page Include="TabHeaderControl.xaml">
<Page Include="TabHeaderControl.xaml">
<SubType>Designer</SubType>
</Page>
<Page Include="HighlightedTextControl.xaml">
@ -74,6 +74,7 @@
<ClInclude Include="Commandline.h" />
<ClInclude Include="CommandLinePaletteItem.h" />
<ClInclude Include="Jumplist.h" />
<ClInclude Include="LanguageProfileNotifier.h" />
<ClInclude Include="MinMaxCloseControl.h">
<DependentUpon>MinMaxCloseControl.xaml</DependentUpon>
</ClInclude>
@ -89,6 +90,9 @@
<DependentUpon>TabBase.idl</DependentUpon>
</ClInclude>
<ClInclude Include="TabPaletteItem.h" />
<ClInclude Include="TaskbarState.h">
<DependentUpon>TaskbarState.idl</DependentUpon>
</ClInclude>
<ClInclude Include="TerminalTab.h">
<DependentUpon>TerminalTab.idl</DependentUpon>
</ClInclude>
@ -112,7 +116,7 @@
<ClInclude Include="HighlightedTextControl.h">
<DependentUpon>HighlightedTextControl.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="HighlightedText.h" />
<ClInclude Include="HighlightedText.h" />
<ClInclude Include="ColorPickupFlyout.h">
<DependentUpon>ColorPickupFlyout.xaml</DependentUpon>
</ClInclude>
@ -139,7 +143,7 @@
<ClInclude Include="AppLogic.h">
<DependentUpon>AppLogic.idl</DependentUpon>
</ClInclude>
<ClInclude Include="Toast.h"/>
<ClInclude Include="Toast.h" />
</ItemGroup>
<!-- ========================= Cpp Files ======================== -->
<ItemGroup>
@ -149,6 +153,7 @@
<ClCompile Include="AppCommandlineArgs.cpp" />
<ClCompile Include="Commandline.cpp" />
<ClCompile Include="Jumplist.cpp" />
<ClCompile Include="LanguageProfileNotifier.cpp" />
<ClCompile Include="MinMaxCloseControl.cpp">
<DependentUpon>MinMaxCloseControl.xaml</DependentUpon>
</ClCompile>
@ -164,6 +169,9 @@
<DependentUpon>TabBase.idl</DependentUpon>
</ClCompile>
<ClCompile Include="TabPaletteItem.cpp" />
<ClCompile Include="TaskbarState.cpp">
<DependentUpon>TaskbarState.idl</DependentUpon>
</ClCompile>
<ClCompile Include="TerminalTab.cpp">
<DependentUpon>TerminalTab.idl</DependentUpon>
</ClCompile>
@ -195,7 +203,7 @@
<ClCompile Include="HighlightedTextControl.cpp">
<DependentUpon>HighlightedTextControl.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="HighlightedText.cpp" />
<ClCompile Include="HighlightedText.cpp" />
<ClCompile Include="ColorPickupFlyout.cpp">
<DependentUpon>ColorPickupFlyout.xaml</DependentUpon>
</ClCompile>
@ -256,6 +264,7 @@
</Midl>
<Midl Include="TabBase.idl" />
<Midl Include="TabPaletteItem.idl" />
<Midl Include="TaskbarState.idl" />
<Midl Include="TerminalTab.idl" />
<Midl Include="TerminalPage.idl">
<DependentUpon>TerminalPage.xaml</DependentUpon>
@ -280,7 +289,7 @@
<DependentUpon>HighlightedTextControl.xaml</DependentUpon>
<SubType>Code</SubType>
</Midl>
<Midl Include="HighlightedText.idl" />
<Midl Include="HighlightedText.idl" />
<Midl Include="ColorPickupFlyout.idl">
<DependentUpon>ColorPickupFlyout.xaml</DependentUpon>
<SubType>Code</SubType>

View file

@ -13,9 +13,6 @@
<ClCompile Include="Pane.cpp">
<Filter>pane</Filter>
</ClCompile>
<ClCompile Include="Tab.cpp">
<Filter>tab</Filter>
</ClCompile>
<ClCompile Include="Pane.LayoutSizeNode.cpp">
<Filter>pane</Filter>
</ClCompile>
@ -23,7 +20,6 @@
<ClCompile Include="Commandline.cpp" />
<ClCompile Include="ColorHelper.cpp" />
<ClCompile Include="DebugTapConnection.cpp" />
<ClCompile Include="Utils.cpp" />
<ClCompile Include="Jumplist.cpp" />
<ClCompile Include="Tab.cpp">
<Filter>tab</Filter>
@ -49,10 +45,10 @@
<ClCompile Include="HighlightedText.cpp">
<Filter>highlightedText</Filter>
</ClCompile>
<ClCompile Include="Toast.cpp" />
<ClCompile Include="LanguageProfileNotifier.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="Utils.h" />
<ClInclude Include="TerminalWarnings.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="App.base.h">
<Filter>app</Filter>
@ -60,9 +56,6 @@
<ClInclude Include="Pane.h">
<Filter>pane</Filter>
</ClInclude>
<ClInclude Include="Tab.h">
<Filter>tab</Filter>
</ClInclude>
<ClInclude Include="AppCommandlineArgs.h" />
<ClInclude Include="Commandline.h" />
<ClInclude Include="DebugTapConnection.h" />
@ -92,14 +85,13 @@
<ClInclude Include="HighlightedText.h">
<Filter>highlightedText</Filter>
</ClInclude>
<ClInclude Include="Toast.h" />
<ClInclude Include="LanguageProfileNotifier.h" />
</ItemGroup>
<ItemGroup>
<Midl Include="AppLogic.idl">
<Filter>app</Filter>
</Midl>
<Midl Include="ActionArgs.idl">
<Filter>settings</Filter>
</Midl>
<Midl Include="AppKeyBindings.idl">
<Filter>settings</Filter>
</Midl>
@ -107,9 +99,6 @@
<Filter>settings</Filter>
</Midl>
<Midl Include="IDirectKeyListener.idl" />
<Midl Include="ITab.idl">
<Filter>tab</Filter>
</Midl>
<Midl Include="SettingsTab.idl">
<Filter>tab</Filter>
</Midl>
@ -125,6 +114,9 @@
<Midl Include="TerminalTabStatus.idl">
<Filter>tab</Filter>
</Midl>
<Midl Include="PaletteItemTemplateSelector.idl" />
<Midl Include="TabBase.idl" />
<Midl Include="EmptyStringVisibilityConverter.idl" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
@ -160,9 +152,6 @@
<Midl Include="ActionPaletteItem.idl">
<Filter>commandPalette</Filter>
</Midl>
<Midl Include="FilterableListItem.idl">
<Filter>commandPalette</Filter>
</Midl>
<Midl Include="CommandLinePaletteItem.idl">
<Filter>commandPalette</Filter>
</Midl>

View file

@ -19,6 +19,8 @@
#include "RenameWindowRequestedArgs.g.cpp"
#include "../inc/WindowingBehavior.h"
#include <til/latch.h>
using namespace winrt;
using namespace winrt::Windows::Foundation::Collections;
using namespace winrt::Windows::UI::Xaml;
@ -253,16 +255,8 @@ namespace winrt::TerminalApp::implementation
path = path.parent_path();
}
std::wstring pathText = path.wstring();
// Handle edge case of "C:\\", seems like the "StartingDirectory" doesn't like path which ends with '\'
if (pathText.back() == L'\\')
{
pathText.erase(std::prev(pathText.end()));
}
NewTerminalArgs args;
args.StartingDirectory(winrt::hstring{ pathText });
args.StartingDirectory(winrt::hstring{ path.wstring() });
this->_OpenNewTerminal(args);
TraceLoggingWrite(
@ -356,34 +350,12 @@ namespace winrt::TerminalApp::implementation
winrt::Microsoft::Terminal::TerminalConnection::ConptyConnection::StartInboundListener();
}
// If we failed to start the listener, it will throw.
// We should fail fast here or the Terminal will be in a very strange state.
// We only start the listener if the Terminal was started with the COM server
// `-Embedding` flag and we make no tabs as a result.
// Therefore, if the listener cannot start itself up to make that tab with
// the inbound connection that caused the COM activation in the first place...
// we would be left with an empty terminal frame with no tabs.
// Instead, crash out so COM sees the server die and things unwind
// without a weird empty frame window.
// We don't want to fail fast here because if a peasant has some trouble with
// starting the listener, we don't want it to crash and take all its tabs down
// with it.
catch (...)
{
// However, we cannot always fail fast because of MSFT:33501832. Sometimes the COM catalog
// tears the state between old and new versions and fails here for that reason.
// As we're always becoming an inbound server in the monarch, even when COM didn't strictly
// ask us yet...we might just crash always.
// Instead... we're going to differentiate. If COM started us... we will fail fast
// so it sees the process die and falls back.
// If we were just starting normally as a Monarch and opportunistically listening for
// inbound connections... then we'll just log the failure and move on assuming
// the version state is torn and will fix itself whenever the packaging upgrade
// tasks decide to clean up.
if (_isEmbeddingInboundListener)
{
FAIL_FAST_CAUGHT_EXCEPTION();
}
else
{
LOG_CAUGHT_EXCEPTION();
}
LOG_CAUGHT_EXCEPTION();
}
}
}
@ -767,7 +739,7 @@ namespace winrt::TerminalApp::implementation
}
else
{
this->_OpenNewTab(newTerminalArgs);
LOG_IF_FAILED(this->_OpenNewTab(newTerminalArgs));
}
}
@ -1246,6 +1218,33 @@ namespace winrt::TerminalApp::implementation
return;
}
_SplitPane(*focusedTab, splitType, splitMode, splitSize, newTerminalArgs);
}
// Method Description:
// - Split the focused pane of the given tab, either horizontally or vertically, and place the
// given TermControl into the newly created pane.
// - If splitType == SplitState::None, this method does nothing.
// Arguments:
// - tab: The tab that is going to be split.
// - splitType: one value from the TerminalApp::SplitState enum, indicating how the
// new pane should be split from its parent.
// - splitMode: value from TerminalApp::SplitType enum, indicating the profile to be used in the newly split pane.
// - newTerminalArgs: An object that may contain a blob of parameters to
// control which profile is created and with possible other
// configurations. See CascadiaSettings::BuildSettings for more details.
void TerminalPage::_SplitPane(TerminalTab& tab,
const SplitState splitType,
const SplitType splitMode,
const float splitSize,
const NewTerminalArgs& newTerminalArgs)
{
// Do nothing if we're requesting no split.
if (splitType == SplitState::None)
{
return;
}
try
{
TerminalSettingsCreateResult controlSettings{ nullptr };
@ -1254,12 +1253,12 @@ namespace winrt::TerminalApp::implementation
if (splitMode == SplitType::Duplicate)
{
std::optional<GUID> current_guid = focusedTab->GetFocusedProfile();
std::optional<GUID> current_guid = tab.GetFocusedProfile();
if (current_guid)
{
profileFound = true;
controlSettings = TerminalSettings::CreateWithProfileByID(_settings, current_guid.value(), *_bindings);
const auto workingDirectory = focusedTab->GetActiveTerminalControl().WorkingDirectory();
const auto workingDirectory = tab.GetActiveTerminalControl().WorkingDirectory();
const auto validWorkingDirectory = !workingDirectory.empty();
if (validWorkingDirectory)
{
@ -1295,10 +1294,10 @@ namespace winrt::TerminalApp::implementation
auto realSplitType = splitType;
if (realSplitType == SplitState::Automatic)
{
realSplitType = focusedTab->PreCalculateAutoSplit(availableSpace);
realSplitType = tab.PreCalculateAutoSplit(availableSpace);
}
const auto canSplit = focusedTab->PreCalculateCanSplit(realSplitType, splitSize, availableSpace);
const auto canSplit = tab.PreCalculateCanSplit(realSplitType, splitSize, availableSpace);
if (!canSplit)
{
return;
@ -1307,11 +1306,11 @@ namespace winrt::TerminalApp::implementation
auto newControl = _InitControl(controlSettings, controlConnection);
// Hookup our event handlers to the new terminal
_RegisterTerminalEvents(newControl, *focusedTab);
_RegisterTerminalEvents(newControl, tab);
_UnZoomIfNeeded();
focusedTab->SplitPane(realSplitType, splitSize, realGuid, newControl);
tab.SplitPane(realSplitType, splitSize, realGuid, newControl);
}
CATCH_LOG();
}
@ -2078,29 +2077,35 @@ namespace winrt::TerminalApp::implementation
}
// Method Description:
// - Gets the taskbar state value from the last active control
// - Get the combined taskbar state for the page. This is the combination of
// all the states of all the tabs, which are themselves a combination of
// all their panes. Taskbar states are given a priority based on the rules
// in:
// https://docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-itaskbarlist3-setprogressstate
// under "How the Taskbar Button Chooses the Progress Indicator for a Group"
// Arguments:
// - <none>
// Return Value:
// - The taskbar state of the last active control
uint64_t TerminalPage::GetLastActiveControlTaskbarState()
// - A TaskbarState object representing the combined taskbar state and
// progress percentage of all our tabs.
winrt::TerminalApp::TaskbarState TerminalPage::TaskbarState() const
{
if (auto control{ _GetActiveControl() })
{
return control.TaskbarState();
}
return {};
}
auto state{ winrt::make<winrt::TerminalApp::implementation::TaskbarState>() };
// Method Description:
// - Gets the taskbar progress value from the last active control
// Return Value:
// - The taskbar progress of the last active control
uint64_t TerminalPage::GetLastActiveControlTaskbarProgress()
{
if (auto control{ _GetActiveControl() })
for (const auto& tab : _tabs)
{
return control.TaskbarProgress();
if (auto tabImpl{ _GetTerminalTabImpl(tab) })
{
auto tabState{ tabImpl->GetCombinedTaskbarState() };
// lowest priority wins
if (tabState.Priority() < state.Priority())
{
state = tabState;
}
}
}
return {};
return state;
}
// Method Description:
@ -2386,13 +2391,38 @@ namespace winrt::TerminalApp::implementation
return _isAlwaysOnTop;
}
void TerminalPage::_OnNewConnection(winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection connection)
HRESULT TerminalPage::_OnNewConnection(winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection connection)
{
// TODO: GH 9458 will give us more context so we can try to choose a better profile.
_OpenNewTab(nullptr, connection);
// We need to be on the UI thread in order for _OpenNewTab to run successfully.
// HasThreadAccess will return true if we're currently on a UI thread and false otherwise.
// When we're on a COM thread, we'll need to dispatch the calls to the UI thread
// and wait on it hence the locking mechanism.
if (Dispatcher().HasThreadAccess())
{
// TODO: GH 9458 will give us more context so we can try to choose a better profile.
auto hr = _OpenNewTab(nullptr, connection);
// Request a summon of this window to the foreground
_SummonWindowRequestedHandlers(*this, nullptr);
// Request a summon of this window to the foreground
_SummonWindowRequestedHandlers(*this, nullptr);
return hr;
}
else
{
til::latch latch{ 1 };
HRESULT finalVal = S_OK;
Dispatcher().RunAsync(CoreDispatcherPriority::Normal, [&]() {
finalVal = _OpenNewTab(nullptr, connection);
_SummonWindowRequestedHandlers(*this, nullptr);
latch.count_down();
});
latch.wait();
return finalVal;
}
}
// Method Description:

View file

@ -85,8 +85,7 @@ namespace winrt::TerminalApp::implementation
winrt::TerminalApp::IDialogPresenter DialogPresenter() const;
void DialogPresenter(winrt::TerminalApp::IDialogPresenter dialogPresenter);
uint64_t GetLastActiveControlTaskbarState();
uint64_t GetLastActiveControlTaskbarProgress();
winrt::TerminalApp::TaskbarState TaskbarState() const;
void ShowKeyboardServiceWarning();
winrt::hstring KeyboardServiceDisabledText();
@ -188,7 +187,7 @@ namespace winrt::TerminalApp::implementation
void _CreateNewTabFlyout();
void _OpenNewTabDropdown();
void _OpenNewTab(const Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs, winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection existingConnection = nullptr);
HRESULT _OpenNewTab(const Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs, winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection existingConnection = nullptr);
void _CreateNewTabFromSettings(GUID profileGuid, const Microsoft::Terminal::Settings::Model::TerminalSettingsCreateResult& settings, winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection existingConnection = nullptr);
winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection _CreateConnectionFromSettings(GUID profileGuid, Microsoft::Terminal::Settings::Model::TerminalSettings settings);
@ -219,6 +218,8 @@ namespace winrt::TerminalApp::implementation
void _DuplicateFocusedTab();
void _DuplicateTab(const TerminalTab& tab);
void _SplitTab(TerminalTab& tab);
winrt::Windows::Foundation::IAsyncAction _HandleCloseTabRequested(winrt::TerminalApp::TabBase tab);
void _CloseTabAtIndex(uint32_t index);
void _RemoveTab(const winrt::TerminalApp::TabBase& tab);
@ -254,6 +255,11 @@ namespace winrt::TerminalApp::implementation
const Microsoft::Terminal::Settings::Model::SplitType splitMode = Microsoft::Terminal::Settings::Model::SplitType::Manual,
const float splitSize = 0.5f,
const Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs = nullptr);
void _SplitPane(TerminalTab& tab,
const Microsoft::Terminal::Settings::Model::SplitState splitType,
const Microsoft::Terminal::Settings::Model::SplitType splitMode = Microsoft::Terminal::Settings::Model::SplitType::Manual,
const float splitSize = 0.5f,
const Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs = nullptr);
void _ResizePane(const Microsoft::Terminal::Settings::Model::ResizeDirection& direction);
void _ToggleSplitOrientation();
@ -337,7 +343,7 @@ namespace winrt::TerminalApp::implementation
winrt::Microsoft::Terminal::Settings::Model::Command _lastPreviewedCommand{ nullptr };
winrt::Microsoft::Terminal::Settings::Model::TerminalSettings _originalSettings{ nullptr };
void _OnNewConnection(winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection connection);
HRESULT _OnNewConnection(winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection connection);
void _HandleToggleInboundPty(const IInspectable& sender, const Microsoft::Terminal::Settings::Model::ActionEventArgs& args);
void _WindowRenamerActionClick(const IInspectable& sender, const IInspectable& eventArgs);

View file

@ -1,5 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import "TaskbarState.idl";
namespace TerminalApp
{
@ -42,8 +43,7 @@ namespace TerminalApp
void ShowKeyboardServiceWarning();
String KeyboardServiceDisabledText { get; };
UInt64 GetLastActiveControlTaskbarState();
UInt64 GetLastActiveControlTaskbarProgress();
TaskbarState TaskbarState{ get; };
event Windows.Foundation.TypedEventHandler<Object, String> TitleChanged;
event Windows.Foundation.TypedEventHandler<Object, LastTabClosedEventArgs> LastTabClosed;

View file

@ -177,10 +177,9 @@ namespace winrt::TerminalApp::implementation
{
lastFocusedControl.Focus(_focusState);
// Update our own progress state, and fire an event signaling
// Update our own progress state. This will fire an event signaling
// that our taskbar progress changed.
_UpdateProgressState();
_TaskbarProgressChangedHandlers(lastFocusedControl, nullptr);
}
// When we gain focus, remove the bell indicator if it is active
if (_tabStatus.BellIndicator())
@ -675,6 +674,26 @@ namespace winrt::TerminalApp::implementation
});
}
// Method Description:
// - Get the combined taskbar state for the tab. This is the combination of
// all the states of all our panes. Taskbar states are given a priority
// based on the rules in:
// https://docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-itaskbarlist3-setprogressstate
// under "How the Taskbar Button Chooses the Progress Indicator for a
// Group"
// Arguments:
// - <none>
// Return Value:
// - A TaskbarState object representing the combined taskbar state and
// progress percentage of all our panes.
winrt::TerminalApp::TaskbarState TerminalTab::GetCombinedTaskbarState() const
{
std::vector<winrt::TerminalApp::TaskbarState> states;
_rootPane->CollectTaskbarStates(states);
return states.empty() ? winrt::make<winrt::TerminalApp::implementation::TaskbarState>() :
*std::min_element(states.begin(), states.end(), TerminalApp::implementation::TaskbarState::ComparePriority);
}
// Method Description:
// - This should be called on the UI thread. If you don't, then it might
// silently do nothing.
@ -690,37 +709,39 @@ namespace winrt::TerminalApp::implementation
// - <none>
void TerminalTab::_UpdateProgressState()
{
if (const auto& activeControl{ GetActiveTerminalControl() })
{
const auto taskbarState = activeControl.TaskbarState();
// The progress of the control changed, but not necessarily the progress of the tab.
// Set the tab's progress ring to the active pane's progress
if (taskbarState > 0)
{
if (taskbarState == 3)
{
// 3 is the indeterminate state, set the progress ring as such
_tabStatus.IsProgressRingIndeterminate(true);
}
else
{
// any non-indeterminate state has a value, set the progress ring as such
_tabStatus.IsProgressRingIndeterminate(false);
const auto state{ GetCombinedTaskbarState() };
const auto progressValue = gsl::narrow<uint32_t>(activeControl.TaskbarProgress());
_tabStatus.ProgressValue(progressValue);
}
// Hide the tab icon (the progress ring is placed over it)
HideIcon(true);
_tabStatus.IsProgressRingActive(true);
const auto taskbarState = state.State();
// The progress of the control changed, but not necessarily the progress of the tab.
// Set the tab's progress ring to the active pane's progress
if (taskbarState > 0)
{
if (taskbarState == 3)
{
// 3 is the indeterminate state, set the progress ring as such
_tabStatus.IsProgressRingIndeterminate(true);
}
else
{
// Show the tab icon
HideIcon(false);
_tabStatus.IsProgressRingActive(false);
// any non-indeterminate state has a value, set the progress ring as such
_tabStatus.IsProgressRingIndeterminate(false);
const auto progressValue = gsl::narrow<uint32_t>(state.Progress());
_tabStatus.ProgressValue(progressValue);
}
// Hide the tab icon (the progress ring is placed over it)
HideIcon(true);
_tabStatus.IsProgressRingActive(true);
}
else
{
// Show the tab icon
HideIcon(false);
_tabStatus.IsProgressRingActive(false);
}
// fire an event signaling that our taskbar progress changed.
_TaskbarProgressChangedHandlers(nullptr, nullptr);
}
// Method Description:
@ -953,6 +974,23 @@ namespace winrt::TerminalApp::implementation
findMenuItem.Icon(findSymbol);
}
Controls::MenuFlyoutItem splitTabMenuItem;
{
// "Split Tab"
Controls::FontIcon splitTabSymbol;
splitTabSymbol.FontFamily(Media::FontFamily{ L"Segoe MDL2 Assets" });
splitTabSymbol.Glyph(L"\xF246"); // ViewDashboard
splitTabMenuItem.Click([weakThis](auto&&, auto&&) {
if (auto tab{ weakThis.get() })
{
tab->_SplitTabRequestedHandlers();
}
});
splitTabMenuItem.Text(RS_(L"SplitTabText"));
splitTabMenuItem.Icon(splitTabSymbol);
}
// Build the menu
Controls::MenuFlyout contextMenuFlyout;
Controls::MenuFlyoutSeparator menuSeparator;
@ -960,6 +998,7 @@ namespace winrt::TerminalApp::implementation
contextMenuFlyout.Items().Append(chooseColorMenuItem);
contextMenuFlyout.Items().Append(renameTabMenuItem);
contextMenuFlyout.Items().Append(duplicateTabMenuItem);
contextMenuFlyout.Items().Append(splitTabMenuItem);
contextMenuFlyout.Items().Append(menuSeparator);
contextMenuFlyout.Items().Append(findMenuItem);
contextMenuFlyout.Items().Append(menuSeparator2);
@ -1336,4 +1375,5 @@ namespace winrt::TerminalApp::implementation
DEFINE_EVENT(TerminalTab, TabRaiseVisualBell, _TabRaiseVisualBellHandlers, winrt::delegate<>);
DEFINE_EVENT(TerminalTab, DuplicateRequested, _DuplicateRequestedHandlers, winrt::delegate<>);
DEFINE_EVENT(TerminalTab, FindRequested, _FindRequestedHandlers, winrt::delegate<>);
DEFINE_EVENT(TerminalTab, SplitTabRequested, _SplitTabRequestedHandlers, winrt::delegate<>);
}

View file

@ -83,6 +83,7 @@ namespace winrt::TerminalApp::implementation
void TogglePaneReadOnly();
std::shared_ptr<Pane> GetActivePane() const;
winrt::TerminalApp::TaskbarState GetCombinedTaskbarState() const;
winrt::TerminalApp::TerminalTabStatus TabStatus()
{
@ -95,6 +96,7 @@ namespace winrt::TerminalApp::implementation
DECLARE_EVENT(TabRaiseVisualBell, _TabRaiseVisualBellHandlers, winrt::delegate<>);
DECLARE_EVENT(DuplicateRequested, _DuplicateRequestedHandlers, winrt::delegate<>);
DECLARE_EVENT(FindRequested, _FindRequestedHandlers, winrt::delegate<>);
DECLARE_EVENT(SplitTabRequested, _SplitTabRequestedHandlers, winrt::delegate<>);
TYPED_EVENT(TaskbarProgressChanged, IInspectable, IInspectable);
private:

View file

@ -66,6 +66,7 @@ TRACELOGGING_DECLARE_PROVIDER(g_hTerminalAppProvider);
#include <telemetry/ProjectTelemetry.h>
#include <TraceLoggingActivity.h>
#include <msctf.h>
#include <shellapi.h>
#include <shobjidl_core.h>

View file

@ -11,6 +11,8 @@ using namespace Microsoft::WRL;
static NewHandoffFunction _pfnHandoff = nullptr;
// The registration ID of the class object for clean up later
static DWORD g_cTerminalHandoffRegistration = 0;
// Mutex so we only do start/stop/establish one at a time.
static std::shared_mutex _mtx;
// Routine Description:
// - Starts listening for TerminalHandoff requests by registering
@ -19,9 +21,11 @@ static DWORD g_cTerminalHandoffRegistration = 0;
// - pfnHandoff - Function to callback when a handoff is received
// Return Value:
// - S_OK, E_NOT_VALID_STATE (start called when already started) or relevant COM registration error.
HRESULT CTerminalHandoff::s_StartListening(NewHandoffFunction pfnHandoff) noexcept
HRESULT CTerminalHandoff::s_StartListening(NewHandoffFunction pfnHandoff)
try
{
std::unique_lock lock{ _mtx };
RETURN_HR_IF(E_NOT_VALID_STATE, _pfnHandoff != nullptr);
const auto classFactory = Make<SimpleClassFactory<CTerminalHandoff>>();
@ -31,7 +35,7 @@ try
ComPtr<IUnknown> unk;
RETURN_IF_FAILED(classFactory.As(&unk));
RETURN_IF_FAILED(CoRegisterClassObject(__uuidof(CTerminalHandoff), unk.Get(), CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &g_cTerminalHandoffRegistration));
RETURN_IF_FAILED(CoRegisterClassObject(__uuidof(CTerminalHandoff), unk.Get(), CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE, &g_cTerminalHandoffRegistration));
_pfnHandoff = pfnHandoff;
@ -46,8 +50,10 @@ CATCH_RETURN()
// - <none>
// Return Value:
// - S_OK, E_NOT_VALID_STATE (stop called when not started), or relevant COM class revoke error
HRESULT CTerminalHandoff::s_StopListening() noexcept
HRESULT CTerminalHandoff::s_StopListening()
{
std::unique_lock lock{ _mtx };
RETURN_HR_IF_NULL(E_NOT_VALID_STATE, _pfnHandoff);
_pfnHandoff = nullptr;
@ -91,10 +97,19 @@ static HRESULT _duplicateHandle(const HANDLE in, HANDLE& out) noexcept
// - E_NOT_VALID_STATE if a event handler is not registered before calling. `::DuplicateHandle`
// error codes if we cannot manage to make our own copy of handles to retain. Or S_OK/error
// from the registered handler event function.
HRESULT CTerminalHandoff::EstablishPtyHandoff(HANDLE in, HANDLE out, HANDLE signal, HANDLE ref, HANDLE server, HANDLE client) noexcept
HRESULT CTerminalHandoff::EstablishPtyHandoff(HANDLE in, HANDLE out, HANDLE signal, HANDLE ref, HANDLE server, HANDLE client)
{
// Stash a local copy of _pfnHandoff before we stop listening.
auto localPfnHandoff = _pfnHandoff;
// Because we are REGCLS_SINGLEUSE... we need to `CoRevokeClassObject` after we handle this ONE call.
// COM does not automatically clean that up for us. We must do it.
s_StopListening();
std::unique_lock lock{ _mtx };
// Report an error if no one registered a handoff function before calling this.
RETURN_HR_IF_NULL(E_NOT_VALID_STATE, _pfnHandoff);
RETURN_HR_IF_NULL(E_NOT_VALID_STATE, localPfnHandoff);
// Duplicate the handles from what we received.
// The contract with COM specifies that any HANDLEs we receive from the caller belong
@ -108,5 +123,5 @@ HRESULT CTerminalHandoff::EstablishPtyHandoff(HANDLE in, HANDLE out, HANDLE sign
RETURN_IF_FAILED(_duplicateHandle(client, client));
// Call registered handler from when we started listening.
return _pfnHandoff(in, out, signal, ref, server, client);
return localPfnHandoff(in, out, signal, ref, server, client);
}

View file

@ -37,12 +37,12 @@ struct __declspec(uuid(__CLSID_CTerminalHandoff))
HANDLE signal,
HANDLE ref,
HANDLE server,
HANDLE client) noexcept override;
HANDLE client) override;
#pragma endregion
static HRESULT s_StartListening(NewHandoffFunction pfnHandoff) noexcept;
static HRESULT s_StopListening() noexcept;
static HRESULT s_StartListening(NewHandoffFunction pfnHandoff);
static HRESULT s_StopListening();
};
// Disable warnings from the CoCreatableClass macro as the value it provides for

View file

@ -23,6 +23,16 @@ using namespace winrt::Windows::Graphics::Display;
using namespace winrt::Windows::System;
using namespace winrt::Windows::ApplicationModel::DataTransfer;
// The minimum delay between updates to the scroll bar's values.
// The updates are throttled to limit power usage.
constexpr const auto ScrollBarUpdateInterval = std::chrono::milliseconds(8);
// The minimum delay between updating the TSF input control.
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);
namespace winrt::Microsoft::Terminal::Control::implementation
{
// Helper static function to ensure that all ambiguous-width glyphs are reported as narrow.
@ -94,6 +104,61 @@ namespace winrt::Microsoft::Terminal::Control::implementation
auto pfnTerminalTaskbarProgressChanged = std::bind(&ControlCore::_terminalTaskbarProgressChanged, this);
_terminal->TaskbarProgressChangedCallback(pfnTerminalTaskbarProgressChanged);
// Get our dispatcher. If we're hosted in-proc with XAML, this will get
// us the same dispatcher as TermControl::Dispatcher(). If we're out of
// proc, this'll return null. We'll need to instead make a new
// DispatcherQueue (on a new thread), so we can use that for throttled
// functions.
_dispatcher = winrt::Windows::System::DispatcherQueue::GetForCurrentThread();
if (!_dispatcher)
{
auto controller{ winrt::Windows::System::DispatcherQueueController::CreateOnDedicatedThread() };
_dispatcher = controller.DispatcherQueue();
}
// A few different events should be throttled, so they don't fire absolutely all the time:
// * _tsfTryRedrawCanvas: When the cursor position moves, we need to
// inform TSF, so it can move the canvas for the composition. We
// throttle this so that we're not hopping across the process boundary
// every time that the cursor moves.
// * _updatePatternLocations: When there's new output, or we scroll the
// viewport, we should re-check if there are any visible hyperlinks.
// But we don't really need to do this every single time text is
// output, we can limit this update to once every 500ms.
// * _updateScrollBar: Same idea as the TSF update - we don't _really_
// need to hop across the process boundary every time text is output.
// We can throttle this to once every 8ms, which will get us out of
// the way of the main output & rendering threads.
_tsfTryRedrawCanvas = std::make_shared<ThrottledFuncTrailing<>>(
_dispatcher,
TsfRedrawInterval,
[weakThis = get_weak()]() {
if (auto core{ weakThis.get() }; !core->_IsClosing())
{
core->_CursorPositionChangedHandlers(*core, nullptr);
}
});
_updatePatternLocations = std::make_shared<ThrottledFuncTrailing<>>(
_dispatcher,
UpdatePatternLocationsInterval,
[weakThis = get_weak()]() {
if (auto core{ weakThis.get() }; !core->_IsClosing())
{
core->UpdatePatternLocations();
}
});
_updateScrollBar = std::make_shared<ThrottledFuncTrailing<Control::ScrollPositionChangedArgs>>(
_dispatcher,
ScrollBarUpdateInterval,
[weakThis = get_weak()](const auto& update) {
if (auto core{ weakThis.get() }; !core->_IsClosing())
{
core->_ScrollPositionChangedHandlers(*core, update);
}
});
UpdateSettings(settings);
}
@ -739,6 +804,18 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return;
}
// Convert our new dimensions to characters
const auto viewInPixels = Viewport::FromDimensions({ 0, 0 },
{ static_cast<short>(size.cx), static_cast<short>(size.cy) });
const auto vp = _renderEngine->GetViewportInCharacters(viewInPixels);
const auto currentVP = _terminal->GetViewport();
// Don't actually resize if viewport dimensions didn't change
if (vp.Height() == currentVP.Height() && vp.Width() == currentVP.Width())
{
return;
}
_terminal->ClearSelection();
// Tell the dx engine that our window is now the new size.
@ -747,11 +824,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// Invalidate everything
_renderer->TriggerRedrawAll();
// Convert our new dimensions to characters
const auto viewInPixels = Viewport::FromDimensions({ 0, 0 },
{ static_cast<short>(size.cx), static_cast<short>(size.cy) });
const auto vp = _renderEngine->GetViewportInCharacters(viewInPixels);
// If this function succeeds with S_FALSE, then the terminal didn't
// actually change size. No need to notify the connection of this no-op.
const HRESULT hr = _terminal->UserResize({ vp.Width(), vp.Height() });
@ -1103,15 +1175,28 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// TODO GH#9617: refine locking around pattern tree
_terminal->ClearPatternTree();
_ScrollPositionChangedHandlers(*this,
winrt::make<ScrollPositionChangedArgs>(viewTop,
viewHeight,
bufferSize));
// Start the throttled update of our scrollbar.
auto update{ winrt::make<ScrollPositionChangedArgs>(viewTop,
viewHeight,
bufferSize) };
if (!_inUnitTests)
{
_updateScrollBar->Run(update);
}
else
{
_ScrollPositionChangedHandlers(*this, update);
}
// Additionally, start the throttled update of where our links are.
_updatePatternLocations->Run();
}
void ControlCore::_terminalCursorPositionChanged()
{
_CursorPositionChangedHandlers(*this, nullptr);
// When the buffer's cursor moves, start the throttled func to
// eventually dispatch a CursorPositionChanged event.
_tsfTryRedrawCanvas->Run();
}
void ControlCore::_terminalTaskbarProgressChanged()
@ -1221,8 +1306,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void ControlCore::Close()
{
if (!_closing.exchange(true))
if (!_IsClosing())
{
_closing = true;
// Stop accepting new output and state changes before we disconnect everything.
_connection.TerminalOutput(_connectionOutputEventToken);
_connectionStateChangedRevoker.revoke();
@ -1400,18 +1487,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
_terminal->Write(hstr);
// NOTE: We're raising an event here to inform the TermControl that
// output has been received, so it can queue up a throttled
// UpdatePatternLocations call. In the future, we should have the
// _updatePatternLocations ThrottledFunc internal to this class, and
// run on this object's dispatcher queue.
//
// We're not doing that quite yet, because the Core will eventually
// be out-of-proc from the UI thread, and won't be able to just use
// the UI thread as the dispatcher queue thread.
//
// See TODO: https://github.com/microsoft/terminal/projects/5#card-50760282
_ReceivedOutputHandlers(*this, nullptr);
// Start the throttled update of where our hyperlinks are.
_updatePatternLocations->Run();
}
}

View file

@ -168,7 +168,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
private:
bool _initializedTerminal{ false };
std::atomic<bool> _closing{ false };
bool _closing{ false };
TerminalConnection::ITerminalConnection _connection{ nullptr };
event_token _connectionOutputEventToken;
@ -206,6 +206,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
double _panelHeight{ 0 };
double _compositionScale{ 0 };
winrt::Windows::System::DispatcherQueue _dispatcher{ nullptr };
std::shared_ptr<ThrottledFuncTrailing<>> _tsfTryRedrawCanvas;
std::shared_ptr<ThrottledFuncTrailing<>> _updatePatternLocations;
std::shared_ptr<ThrottledFuncTrailing<Control::ScrollPositionChangedArgs>> _updateScrollBar;
winrt::fire_and_forget _asyncCloseConnection();
void _setFontSize(int fontSize);
@ -239,8 +244,24 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void _connectionOutputHandler(const hstring& hstr);
void _updateHoveredCell(const std::optional<til::point> terminalPosition);
inline bool _IsClosing() const noexcept
{
#ifndef NDEBUG
if (_dispatcher)
{
// _closing isn't atomic and may only be accessed from the main thread.
//
// Though, the unit tests don't actually run in TAEF's main
// thread, so we don't care when we're running in tests.
assert(_inUnitTests || _dispatcher.HasThreadAccess());
}
#endif
return _closing;
}
friend class ControlUnitTests::ControlCoreTests;
friend class ControlUnitTests::ControlInteractivityTests;
bool _inUnitTests{ false };
};
}

View file

@ -9,5 +9,6 @@ namespace Microsoft.Terminal.Control
interface IKeyBindings
{
Boolean TryKeyChord(KeyChord kc);
Boolean IsKeyChordExplicitlyUnbound(KeyChord kc);
}
}

View file

@ -33,7 +33,8 @@ using namespace winrt::Windows::ApplicationModel::DataTransfer;
constexpr const auto ScrollBarUpdateInterval = std::chrono::milliseconds(8);
// The minimum delay between updating the TSF input control.
constexpr const auto TsfRedrawInterval = std::chrono::milliseconds(100);
// This is already throttled primarily in the ControlCore, with a timeout of 100ms. We're adding another smaller one here, as the (potentially x-proc) call will come in off the UI thread
constexpr const auto TsfRedrawInterval = std::chrono::milliseconds(8);
// The minimum delay between updating the locations of regex patterns
constexpr const auto UpdatePatternLocationsInterval = std::chrono::milliseconds(500);
@ -64,10 +65,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_interactivity = winrt::make<implementation::ControlInteractivity>(settings, connection);
_core = _interactivity.Core();
// Use a manual revoker on the output event, so we can immediately stop
// worrying about it on destruction.
_coreOutputEventToken = _core.ReceivedOutput({ this, &TermControl::_coreReceivedOutput });
// These events might all be triggered by the connection, but that
// should be drained and closed before we complete destruction. So these
// are safe.
@ -104,37 +101,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
});
// Many of these ThrottledFunc's should be inside ControlCore. However,
// currently they depend on the Dispatcher() of the UI thread, which the
// Core eventually won't have access to. When we get to
// https://github.com/microsoft/terminal/projects/5#card-50760282
// then we'll move the applicable ones.
//
// These four throttled functions are triggered by terminal output and interact with the UI.
// Get our dispatcher. This will get us the same dispatcher as
// TermControl::Dispatcher().
auto dispatcher = winrt::Windows::System::DispatcherQueue::GetForCurrentThread();
// These three throttled functions are triggered by terminal output and interact with the UI.
// Since Close() is the point after which we are removed from the UI, but before the
// destructor has run, we MUST check control->_IsClosing() before actually doing anything.
_tsfTryRedrawCanvas = std::make_shared<ThrottledFuncTrailing<>>(
Dispatcher(),
TsfRedrawInterval,
[weakThis = get_weak()]() {
if (auto control{ weakThis.get() }; !control->_IsClosing())
{
control->TSFInputControl().TryRedrawCanvas();
}
});
_updatePatternLocations = std::make_shared<ThrottledFuncTrailing<>>(
Dispatcher(),
UpdatePatternLocationsInterval,
[weakThis = get_weak()]() {
if (auto control{ weakThis.get() }; !control->_IsClosing())
{
control->_core.UpdatePatternLocations();
}
});
_playWarningBell = std::make_shared<ThrottledFuncLeading>(
Dispatcher(),
dispatcher,
TerminalWarningBellInterval,
[weakThis = get_weak()]() {
if (auto control{ weakThis.get() }; !control->_IsClosing())
@ -144,7 +119,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
});
_updateScrollBar = std::make_shared<ThrottledFuncTrailing<ScrollBarUpdate>>(
Dispatcher(),
dispatcher,
ScrollBarUpdateInterval,
[weakThis = get_weak()](const auto& update) {
if (auto control{ weakThis.get() }; !control->_IsClosing())
@ -540,7 +515,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
// create a custom automation peer with this code pattern:
// (https://docs.microsoft.com/en-us/windows/uwp/design/accessibility/custom-automation-peers)
if (const auto& interactivityAutoPeer = _interactivity.OnCreateAutomationPeer())
if (const auto& interactivityAutoPeer{ _interactivity.OnCreateAutomationPeer() })
{
_automationPeer = winrt::make<implementation::TermControlAutomationPeer>(this, interactivityAutoPeer);
return _automationPeer;
@ -786,28 +761,39 @@ namespace winrt::Microsoft::Terminal::Control::implementation
(void)_TrySendKeyEvent(VK_MENU, scanCode, modifiers, false);
handled = true;
}
else if (vkey == VK_F7 && down)
else if ((vkey == VK_F7 || vkey == VK_SPACE) && down)
{
// Manually generate an F7 event into the key bindings or terminal.
// This is required as part of GH#638.
// Or do so for alt+space; only send to terminal when explicitly unbound
// That is part of #GH7125
auto bindings{ _settings.KeyBindings() };
bool isUnbound = false;
const KeyChord kc = {
modifiers.IsCtrlPressed(),
modifiers.IsAltPressed(),
modifiers.IsShiftPressed(),
modifiers.IsWinPressed(),
gsl::narrow_cast<WORD>(vkey),
0
};
if (bindings)
{
handled = bindings.TryKeyChord({
modifiers.IsCtrlPressed(),
modifiers.IsAltPressed(),
modifiers.IsShiftPressed(),
modifiers.IsWinPressed(),
VK_F7,
0,
});
handled = bindings.TryKeyChord(kc);
if (!handled)
{
isUnbound = bindings.IsKeyChordExplicitlyUnbound(kc);
}
}
if (!handled)
const bool sendToTerminal = vkey == VK_F7 || (vkey == VK_SPACE && isUnbound);
if (!handled && sendToTerminal)
{
// _TrySendKeyEvent pretends it didn't handle F7 for some unknown reason.
(void)_TrySendKeyEvent(VK_F7, scanCode, modifiers, true);
(void)_TrySendKeyEvent(gsl::narrow_cast<WORD>(vkey), scanCode, modifiers, true);
// GH#6438: Note that we're _not_ sending the key up here - that'll
// get passed through XAML to our KeyUp handler normally.
handled = true;
@ -1276,23 +1262,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
CATCH_LOG();
}
void TermControl::_coreReceivedOutput(const IInspectable& /*sender*/,
const IInspectable& /*args*/)
{
// Queue up a throttled UpdatePatternLocations call. In the future, we
// should have the _updatePatternLocations ThrottledFunc internal to
// ControlCore, and run on that object's dispatcher queue.
//
// We're not doing that quite yet, because the Core will eventually
// be out-of-proc from the UI thread, and won't be able to just use
// the UI thread as the dispatcher queue thread.
//
// THIS IS CALLED ON EVERY STRING OF TEXT OUTPUT TO THE TERMINAL. Think
// twice before adding anything here.
_updatePatternLocations->Run();
}
// Method Description:
// - Reset the font size of the terminal to its default size.
// Arguments:
@ -1330,8 +1299,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_updateScrollBar->ModifyPending([](auto& update) {
update.newValue.reset();
});
_updatePatternLocations->Run();
}
// Method Description:
@ -1665,7 +1632,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
update.newValue = args.ViewTop();
_updateScrollBar->Run(update);
_updatePatternLocations->Run();
}
// Method Description:
@ -1673,10 +1639,20 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// to be where the current cursor position is.
// Arguments:
// - N/A
void TermControl::_CursorPositionChanged(const IInspectable& /*sender*/,
const IInspectable& /*args*/)
winrt::fire_and_forget TermControl::_CursorPositionChanged(const IInspectable& /*sender*/,
const IInspectable& /*args*/)
{
_tsfTryRedrawCanvas->Run();
// Prior to GH#10187, this fired a trailing throttled func to update the
// TSF canvas only every 100ms. Now, the throttling occurs on the
// ControlCore side. If we're told to update the cursor position, we can
// just go ahead and do it.
// This can come in off the COM thread - hop back to the UI thread.
auto weakThis{ get_weak() };
co_await resume_foreground(Dispatcher());
if (auto control{ weakThis.get() }; !control->_IsClosing())
{
control->TSFInputControl().TryRedrawCanvas();
}
}
hstring TermControl::Title()
@ -1730,8 +1706,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
_closing = true;
_core.ReceivedOutput(_coreOutputEventToken);
_RestorePointerCursorHandlers(*this, nullptr);
// Disconnect the TSF input control so it doesn't receive EditContext events.
TSFInputControl().Close();
_autoScrollTimer.Stop();

View file

@ -153,8 +153,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
bool _focused{ false };
bool _initializedTerminal{ false };
std::shared_ptr<ThrottledFuncTrailing<>> _tsfTryRedrawCanvas;
std::shared_ptr<ThrottledFuncTrailing<>> _updatePatternLocations;
std::shared_ptr<ThrottledFuncLeading> _playWarningBell;
struct ScrollBarUpdate
@ -164,7 +162,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
double newMinimum;
double newViewportSize;
};
std::shared_ptr<ThrottledFuncTrailing<ScrollBarUpdate>> _updateScrollBar;
bool _isInternalScrollBarUpdate;
// Auto scroll occurs when user, while selecting, drags cursor outside
@ -181,8 +181,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
std::optional<Windows::UI::Xaml::DispatcherTimer> _cursorTimer;
std::optional<Windows::UI::Xaml::DispatcherTimer> _blinkTimer;
event_token _coreOutputEventToken;
winrt::Windows::UI::Xaml::Controls::SwapChainPanel::LayoutUpdated_revoker _layoutUpdatedRevoker;
inline bool _IsClosing() const noexcept
@ -233,7 +231,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
void _TerminalTabColorChanged(const std::optional<til::color> color);
void _ScrollPositionChanged(const IInspectable& sender, const Control::ScrollPositionChangedArgs& args);
void _CursorPositionChanged(const IInspectable& sender, const IInspectable& args);
winrt::fire_and_forget _CursorPositionChanged(const IInspectable& sender, const IInspectable& args);
bool _CapturePointer(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs const& e);
bool _ReleasePointerCapture(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs const& e);
@ -265,7 +263,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
const int fontHeight,
const bool isInitialChange);
winrt::fire_and_forget _coreTransparencyChanged(IInspectable sender, Control::TransparencyChangedEventArgs args);
void _coreReceivedOutput(const IInspectable& sender, const IInspectable& args);
void _coreRaisedNotice(const IInspectable& s, const Control::NoticeEventArgs& args);
void _coreWarningBell(const IInspectable& sender, const IInspectable& args);
};

View file

@ -594,14 +594,6 @@ bool Terminal::SendKeyEvent(const WORD vkey,
const auto isAltOnlyPressed = states.IsAltPressed() && !states.IsCtrlPressed();
// DON'T manually handle Alt+Space - the system will use this to bring up
// the system menu for restore, min/maximize, size, move, close.
// (This doesn't apply to Ctrl+Alt+Space.)
if (isAltOnlyPressed && vkey == VK_SPACE)
{
return false;
}
// By default Windows treats Ctrl+Alt as an alias for AltGr.
// When the altGrAliasing setting is set to false, this behaviour should be disabled.
//
@ -672,13 +664,6 @@ bool Terminal::SendMouseEvent(const COORD viewportPos, const unsigned int uiButt
// - false otherwise.
bool Terminal::SendCharEvent(const wchar_t ch, const WORD scanCode, const ControlKeyStates states)
{
// DON'T manually handle Alt+Space - the system will use this to bring up
// the system menu for restore, min/maximize, size, move, close.
if (ch == L' ' && states.IsAltPressed() && !states.IsCtrlPressed())
{
return false;
}
auto vkey = _TakeVirtualKeyFromLastKeyEvent(scanCode);
if (vkey == 0 && scanCode != 0)
{

View file

@ -16,7 +16,7 @@ try
_WriteBuffer(stringView);
return true;
}
CATCH_LOG_RETURN_FALSE()
CATCH_RETURN_FALSE()
bool Terminal::ExecuteChar(wchar_t wch) noexcept
try
@ -24,7 +24,7 @@ try
_WriteBuffer({ &wch, 1 });
return true;
}
CATCH_LOG_RETURN_FALSE()
CATCH_RETURN_FALSE()
TextAttribute Terminal::GetTextAttributes() const noexcept
{
@ -54,7 +54,7 @@ try
return true;
}
CATCH_LOG_RETURN_FALSE()
CATCH_RETURN_FALSE()
COORD Terminal::GetCursorPosition() noexcept
{
@ -75,7 +75,7 @@ try
_buffer->GetCursor().SetColor(color);
return true;
}
CATCH_LOG_RETURN_FALSE()
CATCH_RETURN_FALSE()
// Method Description:
// - Moves the cursor down one line, and possibly also to the leftmost column.
@ -101,7 +101,7 @@ try
return true;
}
CATCH_LOG_RETURN_FALSE()
CATCH_RETURN_FALSE()
// Method Description:
// - deletes count characters starting from the cursor's current position
@ -150,7 +150,7 @@ try
return true;
}
CATCH_LOG_RETURN_FALSE()
CATCH_RETURN_FALSE()
// Method Description:
// - Inserts count spaces starting from the cursor's current position, moving over the existing text
@ -205,7 +205,7 @@ try
return true;
}
CATCH_LOG_RETURN_FALSE()
CATCH_RETURN_FALSE()
bool Terminal::EraseCharacters(const size_t numChars) noexcept
try
@ -218,7 +218,7 @@ try
_buffer->Write(eraseIter, absoluteCursorPos);
return true;
}
CATCH_LOG_RETURN_FALSE()
CATCH_RETURN_FALSE()
// Method description:
// - erases a line of text, either from
@ -264,7 +264,7 @@ try
_buffer->Write(eraseIter, startPos, false);
return true;
}
CATCH_LOG_RETURN_FALSE()
CATCH_RETURN_FALSE()
// Method description:
// - erases text in the buffer in two ways depending on erase type
@ -348,7 +348,7 @@ try
return true;
}
CATCH_LOG_RETURN_FALSE()
CATCH_RETURN_FALSE()
bool Terminal::WarningBell() noexcept
try
@ -356,7 +356,7 @@ try
_pfnWarningBell();
return true;
}
CATCH_LOG_RETURN_FALSE()
CATCH_RETURN_FALSE()
bool Terminal::SetWindowTitle(std::wstring_view title) noexcept
try
@ -368,7 +368,7 @@ try
}
return true;
}
CATCH_LOG_RETURN_FALSE()
CATCH_RETURN_FALSE()
// Method Description:
// - Updates the value in the colortable at index tableIndex to the new color
@ -387,7 +387,7 @@ try
_buffer->GetRenderTarget().TriggerRedrawAll();
return true;
}
CATCH_LOG_RETURN_FALSE()
CATCH_RETURN_FALSE()
// Method Description:
// - Sets the cursor style to the given style.
@ -457,7 +457,7 @@ try
_buffer->GetRenderTarget().TriggerRedrawAll();
return true;
}
CATCH_LOG_RETURN_FALSE()
CATCH_RETURN_FALSE()
// Method Description:
// - Updates the default background color from a COLORREF, format 0x00BBGGRR.
@ -475,7 +475,7 @@ try
_buffer->GetRenderTarget().TriggerRedrawAll();
return true;
}
CATCH_LOG_RETURN_FALSE()
CATCH_RETURN_FALSE()
til::color Terminal::GetDefaultBackground() const noexcept
{
@ -509,7 +509,7 @@ try
_buffer->GetRenderTarget().TriggerRedrawAll();
return true;
}
CATCH_LOG_RETURN_FALSE()
CATCH_RETURN_FALSE()
bool Terminal::EnableVT200MouseMode(const bool enabled) noexcept
{
@ -591,7 +591,7 @@ try
return true;
}
CATCH_LOG_RETURN_FALSE()
CATCH_RETURN_FALSE()
// Method Description:
// - Updates the buffer's current text attributes to start a hyperlink

View file

@ -158,7 +158,6 @@
<!-- Converters & Misc. -->
<model:IconPathConverter x:Key="IconSourceConverter" />
<local:InvertedBooleanToVisibilityConverter x:Key="InvertedBooleanToVisibilityConverter" />
<SolidColorBrush x:Key="ActionContainerBackgroundEditing"
Color="{ThemeResource SystemListMediumColor}" />
<SolidColorBrush x:Key="ActionContainerBackground"
@ -195,7 +194,7 @@
<TextBlock Grid.Column="0"
Style="{StaticResource KeyBindingNameTextBlockStyle}"
Text="{x:Bind Name, Mode=OneWay}"
Visibility="{x:Bind IsInEditMode, Mode=OneWay, Converter={StaticResource InvertedBooleanToVisibilityConverter}}" />
Visibility="{x:Bind local:Converters.InvertedBooleanToVisibility(IsInEditMode), Mode=OneWay}" />
<!-- Edit Mode: Action Combo-box -->
<ComboBox x:Uid="Actions_ActionComboBox"
@ -211,7 +210,7 @@
HorizontalAlignment="Right"
VerticalAlignment="Center"
Style="{ThemeResource KeyChordBorderStyle}"
Visibility="{x:Bind IsInEditMode, Mode=OneWay, Converter={StaticResource InvertedBooleanToVisibilityConverter}}">
Visibility="{x:Bind local:Converters.InvertedBooleanToVisibility(IsInEditMode), Mode=OneWay}">
<TextBlock FontSize="14"
Style="{ThemeResource KeyChordTextBlockStyle}"
@ -303,7 +302,7 @@
Margin="8,0,0,0"
AutomationProperties.Name="{x:Bind DeleteButtonName}"
Style="{StaticResource EditButtonStyle}"
Visibility="{x:Bind IsNewlyAdded, Mode=OneWay, Converter={StaticResource InvertedBooleanToVisibilityConverter}}">
Visibility="{x:Bind local:Converters.InvertedBooleanToVisibility(IsNewlyAdded), Mode=OneWay}">
<Button.Content>
<FontIcon FontSize="{StaticResource EditButtonIconSize}"
Glyph="&#xE74D;" />

View file

@ -51,6 +51,19 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
public:
AppearanceViewModel(const Model::AppearanceConfig& appearance);
void SetFontWeightFromDouble(double fontWeight)
{
FontWeight(winrt::Microsoft::Terminal::Settings::Editor::Converters::DoubleToFontWeight(fontWeight));
}
void SetBackgroundImageOpacityFromPercentageValue(double percentageValue)
{
BackgroundImageOpacity(winrt::Microsoft::Terminal::Settings::Editor::Converters::PercentageValueToPercentage(percentageValue));
}
void SetBackgroundImagePath(winrt::hstring path)
{
BackgroundImagePath(path);
}
// background image
bool UseDesktopBGImage();
void UseDesktopBGImage(const bool useDesktop);

View file

@ -23,6 +23,10 @@ namespace Microsoft.Terminal.Settings.Editor
{
Boolean IsDefault;
void SetFontWeightFromDouble(Double fontWeight);
void SetBackgroundImageOpacityFromPercentageValue(Double percentageValue);
void SetBackgroundImagePath(String path);
Boolean UseDesktopBGImage;
Boolean BackgroundImageSettingsVisible { get; };
@ -68,5 +72,6 @@ namespace Microsoft.Terminal.Settings.Editor
Windows.Foundation.Collections.IObservableVector<Microsoft.Terminal.Settings.Editor.EnumEntry> FontWeightList { get; };
IInspectable CurrentFontFace { get; };
Windows.UI.Xaml.Controls.Slider BIOpacitySlider { get; };
}
}

View file

@ -34,16 +34,6 @@
<TextBlock FontFamily="{x:Bind Name}"
Text="{x:Bind LocalizedName}" />
</DataTemplate>
<local:ColorToBrushConverter x:Key="ColorToBrushConverter" />
<local:PercentageConverter x:Key="PercentageConverter" />
<local:PercentageSignConverter x:Key="PercentageSignConverter" />
<local:FontWeightConverter x:Key="FontWeightConverter" />
<local:InvertedBooleanToVisibilityConverter x:Key="InvertedBooleanToVisibilityConverter" />
<local:StringIsEmptyConverter x:Key="StringIsEmptyConverter" />
<local:PaddingConverter x:Key="PaddingConverter" />
<local:StringIsNotDesktopConverter x:Key="StringIsNotDesktopConverter" />
<local:DesktopWallpaperToEmptyStringConverter x:Key="DesktopWallpaperToEmptyStringConverter" />
</ResourceDictionary>
</UserControl.Resources>
@ -87,7 +77,7 @@
SelectedItem="{x:Bind CurrentFontFace, Mode=OneWay}"
SelectionChanged="FontFace_SelectionChanged"
Style="{StaticResource ComboBoxSettingStyle}"
Visibility="{x:Bind ShowAllFonts, Mode=OneWay, Converter={StaticResource InvertedBooleanToVisibilityConverter}}" />
Visibility="{x:Bind local:Converters.InvertedBooleanToVisibility(ShowAllFonts), Mode=OneWay}" />
<ComboBox ItemTemplate="{StaticResource FontFaceComboBoxItemTemplate}"
ItemsSource="{x:Bind SourceProfile.CompleteFontList, Mode=OneWay}"
SelectedItem="{x:Bind CurrentFontFace, Mode=OneWay}"
@ -144,7 +134,7 @@
Minimum="0"
TickFrequency="50"
TickPlacement="Outside"
Value="{x:Bind Appearance.FontWeight, Converter={StaticResource FontWeightConverter}, Mode=TwoWay}" />
Value="{x:Bind local:Converters.FontWeightToDouble(Appearance.FontWeight), BindBack=Appearance.SetFontWeightFromDouble, Mode=TwoWay}" />
<TextBlock Grid.Column="1"
Margin="10,0,0,0"
Style="{StaticResource SliderValueLabelStyle}"
@ -215,12 +205,12 @@
SettingOverrideSource="{x:Bind Appearance.BackgroundImagePathOverrideSource, Mode=OneWay}">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<TextBox IsEnabled="{x:Bind Appearance.BackgroundImagePath, Mode=OneWay, Converter={StaticResource StringIsNotDesktopConverter}}"
<TextBox IsEnabled="{x:Bind local:Converters.StringsAreNotEqual('desktopWallpaper', Appearance.BackgroundImagePath), Mode=OneWay}"
Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind Appearance.BackgroundImagePath, Mode=TwoWay, Converter={StaticResource DesktopWallpaperToEmptyStringConverter}}" />
Text="{x:Bind local:Converters.StringFallBackToEmptyString('desktopWallpaper', Appearance.BackgroundImagePath), Mode=TwoWay, BindBack=Appearance.SetBackgroundImagePath}" />
<Button x:Uid="Profile_BackgroundImageBrowse"
Click="BackgroundImage_Click"
IsEnabled="{x:Bind Appearance.BackgroundImagePath, Mode=OneWay, Converter={StaticResource StringIsNotDesktopConverter}}"
IsEnabled="{x:Bind local:Converters.StringsAreNotEqual('desktopWallpaper', Appearance.BackgroundImagePath), Mode=OneWay}"
Style="{StaticResource BrowseButtonStyle}" />
</StackPanel>
<CheckBox x:Name="UseDesktopImageCheckBox"
@ -431,10 +421,10 @@
</Grid.ColumnDefinitions>
<Slider x:Name="BIOpacitySlider"
Grid.Column="0"
Value="{x:Bind Appearance.BackgroundImageOpacity, Converter={StaticResource PercentageConverter}, Mode=TwoWay}" />
Value="{x:Bind local:Converters.PercentageToPercentageValue(Appearance.BackgroundImageOpacity), BindBack=Appearance.SetBackgroundImageOpacityFromPercentageValue, Mode=TwoWay}" />
<TextBlock Grid.Column="1"
Style="{StaticResource SliderValueLabelStyle}"
Text="{Binding ElementName=BIOpacitySlider, Path=Value, Mode=OneWay, Converter={StaticResource PercentageSignConverter}}" />
Text="{x:Bind local:Converters.AppendPercentageSign(BIOpacitySlider.Value), Mode=OneWay}" />
</Grid>
</local:SettingContainer>
</StackPanel>

View file

@ -1,33 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "ColorLightenConverter.h"
#include "ColorLightenConverter.g.cpp"
using namespace winrt::Windows;
using namespace winrt::Windows::UI;
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::UI::Text;
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
Foundation::IInspectable ColorLightenConverter::Convert(Foundation::IInspectable const& value,
Windows::UI::Xaml::Interop::TypeName const& /* targetType */,
Foundation::IInspectable const& /* parameter */,
hstring const& /* language */)
{
auto original = winrt::unbox_value_or<Color>(value, Color{ 255, 0, 0, 0 });
auto result = original;
result.A = 128; // halfway transparent
return winrt::box_value(result);
}
Foundation::IInspectable ColorLightenConverter::ConvertBack(Foundation::IInspectable const& /*value*/,
Windows::UI::Xaml::Interop::TypeName const& /* targetType */,
Foundation::IInspectable const& /*parameter*/,
hstring const& /* language */)
{
throw hresult_not_implemented();
}
}

View file

@ -1,9 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "ColorLightenConverter.g.h"
#include "../inc/cppwinrt_utils.h"
DECLARE_CONVERTER(winrt::Microsoft::Terminal::Settings::Editor, ColorLightenConverter);

View file

@ -60,7 +60,7 @@
<DataTemplate x:Key="ColorTableEntryTemplate"
x:DataType="local:ColorTableEntry">
<Button AutomationProperties.Name="{x:Bind Name}"
Background="{x:Bind Color, Converter={StaticResource ColorToBrushConverter}, Mode=OneWay}"
Background="{x:Bind local:Converters.ColorToBrush(Color), Mode=OneWay}"
Style="{StaticResource ColorButtonStyle}"
ToolTipService.ToolTip="{x:Bind Name}">
<Button.Resources>
@ -69,11 +69,11 @@
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Light">
<SolidColorBrush x:Key="ButtonBackgroundPointerOver"
Color="{x:Bind Color, Converter={StaticResource ColorLightenConverter}, Mode=OneWay}" />
Color="{x:Bind local:Converters.LightenColor(Color), Mode=OneWay}" />
</ResourceDictionary>
<ResourceDictionary x:Key="Dark">
<SolidColorBrush x:Key="ButtonBackgroundPointerOver"
Color="{x:Bind Color, Converter={StaticResource ColorLightenConverter}, Mode=OneWay}" />
Color="{x:Bind local:Converters.LightenColor(Color), Mode=OneWay}" />
</ResourceDictionary>
<!-- No High contrast dictionary, let's just leave that unchanged. -->
</ResourceDictionary.ThemeDictionaries>
@ -90,11 +90,6 @@
</Button>
</DataTemplate>
<local:ColorToBrushConverter x:Key="ColorToBrushConverter" />
<local:ColorToHexConverter x:Key="ColorToHexConverter" />
<local:InvertedBooleanToVisibilityConverter x:Key="InvertedBooleanToVisibilityConverter" />
<local:ColorLightenConverter x:Key="ColorLightenConverter" />
</ResourceDictionary>
</Page.Resources>
@ -106,7 +101,7 @@
<StackPanel Orientation="Horizontal">
<StackPanel Orientation="Horizontal"
Visibility="{x:Bind IsRenaming, Converter={StaticResource InvertedBooleanToVisibilityConverter}, Mode=OneWay}">
Visibility="{x:Bind local:Converters.InvertedBooleanToVisibility(IsRenaming), Mode=OneWay}">
<!-- Select a color scheme -->
<ComboBox x:Name="ColorSchemeComboBox"
ItemsSource="{x:Bind ColorSchemeList, Mode=OneWay}"

View file

@ -1,28 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "ColorToBrushConverter.h"
#include "ColorToBrushConverter.g.cpp"
using namespace winrt::Windows;
using namespace winrt::Windows::UI::Xaml;
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
Foundation::IInspectable ColorToBrushConverter::Convert(Foundation::IInspectable const& value,
Windows::UI::Xaml::Interop::TypeName const& /* targetType */,
Foundation::IInspectable const& /* parameter */,
hstring const& /* language */)
{
return winrt::box_value(Windows::UI::Xaml::Media::SolidColorBrush(winrt::unbox_value<Windows::UI::Color>(value)));
}
Foundation::IInspectable ColorToBrushConverter::ConvertBack(Foundation::IInspectable const& /*value*/,
Windows::UI::Xaml::Interop::TypeName const& /* targetType */,
Foundation::IInspectable const& /*parameter*/,
hstring const& /* language */)
{
throw hresult_not_implemented();
}
}

View file

@ -1,30 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "ColorToBrushConverter.g.h"
#include "Utils.h"
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
struct ColorToBrushConverter : ColorToBrushConverterT<ColorToBrushConverter>
{
ColorToBrushConverter() = default;
Windows::Foundation::IInspectable Convert(Windows::Foundation::IInspectable const& value,
Windows::UI::Xaml::Interop::TypeName const& targetType,
Windows::Foundation::IInspectable const& parameter,
hstring const& language);
Windows::Foundation::IInspectable ConvertBack(Windows::Foundation::IInspectable const& value,
Windows::UI::Xaml::Interop::TypeName const& targetType,
Windows::Foundation::IInspectable const& parameter,
hstring const& language);
};
}
namespace winrt::Microsoft::Terminal::Settings::Editor::factory_implementation
{
BASIC_FACTORY(ColorToBrushConverter);
}

View file

@ -1,30 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "ColorToHexConverter.h"
#include "ColorToHexConverter.g.cpp"
using namespace winrt::Windows;
using namespace winrt::Windows::UI::Xaml;
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
Foundation::IInspectable ColorToHexConverter::Convert(Foundation::IInspectable const& value,
Windows::UI::Xaml::Interop::TypeName const& /* targetType */,
Foundation::IInspectable const& /* parameter */,
hstring const& /* language */)
{
til::color color{ winrt::unbox_value<winrt::Windows::UI::Color>(value) };
auto hex = winrt::to_hstring(color.ToHexString().data());
return winrt::box_value(hex);
}
Foundation::IInspectable ColorToHexConverter::ConvertBack(Foundation::IInspectable const& /*value*/,
Windows::UI::Xaml::Interop::TypeName const& /* targetType */,
Foundation::IInspectable const& /*parameter*/,
hstring const& /* language */)
{
throw hresult_not_implemented();
}
}

View file

@ -1,30 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "ColorToHexConverter.g.h"
#include "Utils.h"
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
struct ColorToHexConverter : ColorToHexConverterT<ColorToHexConverter>
{
ColorToHexConverter() = default;
Windows::Foundation::IInspectable Convert(Windows::Foundation::IInspectable const& value,
Windows::UI::Xaml::Interop::TypeName const& targetType,
Windows::Foundation::IInspectable const& parameter,
hstring const& language);
Windows::Foundation::IInspectable ConvertBack(Windows::Foundation::IInspectable const& value,
Windows::UI::Xaml::Interop::TypeName const& targetType,
Windows::Foundation::IInspectable const& parameter,
hstring const& language);
};
}
namespace winrt::Microsoft::Terminal::Settings::Editor::factory_implementation
{
BASIC_FACTORY(ColorToHexConverter);
}

View file

@ -0,0 +1,106 @@
#include "pch.h"
#include "Converters.h"
#if __has_include("Converters.g.cpp")
#include "Converters.g.cpp"
#endif
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
winrt::hstring Converters::AppendPercentageSign(double value)
{
const auto number{ value };
return to_hstring((int)number) + L"%";
}
winrt::Windows::UI::Xaml::Media::SolidColorBrush Converters::ColorToBrush(winrt::Windows::UI::Color color)
{
return Windows::UI::Xaml::Media::SolidColorBrush(color);
}
winrt::Windows::UI::Text::FontWeight Converters::DoubleToFontWeight(double value)
{
return winrt::Windows::UI::Text::FontWeight{ base::ClampedNumeric<uint16_t>(value) };
}
double Converters::FontWeightToDouble(winrt::Windows::UI::Text::FontWeight fontWeight)
{
return fontWeight.Weight;
}
bool Converters::InvertBoolean(bool value)
{
return !value;
}
winrt::Windows::UI::Xaml::Visibility Converters::InvertedBooleanToVisibility(bool value)
{
return value ? winrt::Windows::UI::Xaml::Visibility::Collapsed : winrt::Windows::UI::Xaml::Visibility::Visible;
}
winrt::Windows::UI::Color Converters::LightenColor(winrt::Windows::UI::Color color)
{
color.A = 128; // halfway transparent
return color;
}
double Converters::MaxValueFromPaddingString(winrt::hstring paddingString)
{
const wchar_t singleCharDelim = L',';
std::wstringstream tokenStream(paddingString.c_str());
std::wstring token;
double maxVal = 0;
size_t* idx = nullptr;
// Get padding values till we run out of delimiter separated values in the stream
// Non-numeral values detected will default to 0
// std::getline will not throw exception unless flags are set on the wstringstream
// std::stod will throw invalid_argument exception if the input is an invalid double value
// std::stod will throw out_of_range exception if the input value is more than DBL_MAX
try
{
while (std::getline(tokenStream, token, singleCharDelim))
{
// std::stod internally calls wcstod which handles whitespace prefix (which is ignored)
// & stops the scan when first char outside the range of radix is encountered
// We'll be permissive till the extent that stod function allows us to be by default
// Ex. a value like 100.3#535w2 will be read as 100.3, but ;df25 will fail
const auto curVal = std::stod(token, idx);
if (curVal > maxVal)
{
maxVal = curVal;
}
}
}
catch (...)
{
// If something goes wrong, even if due to a single bad padding value, we'll return default 0 padding
maxVal = 0;
LOG_CAUGHT_EXCEPTION();
}
return maxVal;
}
int Converters::PercentageToPercentageValue(double value)
{
return base::ClampMul(value, 100u);
}
double Converters::PercentageValueToPercentage(double value)
{
return base::ClampDiv<double, double>(value, 100);
}
bool Converters::StringsAreNotEqual(winrt::hstring expected, winrt::hstring actual)
{
return expected != actual;
}
winrt::Windows::UI::Xaml::Visibility Converters::StringNotEmptyToVisibility(winrt::hstring value)
{
return value.empty() ? winrt::Windows::UI::Xaml::Visibility::Collapsed : winrt::Windows::UI::Xaml::Visibility::Visible;
}
winrt::hstring Converters::StringFallBackToEmptyString(winrt::hstring expected, winrt::hstring actual)
{
return expected == actual ? expected : L"";
}
}

View file

@ -0,0 +1,33 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "Converters.g.h"
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
struct Converters : ConvertersT<Converters>
{
static winrt::hstring AppendPercentageSign(double value);
static winrt::Windows::UI::Text::FontWeight DoubleToFontWeight(double value);
static winrt::Windows::UI::Xaml::Media::SolidColorBrush ColorToBrush(winrt::Windows::UI::Color color);
static double FontWeightToDouble(winrt::Windows::UI::Text::FontWeight fontWeight);
static bool InvertBoolean(bool value);
static winrt::Windows::UI::Xaml::Visibility InvertedBooleanToVisibility(bool value);
static winrt::Windows::UI::Color LightenColor(winrt::Windows::UI::Color color);
static double MaxValueFromPaddingString(winrt::hstring paddingString);
static int PercentageToPercentageValue(double value);
static double PercentageValueToPercentage(double value);
static bool StringsAreNotEqual(winrt::hstring expected, winrt::hstring actual);
static winrt::Windows::UI::Xaml::Visibility StringNotEmptyToVisibility(winrt::hstring value);
static winrt::hstring StringFallBackToEmptyString(winrt::hstring expected, winrt::hstring actual);
};
}
namespace winrt::Microsoft::Terminal::Settings::Editor::factory_implementation
{
struct Converters : ConvertersT<Converters, implementation::Converters>
{
};
}

View file

@ -4,63 +4,22 @@
namespace Microsoft.Terminal.Settings.Editor
{
runtimeclass ColorLightenConverter : [default] Windows.UI.Xaml.Data.IValueConverter
[bindable]
[default_interface] static runtimeclass Converters
{
ColorLightenConverter();
};
runtimeclass FontWeightConverter : [default] Windows.UI.Xaml.Data.IValueConverter
{
FontWeightConverter();
};
runtimeclass InvertedBooleanConverter : [default] Windows.UI.Xaml.Data.IValueConverter
{
InvertedBooleanConverter();
};
runtimeclass InvertedBooleanToVisibilityConverter : [default] Windows.UI.Xaml.Data.IValueConverter
{
InvertedBooleanToVisibilityConverter();
};
runtimeclass ColorToBrushConverter : [default] Windows.UI.Xaml.Data.IValueConverter
{
ColorToBrushConverter();
};
runtimeclass ColorToHexConverter : [default] Windows.UI.Xaml.Data.IValueConverter
{
ColorToHexConverter();
};
runtimeclass PercentageConverter : [default] Windows.UI.Xaml.Data.IValueConverter
{
PercentageConverter();
};
runtimeclass PercentageSignConverter : [default] Windows.UI.Xaml.Data.IValueConverter
{
PercentageSignConverter();
};
runtimeclass StringIsEmptyConverter : [default] Windows.UI.Xaml.Data.IValueConverter
{
StringIsEmptyConverter();
};
runtimeclass PaddingConverter : [default] Windows.UI.Xaml.Data.IValueConverter
{
PaddingConverter();
};
runtimeclass StringIsNotDesktopConverter : [default] Windows.UI.Xaml.Data.IValueConverter
{
StringIsNotDesktopConverter();
};
runtimeclass DesktopWallpaperToEmptyStringConverter : [default] Windows.UI.Xaml.Data.IValueConverter
{
DesktopWallpaperToEmptyStringConverter();
};
static String AppendPercentageSign(Double value);
static Windows.UI.Text.FontWeight DoubleToFontWeight(Double value);
static Windows.UI.Xaml.Media.SolidColorBrush ColorToBrush(Windows.UI.Color color);
static Double FontWeightToDouble(Windows.UI.Text.FontWeight fontWeight);
static Boolean InvertBoolean(Boolean value);
static Windows.UI.Xaml.Visibility InvertedBooleanToVisibility(Boolean value);
static Windows.UI.Color LightenColor(Windows.UI.Color color);
static Double MaxValueFromPaddingString(String paddingString);
static Int32 PercentageToPercentageValue(Double value);
static Double PercentageValueToPercentage(Double value);
static Boolean StringsAreNotEqual(String expected, String actual);
static Windows.UI.Xaml.Visibility StringNotEmptyToVisibility(String value);
static String StringFallBackToEmptyString(String expected, String actual);
}
}

View file

@ -1,32 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "FontWeightConverter.h"
#include "FontWeightConverter.g.cpp"
using namespace winrt::Windows;
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::UI::Text;
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
Foundation::IInspectable FontWeightConverter::Convert(Foundation::IInspectable const& value,
Windows::UI::Xaml::Interop::TypeName const& /* targetType */,
Foundation::IInspectable const& /* parameter */,
hstring const& /* language */)
{
const auto weight{ winrt::unbox_value<FontWeight>(value) };
return winrt::box_value<double>(weight.Weight);
}
Foundation::IInspectable FontWeightConverter::ConvertBack(Foundation::IInspectable const& value,
Windows::UI::Xaml::Interop::TypeName const& /* targetType */,
Foundation::IInspectable const& /*parameter*/,
hstring const& /* language */)
{
const auto sliderVal{ winrt::unbox_value<double>(value) };
FontWeight weight{ base::ClampedNumeric<uint16_t>(sliderVal) };
return winrt::box_value<FontWeight>(weight);
}
}

View file

@ -1,30 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "FontWeightConverter.g.h"
#include "Utils.h"
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
struct FontWeightConverter : FontWeightConverterT<FontWeightConverter>
{
FontWeightConverter() = default;
Windows::Foundation::IInspectable Convert(Windows::Foundation::IInspectable const& value,
Windows::UI::Xaml::Interop::TypeName const& targetType,
Windows::Foundation::IInspectable const& parameter,
hstring const& language);
Windows::Foundation::IInspectable ConvertBack(Windows::Foundation::IInspectable const& value,
Windows::UI::Xaml::Interop::TypeName const& targetType,
Windows::Foundation::IInspectable const& parameter,
hstring const& language);
};
}
namespace winrt::Microsoft::Terminal::Settings::Editor::factory_implementation
{
BASIC_FACTORY(FontWeightConverter);
}

View file

@ -21,8 +21,6 @@
x:DataType="local:EnumEntry">
<RadioButton Content="{x:Bind EnumName, Mode=OneWay}" />
</DataTemplate>
<local:InvertedBooleanConverter x:Key="InvertedBooleanConverter" />
</ResourceDictionary>
</Page.Resources>
@ -79,7 +77,7 @@
<!-- Disable Animations -->
<!-- NOTE: the UID is "DisablePaneAnimationsReversed" not "DisablePaneAnimations". See GH#9124 for more details. -->
<local:SettingContainer x:Uid="Globals_DisableAnimationsReversed">
<ToggleSwitch IsOn="{x:Bind State.Globals.DisableAnimations, Mode=TwoWay, Converter={StaticResource InvertedBooleanConverter}}" />
<ToggleSwitch IsOn="{x:Bind local:Converters.InvertBoolean(State.Globals.DisableAnimations), BindBack=State.Globals.SetInvertedDisableAnimationsValue, Mode=TwoWay}" />
</local:SettingContainer>
</StackPanel>
</ScrollViewer>

View file

@ -1,28 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "InvertedBooleanConverter.h"
#include "InvertedBooleanConverter.g.cpp"
using namespace winrt::Windows;
using namespace winrt::Windows::UI::Xaml;
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
Foundation::IInspectable InvertedBooleanConverter::Convert(Foundation::IInspectable const& value,
Windows::UI::Xaml::Interop::TypeName const& /* targetType */,
Foundation::IInspectable const& /* parameter */,
hstring const& /* language */)
{
return winrt::box_value(!winrt::unbox_value<bool>(value));
}
Foundation::IInspectable InvertedBooleanConverter::ConvertBack(Foundation::IInspectable const& value,
Windows::UI::Xaml::Interop::TypeName const& /* targetType */,
Foundation::IInspectable const& /*parameter*/,
hstring const& /* language */)
{
return winrt::box_value(!winrt::unbox_value<bool>(value));
}
}

View file

@ -1,9 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "InvertedBooleanConverter.g.h"
#include "../inc/cppwinrt_utils.h"
DECLARE_CONVERTER(winrt::Microsoft::Terminal::Settings::Editor, InvertedBooleanConverter);

View file

@ -1,28 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "InvertedBooleanToVisibilityConverter.h"
#include "InvertedBooleanToVisibilityConverter.g.cpp"
using namespace winrt::Windows;
using namespace winrt::Windows::UI::Xaml;
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
Foundation::IInspectable InvertedBooleanToVisibilityConverter::Convert(Foundation::IInspectable const& value,
Windows::UI::Xaml::Interop::TypeName const& /* targetType */,
Foundation::IInspectable const& /* parameter */,
hstring const& /* language */)
{
return winrt::box_value(winrt::unbox_value<bool>(value) ? Visibility::Collapsed : Visibility::Visible);
}
Foundation::IInspectable InvertedBooleanToVisibilityConverter::ConvertBack(Foundation::IInspectable const& /*value*/,
Windows::UI::Xaml::Interop::TypeName const& /* targetType */,
Foundation::IInspectable const& /*parameter*/,
hstring const& /* language */)
{
throw hresult_not_implemented();
}
}

View file

@ -1,9 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "InvertedBooleanToVisibilityConverter.g.h"
#include "../inc/cppwinrt_utils.h"
DECLARE_CONVERTER(winrt::Microsoft::Terminal::Settings::Editor, InvertedBooleanToVisibilityConverter);

View file

@ -42,41 +42,9 @@
<ClInclude Include="AddProfile.h">
<DependentUpon>AddProfile.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="ColorToBrushConverter.h">
<DependentUpon>Converters.idl</DependentUpon>
</ClInclude>
<ClInclude Include="ColorLightenConverter.h">
<DependentUpon>Converters.idl</DependentUpon>
</ClInclude>
<ClInclude Include="ColorToHexConverter.h">
<DependentUpon>Converters.idl</DependentUpon>
</ClInclude>
<ClInclude Include="FontWeightConverter.h">
<DependentUpon>Converters.idl</DependentUpon>
</ClInclude>
<ClInclude Include="InvertedBooleanConverter.h">
<DependentUpon>Converters.idl</DependentUpon>
</ClInclude>
<ClInclude Include="InvertedBooleanToVisibilityConverter.h">
<DependentUpon>Converters.idl</DependentUpon>
</ClInclude>
<ClInclude Include="KeyChordListener.h">
<DependentUpon>KeyChordListener.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="PercentageSignConverter.h">
<DependentUpon>Converters.idl</DependentUpon>
</ClInclude>
<ClInclude Include="StringIsEmptyConverter.h">
<DependentUpon>Converters.idl</DependentUpon>
</ClInclude>
<ClInclude Include="PaddingConverter.h">
<DependentUpon>Converters.idl</DependentUpon>
</ClInclude>
<ClInclude Include="StringIsNotDesktopConverter.h">
<DependentUpon>Converters.idl</DependentUpon>
</ClInclude>
<ClInclude Include="PercentageConverter.h">
<ClInclude Include="Converters.h">
<DependentUpon>Converters.idl</DependentUpon>
<SubType>Code</SubType>
</ClInclude>
<ClInclude Include="EnumEntry.h">
<DependentUpon>EnumEntry.idl</DependentUpon>
@ -91,6 +59,9 @@
<ClInclude Include="Interaction.h">
<DependentUpon>Interaction.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="KeyChordListener.h">
<DependentUpon>KeyChordListener.xaml</DependentUpon>
</ClInclude>
<ClInclude Include="Launch.h">
<DependentUpon>Launch.xaml</DependentUpon>
</ClInclude>
@ -171,41 +142,9 @@
<ClCompile Include="AddProfile.cpp">
<DependentUpon>AddProfile.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="ColorToBrushConverter.cpp">
<DependentUpon>Converters.idl</DependentUpon>
</ClCompile>
<ClCompile Include="ColorLightenConverter.cpp">
<DependentUpon>Converters.idl</DependentUpon>
</ClCompile>
<ClCompile Include="ColorToHexConverter.cpp">
<DependentUpon>Converters.idl</DependentUpon>
</ClCompile>
<ClCompile Include="FontWeightConverter.cpp">
<DependentUpon>Converters.idl</DependentUpon>
</ClCompile>
<ClCompile Include="InvertedBooleanConverter.cpp">
<DependentUpon>Converters.idl</DependentUpon>
</ClCompile>
<ClCompile Include="InvertedBooleanToVisibilityConverter.cpp">
<DependentUpon>Converters.idl</DependentUpon>
</ClCompile>
<ClCompile Include="KeyChordListener.cpp">
<DependentUpon>KeyChordListener.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="PercentageSignConverter.cpp">
<DependentUpon>Converters.idl</DependentUpon>
</ClCompile>
<ClCompile Include="StringIsEmptyConverter.cpp">
<DependentUpon>Converters.idl</DependentUpon>
</ClCompile>
<ClCompile Include="PaddingConverter.cpp">
<DependentUpon>Converters.idl</DependentUpon>
</ClCompile>
<ClCompile Include="StringIsNotDesktopConverter.cpp">
<DependentUpon>Converters.idl</DependentUpon>
</ClCompile>
<ClCompile Include="PercentageConverter.cpp">
<ClCompile Include="Converters.cpp">
<DependentUpon>Converters.idl</DependentUpon>
<SubType>Code</SubType>
</ClCompile>
<ClCompile Include="GlobalAppearance.cpp">
<DependentUpon>GlobalAppearance.xaml</DependentUpon>
@ -217,6 +156,9 @@
<ClCompile Include="Interaction.cpp">
<DependentUpon>Interaction.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="KeyChordListener.cpp">
<DependentUpon>KeyChordListener.xaml</DependentUpon>
</ClCompile>
<ClCompile Include="Launch.cpp">
<DependentUpon>Launch.xaml</DependentUpon>
</ClCompile>
@ -339,7 +281,6 @@
<Private>true</Private>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\TerminalSettingsModel\dll\Microsoft.Terminal.Settings.Model.vcxproj">
<Private>false</Private>
</ProjectReference>
@ -379,4 +320,4 @@
<Error Condition="!Exists('$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(OpenConsoleDir)\packages\Microsoft.UI.Xaml.2.5.0-prerelease.201202003\build\native\Microsoft.UI.Xaml.targets'))" />
</Target>
<Import Project="$(SolutionDir)build\rules\CollectWildcardResources.targets" />
</Project>
</Project>

View file

@ -10,16 +10,10 @@
<ClCompile Include="pch.cpp" />
<ClCompile Include="$(GeneratedFilesDir)module.g.cpp" />
<ClCompile Include="Utils.cpp" />
<ClCompile Include="PercentageSignConverter.cpp">
<Filter>Converters</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h" />
<ClInclude Include="Utils.h" />
<ClInclude Include="PercentageSignConverter.h">
<Filter>Converters</Filter>
</ClInclude>
<ClInclude Include="PreviewConnection.h" />
</ItemGroup>
<ItemGroup>
@ -49,9 +43,4 @@
<Page Include="ReadOnlyActions.xaml" />
<Page Include="KeyChordListener.xaml" />
</ItemGroup>
<ItemGroup>
<Filter Include="Converters">
<UniqueIdentifier>{00f725c8-41b4-40a8-995e-8ee2e49a4a4c}</UniqueIdentifier>
</Filter>
</ItemGroup>
</Project>
</Project>

View file

@ -1,65 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "PaddingConverter.h"
#include "PaddingConverter.g.cpp"
using namespace winrt::Windows;
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::UI::Text;
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
Foundation::IInspectable PaddingConverter::Convert(Foundation::IInspectable const& value,
Windows::UI::Xaml::Interop::TypeName const& /* targetType */,
Foundation::IInspectable const& /* parameter */,
hstring const& /* language */)
{
const auto& padding = winrt::unbox_value<hstring>(value);
const wchar_t singleCharDelim = L',';
std::wstringstream tokenStream(padding.c_str());
std::wstring token;
double maxVal = 0;
size_t* idx = nullptr;
// Get padding values till we run out of delimiter separated values in the stream
// Non-numeral values detected will default to 0
// std::getline will not throw exception unless flags are set on the wstringstream
// std::stod will throw invalid_argument exception if the input is an invalid double value
// std::stod will throw out_of_range exception if the input value is more than DBL_MAX
try
{
while (std::getline(tokenStream, token, singleCharDelim))
{
// std::stod internally calls wcstod which handles whitespace prefix (which is ignored)
// & stops the scan when first char outside the range of radix is encountered
// We'll be permissive till the extent that stod function allows us to be by default
// Ex. a value like 100.3#535w2 will be read as 100.3, but ;df25 will fail
const auto curVal = std::stod(token, idx);
if (curVal > maxVal)
{
maxVal = curVal;
}
}
}
catch (...)
{
// If something goes wrong, even if due to a single bad padding value, we'll return default 0 padding
maxVal = 0;
LOG_CAUGHT_EXCEPTION();
}
return winrt::box_value<double>(maxVal);
}
Foundation::IInspectable PaddingConverter::ConvertBack(Foundation::IInspectable const& value,
Windows::UI::Xaml::Interop::TypeName const& /* targetType */,
Foundation::IInspectable const& /*parameter*/,
hstring const& /* language */)
{
const auto padding{ winrt::unbox_value<double>(value) };
return winrt::box_value(winrt::to_hstring(padding));
}
}

View file

@ -1,9 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "PaddingConverter.g.h"
#include "../inc/cppwinrt_utils.h"
DECLARE_CONVERTER(winrt::Microsoft::Terminal::Settings::Editor, PaddingConverter);

View file

@ -1,32 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "PercentageConverter.h"
#include "PercentageConverter.g.cpp"
using namespace winrt::Windows;
using namespace winrt::Windows::UI::Xaml;
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
Foundation::IInspectable PercentageConverter::Convert(Foundation::IInspectable const& value,
Windows::UI::Xaml::Interop::TypeName const& /* targetType */,
Foundation::IInspectable const& /* parameter */,
hstring const& /* language */)
{
const auto decimal{ winrt::unbox_value<double>(value) };
const unsigned int number{ base::ClampMul(decimal, 100u) };
return winrt::box_value<double>(number);
}
Foundation::IInspectable PercentageConverter::ConvertBack(Foundation::IInspectable const& value,
Windows::UI::Xaml::Interop::TypeName const& /* targetType */,
Foundation::IInspectable const& /*parameter*/,
hstring const& /* language */)
{
const auto number{ winrt::unbox_value<double>(value) };
const auto decimal{ base::ClampDiv<double, double>(number, 100) };
return winrt::box_value<double>(decimal);
}
}

View file

@ -1,30 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "PercentageConverter.g.h"
#include "Utils.h"
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
struct PercentageConverter : PercentageConverterT<PercentageConverter>
{
PercentageConverter() = default;
Windows::Foundation::IInspectable Convert(Windows::Foundation::IInspectable const& value,
Windows::UI::Xaml::Interop::TypeName const& targetType,
Windows::Foundation::IInspectable const& parameter,
hstring const& language);
Windows::Foundation::IInspectable ConvertBack(Windows::Foundation::IInspectable const& value,
Windows::UI::Xaml::Interop::TypeName const& targetType,
Windows::Foundation::IInspectable const& parameter,
hstring const& language);
};
}
namespace winrt::Microsoft::Terminal::Settings::Editor::factory_implementation
{
BASIC_FACTORY(PercentageConverter);
}

View file

@ -20,6 +20,16 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
Model::TerminalSettings TermSettings() const;
void SetAcrylicOpacityPercentageValue(double value)
{
AcrylicOpacity(winrt::Microsoft::Terminal::Settings::Editor::Converters::PercentageValueToPercentage(value));
};
void SetPadding(double value)
{
Padding(to_hstring(value));
}
// starting directory
bool UseParentProcessDirectory();
void UseParentProcessDirectory(const bool useParent);

View file

@ -19,6 +19,9 @@ namespace Microsoft.Terminal.Settings.Editor
Windows.Foundation.Collections.IObservableVector<Font> MonospaceFontList { get; };
Microsoft.Terminal.Settings.Model.TerminalSettings TermSettings { get; };
void SetAcrylicOpacityPercentageValue(Double value);
void SetPadding(Double value);
Boolean CanDeleteProfile { get; };
Boolean IsBaseLayer;
Boolean UseParentProcessDirectory;
@ -105,5 +108,7 @@ namespace Microsoft.Terminal.Settings.Editor
IInspectable CurrentScrollState;
Windows.Foundation.Collections.IObservableVector<Microsoft.Terminal.Settings.Editor.EnumEntry> ScrollStateList { get; };
Windows.UI.Xaml.Controls.Slider AcrylicOpacitySlider { get; };
}
}

View file

@ -33,17 +33,6 @@
<TextBlock FontFamily="{x:Bind Name}"
Text="{x:Bind LocalizedName}" />
</DataTemplate>
<local:ColorToBrushConverter x:Key="ColorToBrushConverter" />
<local:PercentageConverter x:Key="PercentageConverter" />
<local:PercentageSignConverter x:Key="PercentageSignConverter" />
<local:FontWeightConverter x:Key="FontWeightConverter" />
<local:InvertedBooleanToVisibilityConverter x:Key="InvertedBooleanToVisibilityConverter" />
<local:StringIsEmptyConverter x:Key="StringIsEmptyConverter" />
<local:PaddingConverter x:Key="PaddingConverter" />
<local:StringIsNotDesktopConverter x:Key="StringIsNotDesktopConverter" />
<local:DesktopWallpaperToEmptyStringConverter x:Key="DesktopWallpaperToEmptyStringConverter" />
</ResourceDictionary>
</Page.Resources>
@ -78,7 +67,7 @@
-->
<local:SettingContainer x:Uid="Profile_Name"
Margin="0,0,0,24"
Visibility="{x:Bind State.Profile.IsBaseLayer, Mode=OneWay, Converter={StaticResource InvertedBooleanToVisibilityConverter}}">
Visibility="{x:Bind local:Converters.InvertedBooleanToVisibility(State.Profile.IsBaseLayer), Mode=OneWay}">
<TextBox Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind State.Profile.Name, Mode=TwoWay}" />
</local:SettingContainer>
@ -90,7 +79,7 @@
ClearSettingValue="{x:Bind State.Profile.ClearCommandline}"
HasSettingValue="{x:Bind State.Profile.HasCommandline, Mode=OneWay}"
SettingOverrideSource="{x:Bind State.Profile.CommandlineOverrideSource, Mode=OneWay}"
Visibility="{x:Bind State.Profile.IsBaseLayer, Mode=OneWay, Converter={StaticResource InvertedBooleanToVisibilityConverter}}">
Visibility="{x:Bind local:Converters.InvertedBooleanToVisibility(State.Profile.IsBaseLayer), Mode=OneWay}">
<StackPanel Orientation="Horizontal">
<TextBox Style="{StaticResource TextBoxSettingStyle}"
Text="{x:Bind State.Profile.Commandline, Mode=TwoWay}" />
@ -150,7 +139,7 @@
<!-- Hidden -->
<local:SettingContainer x:Uid="Profile_Hidden"
Visibility="{x:Bind State.Profile.IsBaseLayer, Mode=OneWay, Converter={StaticResource InvertedBooleanToVisibilityConverter}}">
Visibility="{x:Bind local:Converters.InvertedBooleanToVisibility(State.Profile.IsBaseLayer), Mode=OneWay}">
<ToggleSwitch IsOn="{x:Bind State.Profile.Hidden, Mode=TwoWay}" />
</local:SettingContainer>
@ -280,10 +269,10 @@
</Grid.ColumnDefinitions>
<Slider x:Name="AcrylicOpacitySlider"
Grid.Column="0"
Value="{x:Bind State.Profile.AcrylicOpacity, Converter={StaticResource PercentageConverter}, Mode=TwoWay}" />
Value="{x:Bind local:Converters.PercentageToPercentageValue(State.Profile.AcrylicOpacity), BindBack=State.Profile.SetAcrylicOpacityPercentageValue, Mode=TwoWay}" />
<TextBlock Grid.Column="1"
Style="{StaticResource SliderValueLabelStyle}"
Text="{Binding ElementName=AcrylicOpacitySlider, Path=Value, Mode=OneWay, Converter={StaticResource PercentageSignConverter}}" />
Text="{x:Bind local:Converters.AppendPercentageSign(AcrylicOpacitySlider.Value), Mode=OneWay}" />
</Grid>
</StackPanel>
</local:SettingContainer>
@ -307,7 +296,7 @@
</Grid.ColumnDefinitions>
<Slider x:Name="PaddingSlider"
Grid.Column="0"
Value="{x:Bind State.Profile.Padding, Converter={StaticResource PaddingConverter}, Mode=TwoWay}" />
Value="{x:Bind local:Converters.MaxValueFromPaddingString(State.Profile.Padding), BindBack=State.Profile.SetPadding, Mode=TwoWay}" />
<TextBlock Grid.Column="1"
Style="{StaticResource SliderValueLabelStyle}"
Text="{Binding ElementName=PaddingSlider, Path=Value, Mode=OneWay}" />
@ -333,7 +322,7 @@
Margin="32,0,0,0"
Click="CreateUnfocusedAppearance_Click"
Style="{StaticResource BaseButtonStyle}"
Visibility="{x:Bind State.Profile.HasUnfocusedAppearance, Mode=OneWay, Converter={StaticResource InvertedBooleanToVisibilityConverter}}">
Visibility="{x:Bind local:Converters.InvertedBooleanToVisibility(State.Profile.HasUnfocusedAppearance), Mode=OneWay}">
<Button.Content>
<FontIcon FontSize="{StaticResource StandardIconSize}"
Glyph="&#xE710;" />

View file

@ -17,9 +17,6 @@
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="CommonResources.xaml" />
</ResourceDictionary.MergedDictionaries>
<local:StringIsEmptyConverter x:Key="CommandKeyChordVisibilityConverter" />
<!--
Template for actions. This is _heavily_ copied from the command
palette, with modifications:

View file

@ -232,7 +232,7 @@
<comment>Header for a control to toggle if the app should always show the tabs (similar to a website browser).</comment>
</data>
<data name="Globals_AlwaysShowTabs.HelpText" xml:space="preserve">
<value>When unchecked, the tab bar will appear when a new tab is created.</value>
<value>When disabled, the tab bar will appear when a new tab is created.</value>
<comment>A description for what the "always show tabs" setting does. Presented near "Globals_AlwaysShowTabs.Header".</comment>
</data>
<data name="Globals_CopyOnSelect.Header" xml:space="preserve">
@ -272,7 +272,7 @@
<comment>Header for a control to toggle the "force full repaint" setting. When enabled, the app renders new content between screen frames.</comment>
</data>
<data name="Globals_ForceFullRepaint.HelpText" xml:space="preserve">
<value>When unchecked, the terminal will render only the updates to the screen between frames.</value>
<value>When disabled, the terminal will render only the updates to the screen between frames.</value>
<comment>A description for what the "force full repaint" setting does. Presented near "Globals_ForceFullRepaint.Header".</comment>
</data>
<data name="Globals_InitialCols.Header" xml:space="preserve">
@ -340,7 +340,7 @@
<comment>Header for a control to toggle whether the title bar should be shown or not. Changing this setting requires the user to relaunch the app.</comment>
</data>
<data name="Globals_ShowTitlebar.HelpText" xml:space="preserve">
<value>When unchecked, the title bar will appear above the tabs.</value>
<value>When disabled, the title bar will appear above the tabs.</value>
<comment>A description for what the "show titlebar" setting does. Presented near "Globals_ShowTitlebar.Header".</comment>
</data>
<data name="Globals_ShowTitleInTitlebar.Header" xml:space="preserve">
@ -348,7 +348,7 @@
<comment>Header for a control to toggle whether the terminal's title is shown as the application title, or not.</comment>
</data>
<data name="Globals_ShowTitleInTitlebar.HelpText" xml:space="preserve">
<value>When unchecked, the title bar will be 'Windows Terminal'.</value>
<value>When disabled, the title bar will be 'Windows Terminal'.</value>
<comment>A description for what the "show title in titlebar" setting does. Presented near "Globals_ShowTitleInTitlebar.Header".{Locked="Windows"}</comment>
</data>
<data name="Globals_SnapToGridOnResize.Header" xml:space="preserve">
@ -356,7 +356,7 @@
<comment>Header for a control to toggle whether the terminal snaps the window to the character grid when resizing, or not.</comment>
</data>
<data name="Globals_SnapToGridOnResize.HelpText" xml:space="preserve">
<value>When unchecked, the window will resize smoothly.</value>
<value>When disabled, the window will resize smoothly.</value>
<comment>A description for what the "snap to grid on resize" setting does. Presented near "Globals_SnapToGridOnResize.Header".</comment>
</data>
<data name="Globals_SoftwareRendering.Header" xml:space="preserve">
@ -364,7 +364,7 @@
<comment>Header for a control to toggle whether the terminal should use software to render content instead of the hardware.</comment>
</data>
<data name="Globals_SoftwareRendering.HelpText" xml:space="preserve">
<value>When checked, the terminal will use the software renderer (a.k.a. WARP) instead of the hardware one.</value>
<value>When enabled, the terminal will use the software renderer (a.k.a. WARP) instead of the hardware one.</value>
<comment>A description for what the "software rendering" setting does. Presented near "Globals_SoftwareRendering.Header".</comment>
</data>
<data name="Globals_StartOnUserLogin.Header" xml:space="preserve">
@ -372,7 +372,7 @@
<comment>Header for a control to toggle whether the app should launch when the user's machine starts up, or not.</comment>
</data>
<data name="Globals_StartOnUserLogin.HelpText" xml:space="preserve">
<value>When checked, this enables the launch of Windows Terminal at machine startup.</value>
<value>When enabled, this enables the launch of Windows Terminal at machine startup.</value>
<comment>A description for what the "start on user login" setting does. Presented near "Globals_StartOnUserLogin.Header".</comment>
</data>
<data name="Globals_AlwaysOnTop.Header" xml:space="preserve">
@ -480,7 +480,7 @@
<comment>Header for a control to toggle whether the app treats ctrl+alt as the AltGr (also known as the Alt Graph) modifier key found on keyboards. {Locked="AltGr"}</comment>
</data>
<data name="Profile_AltGrAliasing.HelpText" xml:space="preserve">
<value>By default Windows treats Ctrl+Alt as an alias for AltGr. When unchecked, this behavior will be disabled.</value>
<value>By default Windows treats Ctrl+Alt as an alias for AltGr. When disabled, this behavior will be disabled.</value>
<comment>A description for what the "AltGr aliasing" setting does. Presented near "Profile_AltGrAliasing.Header".</comment>
</data>
<data name="Profile_AntialiasingMode.Header" xml:space="preserve">
@ -700,7 +700,7 @@
<comment>Header for a control to toggle whether the profile is shown in a dropdown menu, or not.</comment>
</data>
<data name="Profile_Hidden.HelpText" xml:space="preserve">
<value>If checked, the profile will not appear in the list of profiles. This can be used to hide default profiles and dynamically generated profiles, while leaving them in your settings file.</value>
<value>If enabled, the profile will not appear in the list of profiles. This can be used to hide default profiles and dynamically generated profiles, while leaving them in your settings file.</value>
<comment>A description for what the "hidden" setting does. Presented near "Profile_Hidden".</comment>
</data>
<data name="Profile_HistorySize.Header" xml:space="preserve">
@ -736,7 +736,7 @@
<comment>Header for a control to toggle classic CRT display effects, which gives the terminal a retro look.</comment>
</data>
<data name="Profile_RetroTerminalEffect.HelpText" xml:space="preserve">
<value>When checked, enables retro terminal effects such as glowing text and scan lines.</value>
<value>When enabled, enables retro terminal effects such as glowing text and scan lines.</value>
<comment>A description for what the "retro terminal effects" setting does. Presented near "Profile_RetroTerminalEffect".</comment>
</data>
<data name="Profile_ScrollbarVisibility.Header" xml:space="preserve">
@ -772,7 +772,7 @@
<comment>A supplementary setting to the "starting directory" setting. "Parent" refers to the parent process of the current process.</comment>
</data>
<data name="Profile_StartingDirectoryUseParentCheckbox.[using:Windows.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">
<value>If checked, this profile will spawn in the directory from which Windows Terminal was launched.</value>
<value>If enabled, this profile will spawn in the directory from which Windows Terminal was launched.</value>
<comment>A description for what the supplementary "use parent process directory" setting does. Presented near "Profile_StartingDirectoryUseParentCheckbox".</comment>
</data>
<data name="Profile_SuppressApplicationTitle.Header" xml:space="preserve">
@ -808,7 +808,7 @@
<comment>A supplementary setting to the "background image" setting. When enabled, the OS desktop wallpaper is used as the background image. Presented near "Profile_BackgroundImage".</comment>
</data>
<data name="Profile_UseDesktopImage.[using:Windows.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">
<value>When checked, use the desktop wallpaper image as the background image for the terminal.</value>
<value>When enabled, use the desktop wallpaper image as the background image for the terminal.</value>
<comment>A description for what the supplementary "use desktop image" setting does. Presented near "Profile_UseDesktopImage".</comment>
</data>
<data name="Settings_ResetSettingsButton.Content" xml:space="preserve">
@ -1111,7 +1111,7 @@
<comment>A supplementary setting to the "font face" setting. Toggling this control updates the font face control to show all of the fonts installed.</comment>
</data>
<data name="Profile_FontFaceShowAllFonts.[using:Windows.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">
<value>If checked, show all installed fonts in the list above. Otherwise, only show the list of monospace fonts.</value>
<value>If enabled, show all installed fonts in the list above. Otherwise, only show the list of monospace fonts.</value>
<comment>A description for what the supplementary "show all fonts" setting does. Presented near "Profile_FontFaceShowAllFonts".</comment>
</data>
<data name="Profile_CreateUnfocusedAppearanceButton.[using:Windows.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">

View file

@ -1,30 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "StringIsEmptyConverter.h"
#include "StringIsEmptyConverter.g.cpp"
using namespace winrt::Windows;
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::UI::Text;
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
Foundation::IInspectable StringIsEmptyConverter::Convert(Foundation::IInspectable const& value,
Windows::UI::Xaml::Interop::TypeName const& /* targetType */,
Foundation::IInspectable const& /* parameter */,
hstring const& /* language */)
{
const auto& name = winrt::unbox_value_or<hstring>(value, L"");
return winrt::box_value(name.empty() ? Visibility::Collapsed : Visibility::Visible);
}
Foundation::IInspectable StringIsEmptyConverter::ConvertBack(Foundation::IInspectable const& /*value*/,
Windows::UI::Xaml::Interop::TypeName const& /* targetType */,
Foundation::IInspectable const& /*parameter*/,
hstring const& /* language */)
{
throw hresult_not_implemented();
}
}

View file

@ -1,9 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "StringIsEmptyConverter.g.h"
#include "../inc/cppwinrt_utils.h"
DECLARE_CONVERTER(winrt::Microsoft::Terminal::Settings::Editor, StringIsEmptyConverter);

View file

@ -1,50 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "StringIsNotDesktopConverter.h"
#include "StringIsNotDesktopConverter.g.cpp"
#include "DesktopWallpaperToEmptyStringConverter.g.cpp"
using namespace winrt::Windows;
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::UI::Text;
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
Foundation::IInspectable StringIsNotDesktopConverter::Convert(Foundation::IInspectable const& value,
Windows::UI::Xaml::Interop::TypeName const& /* targetType */,
Foundation::IInspectable const& /* parameter */,
hstring const& /* language */)
{
// Returns Visible if the string is _not_ "desktopWallpaper", else returns Collapsed
const auto& name = winrt::unbox_value_or<hstring>(value, L"");
return winrt::box_value(name != L"desktopWallpaper");
}
Foundation::IInspectable StringIsNotDesktopConverter::ConvertBack(Foundation::IInspectable const& /*value*/,
Windows::UI::Xaml::Interop::TypeName const& /* targetType */,
Foundation::IInspectable const& /*parameter*/,
hstring const& /* language */)
{
throw hresult_not_implemented();
}
Foundation::IInspectable DesktopWallpaperToEmptyStringConverter::Convert(Foundation::IInspectable const& value,
Windows::UI::Xaml::Interop::TypeName const& /* targetType */,
Foundation::IInspectable const& /* parameter */,
hstring const& /* language */)
{
// Returns the empty string if the string is "desktopWallpaper", else returns the original value.
const auto& name = winrt::unbox_value_or<hstring>(value, L"");
return winrt::box_value(name == L"desktopWallpaper" ? L"" : name);
}
Foundation::IInspectable DesktopWallpaperToEmptyStringConverter::ConvertBack(Foundation::IInspectable const& value,
Windows::UI::Xaml::Interop::TypeName const& /* targetType */,
Foundation::IInspectable const& /*parameter*/,
hstring const& /* language */)
{
return value;
}
}

View file

@ -1,11 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include "StringIsNotDesktopConverter.g.h"
#include "DesktopWallpaperToEmptyStringConverter.g.h"
#include "../inc/cppwinrt_utils.h"
DECLARE_CONVERTER(winrt::Microsoft::Terminal::Settings::Editor, StringIsNotDesktopConverter);
DECLARE_CONVERTER(winrt::Microsoft::Terminal::Settings::Editor, DesktopWallpaperToEmptyStringConverter);

View file

@ -118,7 +118,10 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
if (!StartingDirectory().empty())
{
ss << fmt::format(L"--startingDirectory \"{}\" ", StartingDirectory());
// If the directory ends in a '\', we need to add another one on so that the enclosing quote added
// afterwards isn't escaped
const auto trailingBackslashEscape = StartingDirectory().back() == L'\\' ? L"\\" : L"";
ss << fmt::format(L"--startingDirectory \"{}{}\" ", StartingDirectory(), trailingBackslashEscape);
}
if (!TabTitle().empty())

View file

@ -677,6 +677,32 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
}
}
// Method Description:
// - Determines whether the given key chord is explicitly unbound
// Arguments:
// - keys: the key chord to check
// Return value:
// - true if the keychord is explicitly unbound
// - false if either the keychord is bound, or not bound at all
bool ActionMap::IsKeyChordExplicitlyUnbound(Control::KeyChord const& keys) const
{
const auto modifiers = keys.Modifiers();
// The "keys" given to us can contain both a Vkey, as well as a ScanCode.
// For instance our UI code fills out a KeyChord with all available information.
// But our _KeyMap only contains KeyChords that contain _either_ a Vkey or ScanCode.
// Due to this we'll have to call _GetActionByKeyChordInternal twice.
if (auto vkey = keys.Vkey())
{
// We use the fact that the ..Internal call returns nullptr for explicitly unbound
// key chords, and nullopt for keychord that are not bound - it allows us to distinguish
// between unbound and lack of binding.
return nullptr == _GetActionByKeyChordInternal({ modifiers, vkey, 0 });
}
return nullptr == _GetActionByKeyChordInternal({ modifiers, 0, keys.ScanCode() });
}
// Method Description:
// - Retrieves the assigned command that can be invoked with the given key chord
// Arguments:

View file

@ -61,6 +61,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
// queries
Model::Command GetActionByKeyChord(Control::KeyChord const& keys) const;
bool IsKeyChordExplicitlyUnbound(Control::KeyChord const& keys) const;
Control::KeyChord GetKeyBindingForAction(ShortcutAction const& action) const;
Control::KeyChord GetKeyBindingForAction(ShortcutAction const& action, IActionArgs const& actionArgs) const;

View file

@ -8,6 +8,8 @@ namespace Microsoft.Terminal.Settings.Model
// This interface ensures that no changes are made to ActionMap
interface IActionMapView
{
Boolean IsKeyChordExplicitlyUnbound(Microsoft.Terminal.Control.KeyChord keys);
Command GetActionByKeyChord(Microsoft.Terminal.Control.KeyChord keys);
Microsoft.Terminal.Control.KeyChord GetKeyBindingForAction(ShortcutAction action);

View file

@ -60,6 +60,12 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
void UnparsedDefaultProfile(const hstring& value);
void ClearUnparsedDefaultProfile();
// TODO GH#9207: Remove this once we have a GlobalAppSettingsViewModel in TerminalSettingsEditor
void SetInvertedDisableAnimationsValue(bool invertedDisableAnimationsValue)
{
DisableAnimations(!invertedDisableAnimationsValue);
}
INHERITABLE_SETTING(Model::GlobalAppSettings, int32_t, InitialRows, DEFAULT_ROWS);
INHERITABLE_SETTING(Model::GlobalAppSettings, int32_t, InitialCols, DEFAULT_COLS);
INHERITABLE_SETTING(Model::GlobalAppSettings, bool, AlwaysShowTabs, true);

View file

@ -36,6 +36,9 @@ namespace Microsoft.Terminal.Settings.Model
[default_interface] runtimeclass GlobalAppSettings {
Guid DefaultProfile;
void SetInvertedDisableAnimationsValue(Boolean invertedDisableAnimationsValue);
INHERITABLE_SETTING(String, UnparsedDefaultProfile);
INHERITABLE_SETTING(Int32, InitialRows);

View file

@ -56,6 +56,16 @@ namespace ControlUnitTests
return { settings, conn };
}
winrt::com_ptr<Control::implementation::ControlCore> createCore(Control::IControlSettings settings,
TerminalConnection::ITerminalConnection conn)
{
Log::Comment(L"Create ControlCore object");
auto core = winrt::make_self<Control::implementation::ControlCore>(settings, conn);
core->_inUnitTests = true;
return core;
}
};
void ControlCoreTests::ComPtrSettings()
@ -71,8 +81,7 @@ namespace ControlUnitTests
{
auto [settings, conn] = _createSettingsAndConnection();
Log::Comment(L"Create ControlCore object");
auto core = winrt::make_self<Control::implementation::ControlCore>(*settings, *conn);
auto core = createCore(*settings, *conn);
VERIFY_IS_NOT_NULL(core);
}
@ -80,8 +89,7 @@ namespace ControlUnitTests
{
auto [settings, conn] = _createSettingsAndConnection();
Log::Comment(L"Create ControlCore object");
auto core = winrt::make_self<Control::implementation::ControlCore>(*settings, *conn);
auto core = createCore(*settings, *conn);
VERIFY_IS_NOT_NULL(core);
VERIFY_IS_FALSE(core->_initializedTerminal);
@ -99,8 +107,7 @@ namespace ControlUnitTests
settings->UseAcrylic(true);
settings->TintOpacity(0.5f);
Log::Comment(L"Create ControlCore object");
auto core = winrt::make_self<Control::implementation::ControlCore>(*settings, *conn);
auto core = createCore(*settings, *conn);
VERIFY_IS_NOT_NULL(core);
// A callback to make sure that we're raising TransparencyChanged events
@ -167,8 +174,7 @@ namespace ControlUnitTests
{
auto [settings, conn] = _createSettingsAndConnection();
Log::Comment(L"Create ControlCore object");
auto core = winrt::make_self<Control::implementation::ControlCore>(*settings, *conn);
auto core = createCore(*settings, *conn);
VERIFY_IS_NOT_NULL(core);
Log::Comment(L"Close the Core, like a TermControl would");
@ -190,8 +196,7 @@ namespace ControlUnitTests
// that you don't default to Cascadia*
settings->FontFace(L"Impact");
Log::Comment(L"Create ControlCore object");
auto core = winrt::make_self<Control::implementation::ControlCore>(*settings, *conn);
auto core = createCore(*settings, *conn);
VERIFY_IS_NOT_NULL(core);
VERIFY_ARE_EQUAL(L"Impact", std::wstring_view{ core->_actualFont.GetFaceName() });

View file

@ -73,6 +73,7 @@ namespace ControlUnitTests
auto interactivity = winrt::make_self<Control::implementation::ControlInteractivity>(settings, conn);
VERIFY_IS_NOT_NULL(interactivity);
auto core = interactivity->_core;
core->_inUnitTests = true;
VERIFY_IS_NOT_NULL(core);
return { core, interactivity };
@ -163,6 +164,10 @@ namespace ControlUnitTests
void ControlInteractivityTests::TestScrollWithMouse()
{
BEGIN_TEST_METHOD_PROPERTIES()
TEST_METHOD_PROPERTY(L"IsolationLevel", L"Method")
END_TEST_METHOD_PROPERTIES()
WEX::TestExecution::DisableVerifyExceptions disableVerifyExceptions{};
auto [settings, conn] = _createSettingsAndConnection();
@ -243,7 +248,7 @@ namespace ControlUnitTests
buttonState);
Log::Comment(NoThrowString().Format(L"internal scrollbar pos:%f", interactivity->_internalScrollbarPosition));
}
Log::Comment(L"Scrolling up more should do nothing");
Log::Comment(L"Scrolling down more should do nothing");
expectedTop = 21;
interactivity->MouseWheel(modifiers,
-WHEEL_DELTA,
@ -257,6 +262,10 @@ namespace ControlUnitTests
void ControlInteractivityTests::CreateSubsequentSelectionWithDragging()
{
BEGIN_TEST_METHOD_PROPERTIES()
TEST_METHOD_PROPERTY(L"IsolationLevel", L"Method")
END_TEST_METHOD_PROPERTIES()
// This is a test for GH#9725
WEX::TestExecution::DisableVerifyExceptions disableVerifyExceptions{};

View file

@ -47,6 +47,8 @@ Licensed under the MIT license.
// Manually include til after we include Windows.Foundation to give it winrt superpowers
#include "til.h"
#include "ThrottledFunc.h"
// Common includes for most tests:
#include "../../inc/argb.h"
#include "../../inc/conattrs.hpp"

View file

@ -29,7 +29,6 @@ namespace TerminalCoreUnitTests
};
TEST_METHOD(AltShiftKey);
TEST_METHOD(AltSpace);
TEST_METHOD(InvalidKeyEvent);
void _VerifyExpectedInput(std::wstring& actualInput)
@ -57,16 +56,6 @@ namespace TerminalCoreUnitTests
VERIFY_IS_TRUE(term.SendCharEvent(L'A', 0, ControlKeyStates::LeftAltPressed | ControlKeyStates::ShiftPressed));
}
void InputTest::AltSpace()
{
// Make sure we don't handle Alt+Space. The system will use this to
// bring up the system menu for restore, min/maximize, size, move,
// close
VERIFY_IS_FALSE(term.SendKeyEvent(L' ', 0, ControlKeyStates::LeftAltPressed, true));
VERIFY_IS_FALSE(term.SendKeyEvent(L' ', 0, ControlKeyStates::LeftAltPressed, false));
VERIFY_IS_FALSE(term.SendCharEvent(L' ', 0, ControlKeyStates::LeftAltPressed));
}
void InputTest::InvalidKeyEvent()
{
// Certain applications like AutoHotKey and its keyboard remapping feature,

View file

@ -24,7 +24,7 @@ public:
//
// After `func` was invoked the state is reset and this cycle is repeated again.
ThrottledFunc(
winrt::Windows::UI::Core::CoreDispatcher dispatcher,
winrt::Windows::System::DispatcherQueue dispatcher,
filetime_duration delay,
function func) :
_dispatcher{ std::move(dispatcher) },
@ -81,7 +81,7 @@ private:
{
if constexpr (leading)
{
_dispatcher.RunAsync(winrt::Windows::UI::Core::CoreDispatcherPriority::Normal, [weakSelf = this->weak_from_this()]() {
_dispatcher.TryEnqueue(winrt::Windows::System::DispatcherQueuePriority::Normal, [weakSelf = this->weak_from_this()]() {
if (auto self{ weakSelf.lock() })
{
try
@ -108,7 +108,7 @@ private:
}
else
{
_dispatcher.RunAsync(winrt::Windows::UI::Core::CoreDispatcherPriority::Normal, [weakSelf = this->weak_from_this()]() {
_dispatcher.TryEnqueue(winrt::Windows::System::DispatcherQueuePriority::Normal, [weakSelf = this->weak_from_this()]() {
if (auto self{ weakSelf.lock() })
{
try
@ -129,7 +129,7 @@ private:
}
FILETIME _delay;
winrt::Windows::UI::Core::CoreDispatcher _dispatcher;
winrt::Windows::System::DispatcherQueue _dispatcher;
function _func;
wil::unique_threadpool_timer _timer;

View file

@ -126,13 +126,14 @@ bool AppHost::OnDirectKeyEvent(const uint32_t vkey, const uint8_t scanCode, cons
// Arguments:
// - sender: not used
// - args: not used
void AppHost::SetTaskbarProgress(const winrt::Windows::Foundation::IInspectable& /*sender*/, const winrt::Windows::Foundation::IInspectable& /*args*/)
void AppHost::SetTaskbarProgress(const winrt::Windows::Foundation::IInspectable& /*sender*/,
const winrt::Windows::Foundation::IInspectable& /*args*/)
{
if (_logic)
{
const auto state = gsl::narrow_cast<size_t>(_logic.GetLastActiveControlTaskbarState());
const auto progress = gsl::narrow_cast<size_t>(_logic.GetLastActiveControlTaskbarProgress());
_window->SetTaskbarProgress(state, progress);
const auto state = _logic.TaskbarState();
_window->SetTaskbarProgress(gsl::narrow_cast<size_t>(state.State()),
gsl::narrow_cast<size_t>(state.Progress()));
}
}
@ -410,6 +411,7 @@ void AppHost::_HandleCreateWindow(const HWND hwnd, RECT proposedRect, LaunchMode
// Get the size of a window we'd need to host that client rect. This will
// add the titlebar space.
const til::size nonClientSize = _window->GetTotalNonClientExclusiveSize(dpix);
const til::rectangle nonClientFrame = _window->GetNonClientFrame(dpix);
adjustedWidth = islandWidth + nonClientSize.width<long>();
adjustedHeight = islandHeight + nonClientSize.height<long>();
@ -425,14 +427,18 @@ void AppHost::_HandleCreateWindow(const HWND hwnd, RECT proposedRect, LaunchMode
const til::size desktopDimensions{ gsl::narrow<short>(nearestMonitorInfo.rcWork.right - nearestMonitorInfo.rcWork.left),
gsl::narrow<short>(nearestMonitorInfo.rcWork.bottom - nearestMonitorInfo.rcWork.top) };
til::point origin{ (proposedRect.left),
// GH#10583 - Adjust the position of the rectangle to account for the size
// of the invisible borders on the left/right. We DON'T want to adjust this
// for the top here - the IslandWindow includes the titlebar in
// nonClientFrame.top, so adjusting for that would actually place the
// titlebar _off_ the monitor.
til::point origin{ (proposedRect.left + nonClientFrame.left<LONG>()),
(proposedRect.top) };
if (_logic.IsQuakeWindow())
{
// If we just use rcWork by itself, we'll fail to account for the invisible
// space reserved for the resize handles. So retrieve that size here.
const til::size ncSize{ _window->GetTotalNonClientExclusiveSize(dpix) };
const til::size availableSpace = desktopDimensions + nonClientSize;
origin = til::point{
@ -656,9 +662,6 @@ void AppHost::_BecomeMonarch(const winrt::Windows::Foundation::IInspectable& /*s
const winrt::Windows::Foundation::IInspectable& /*args*/)
{
_setupGlobalHotkeys();
// The monarch is just going to be THE listener for inbound connections.
_listenForInboundConnections();
}
void AppHost::_listenForInboundConnections()

View file

@ -616,12 +616,20 @@ void IslandWindow::SetContent(winrt::Windows::UI::Xaml::UIElement content)
}
// Method Description:
// - Gets the difference between window and client area size.
// - Get the dimensions of our non-client area, as a rect where each component
// represents that side.
// - The .left will be a negative number, to represent that the actual side of
// the non-client area is outside the border of our window. It's roughly 8px (
// * DPI scaling) to the left of the visible border.
// - The .right component will be positive, indicating that the nonclient border
// is in the positive-x direction from the edge of our client area.
// - This will also include our titlebar! It's in the nonclient area for us.
// Arguments:
// - dpi: dpi of a monitor on which the window is placed
// Return Value
// - The size difference
SIZE IslandWindow::GetTotalNonClientExclusiveSize(const UINT dpi) const noexcept
// - dpi: the scaling that we should use to calculate the border sizes.
// Return Value:
// - a RECT whose components represent the margins of the nonclient area,
// relative to the client area.
RECT IslandWindow::GetNonClientFrame(const UINT dpi) const noexcept
{
const auto windowStyle = static_cast<DWORD>(GetWindowLong(_window.get(), GWL_STYLE));
RECT islandFrame{};
@ -630,7 +638,18 @@ SIZE IslandWindow::GetTotalNonClientExclusiveSize(const UINT dpi) const noexcept
// the error and go on. We'll use whatever the control proposed as the
// size of our window, which will be at least close.
LOG_IF_WIN32_BOOL_FALSE(AdjustWindowRectExForDpi(&islandFrame, windowStyle, false, 0, dpi));
return islandFrame;
}
// Method Description:
// - Gets the difference between window and client area size.
// Arguments:
// - dpi: dpi of a monitor on which the window is placed
// Return Value
// - The size difference
SIZE IslandWindow::GetTotalNonClientExclusiveSize(const UINT dpi) const noexcept
{
const auto islandFrame{ GetNonClientFrame(dpi) };
return {
islandFrame.right - islandFrame.left,
islandFrame.bottom - islandFrame.top
@ -757,7 +776,12 @@ void IslandWindow::SetTaskbarProgress(const size_t state, const size_t progress)
_taskbar->SetProgressValue(_window.get(), progress, 100);
break;
case 3:
// sets the progress indicator to an indeterminate state
// sets the progress indicator to an indeterminate state.
// FIRST, set the progress to "no progress". That'll clear out any
// progress value from the previous state. Otherwise, a transition
// from (error,x%) or (warning,x%) to indeterminate will leave the
// progress value unchanged, and not show the spinner.
_taskbar->SetProgressState(_window.get(), TBPF_NOPROGRESS);
_taskbar->SetProgressState(_window.get(), TBPF_INDETERMINATE);
break;
case 4:

View file

@ -24,6 +24,7 @@ public:
virtual void OnAppInitialized();
virtual void SetContent(winrt::Windows::UI::Xaml::UIElement content);
virtual void OnApplicationThemeChanged(const winrt::Windows::UI::Xaml::ElementTheme& requestedTheme);
virtual RECT GetNonClientFrame(const UINT dpi) const noexcept;
virtual SIZE GetTotalNonClientExclusiveSize(const UINT dpi) const noexcept;
virtual void Initialize();

View file

@ -629,14 +629,21 @@ int NonClientIslandWindow::_GetResizeHandleHeight() const noexcept
return DefWindowProc(GetHandle(), WM_SETCURSOR, wParam, lParam);
}
// Method Description:
// - Gets the difference between window and client area size.
// - Get the dimensions of our non-client area, as a rect where each component
// represents that side.
// - The .left will be a negative number, to represent that the actual side of
// the non-client area is outside the border of our window. It's roughly 8px (
// * DPI scaling) to the left of the visible border.
// - The .right component will be positive, indicating that the nonclient border
// is in the positive-x direction from the edge of our client area.
// - This DOES NOT include our titlebar! It's in the client area for us.
// Arguments:
// - dpi: dpi of a monitor on which the window is placed
// Return Value
// - The size difference
SIZE NonClientIslandWindow::GetTotalNonClientExclusiveSize(UINT dpi) const noexcept
// - dpi: the scaling that we should use to calculate the border sizes.
// Return Value:
// - a RECT whose components represent the margins of the nonclient area,
// relative to the client area.
RECT NonClientIslandWindow::GetNonClientFrame(UINT dpi) const noexcept
{
const auto windowStyle = static_cast<DWORD>(GetWindowLong(_window.get(), GWL_STYLE));
RECT islandFrame{};
@ -647,6 +654,18 @@ SIZE NonClientIslandWindow::GetTotalNonClientExclusiveSize(UINT dpi) const noexc
LOG_IF_WIN32_BOOL_FALSE(AdjustWindowRectExForDpi(&islandFrame, windowStyle, false, 0, dpi));
islandFrame.top = -topBorderVisibleHeight;
return islandFrame;
}
// Method Description:
// - Gets the difference between window and client area size.
// Arguments:
// - dpi: dpi of a monitor on which the window is placed
// Return Value
// - The size difference
SIZE NonClientIslandWindow::GetTotalNonClientExclusiveSize(UINT dpi) const noexcept
{
const auto islandFrame{ GetNonClientFrame(dpi) };
// If we have a titlebar, this is being called after we've initialized, and
// we can just ask that titlebar how big it wants to be.

View file

@ -37,6 +37,7 @@ public:
[[nodiscard]] virtual LRESULT MessageHandler(UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept override;
virtual RECT GetNonClientFrame(UINT dpi) const noexcept override;
virtual SIZE GetTotalNonClientExclusiveSize(UINT dpi) const noexcept override;
void Initialize() override;

View file

@ -82,6 +82,10 @@ static bool _messageIsAltKeyup(const MSG& message)
{
return (message.message == WM_KEYUP || message.message == WM_SYSKEYUP) && message.wParam == VK_MENU;
}
static bool _messageIsAltSpaceKeypress(const MSG& message)
{
return message.message == WM_SYSKEYDOWN && message.wParam == VK_SPACE;
}
int __stdcall wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int)
{
@ -171,6 +175,18 @@ int __stdcall wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int)
}
}
// GH#7125 = System XAML will show a system dialog on Alt Space. We might want to
// explicitly prevent that - for example when an action is bound to it. So similar to
// above, we steal the event and hand it off to the host. When the host does not process
// it, we will still dispatch like normal.
if (_messageIsAltSpaceKeypress(message))
{
if (host.OnDirectKeyEvent(VK_SPACE, LOBYTE(HIWORD(message.lParam)), true))
{
continue;
}
}
TranslateMessage(&message);
DispatchMessage(&message);
}

View file

@ -1639,6 +1639,30 @@ void DoSrvEndHyperlink(SCREEN_INFORMATION& screenInfo)
screenInfo.GetTextBuffer().SetCurrentAttributes(attr);
}
// Routine Description:
// - A private API call for updating the active soft font.
// Arguments:
// - bitPattern - An array of scanlines representing all the glyphs in the font.
// - cellSize - The cell size for an individual glyph.
// - centeringHint - The horizontal extent that glyphs are offset from center.
// Return Value:
// - S_OK if we succeeded, otherwise the HRESULT of the failure.
[[nodiscard]] HRESULT DoSrvUpdateSoftFont(const gsl::span<const uint16_t> bitPattern,
const SIZE cellSize,
const size_t centeringHint) noexcept
{
try
{
auto* pRender = ServiceLocator::LocateGlobals().pRender;
if (pRender)
{
pRender->UpdateSoftFont(bitPattern, cellSize, centeringHint);
}
return S_OK;
}
CATCH_RETURN();
}
// Routine Description:
// - A private API call for forcing the renderer to repaint the screen. If the
// input screen buffer is not the active one, then just do nothing. We only

View file

@ -55,6 +55,10 @@ void DoSrvAddHyperlink(SCREEN_INFORMATION& screenInfo,
void DoSrvEndHyperlink(SCREEN_INFORMATION& screenInfo);
[[nodiscard]] HRESULT DoSrvUpdateSoftFont(const gsl::span<const uint16_t> bitPattern,
const SIZE cellSize,
const size_t centeringHint) noexcept;
void DoSrvPrivateRefreshWindow(const SCREEN_INFORMATION& screenInfo);
[[nodiscard]] HRESULT DoSrvSetConsoleOutputCodePage(const unsigned int codepage);

View file

@ -818,3 +818,18 @@ bool ConhostInternalGetSet::PrivateEndHyperlink() const
DoSrvEndHyperlink(_io.GetActiveOutputBuffer());
return true;
}
// Routine Description:
// - Replaces the active soft font with the given bit pattern.
// Arguments:
// - bitPattern - An array of scanlines representing all the glyphs in the font.
// - cellSize - The cell size for an individual glyph.
// - centeringHint - The horizontal extent that glyphs are offset from center.
// Return Value:
// - true if successful (see DoSrvUpdateSoftFont). false otherwise.
bool ConhostInternalGetSet::PrivateUpdateSoftFont(const gsl::span<const uint16_t> bitPattern,
const SIZE cellSize,
const size_t centeringHint) noexcept
{
return SUCCEEDED(DoSrvUpdateSoftFont(bitPattern, cellSize, centeringHint));
}

View file

@ -147,6 +147,10 @@ public:
bool PrivateAddHyperlink(const std::wstring_view uri, const std::wstring_view params) const override;
bool PrivateEndHyperlink() const override;
bool PrivateUpdateSoftFont(const gsl::span<const uint16_t> bitPattern,
const SIZE cellSize,
const size_t centeringHint) noexcept override;
private:
Microsoft::Console::IIoProvider& _io;
};

View file

@ -2002,8 +2002,6 @@ void SCREEN_INFORMATION::UseMainScreenBuffer()
SCREEN_INFORMATION* psiAlt = psiMain->_psiAlternateBuffer;
psiMain->_psiAlternateBuffer = nullptr;
s_RemoveScreenBuffer(psiAlt); // this will also delete the alt buffer
// deleting the alt buffer will give the GetSet back to its main
// Copy the alt buffer's cursor style and visibility back to the main buffer.
const auto& altCursor = psiAlt->GetTextBuffer().GetCursor();
@ -2012,6 +2010,9 @@ void SCREEN_INFORMATION::UseMainScreenBuffer()
mainCursor.SetIsVisible(altCursor.IsVisible());
mainCursor.SetBlinkingAllowed(altCursor.IsBlinkingAllowed());
s_RemoveScreenBuffer(psiAlt); // this will also delete the alt buffer
// deleting the alt buffer will give the GetSet back to its main
// Tell the VT MouseInput handler that we're in the main buffer now
gci.GetActiveInputBuffer()->GetTerminalInput().UseMainScreenBuffer();
}

View file

@ -420,6 +420,7 @@ void VtRendererTest::Xterm256TestColors()
qExpectedInput.push_back("\x1b[48;2;5;6;7m");
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes({ 0x00030201, 0x00070605 },
&renderData,
false,
false));
TestPaint(*engine, [&]() {
@ -428,6 +429,7 @@ void VtRendererTest::Xterm256TestColors()
qExpectedInput.push_back("\x1b[48;2;7;8;9m");
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes({ 0x00030201, 0x00090807 },
&renderData,
false,
false));
Log::Comment(NoThrowString().Format(
@ -435,6 +437,7 @@ void VtRendererTest::Xterm256TestColors()
qExpectedInput.push_back("\x1b[38;2;10;11;12m");
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes({ 0x000c0b0a, 0x00090807 },
&renderData,
false,
false));
});
@ -444,6 +447,7 @@ void VtRendererTest::Xterm256TestColors()
qExpectedInput.push_back(EMPTY_CALLBACK_SENTINEL);
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes({ 0x000c0b0a, 0x00090807 },
&renderData,
false,
false));
WriteCallback(EMPTY_CALLBACK_SENTINEL, 1); // This will make sure nothing was written to the callback
});
@ -458,6 +462,7 @@ void VtRendererTest::Xterm256TestColors()
qExpectedInput.push_back("\x1b[m");
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes({},
&renderData,
false,
false));
TestPaint(*engine, [&]() {
@ -469,6 +474,7 @@ void VtRendererTest::Xterm256TestColors()
qExpectedInput.push_back("\x1b[41m"); // Background DARK_RED
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes,
&renderData,
false,
false));
Log::Comment(NoThrowString().Format(
@ -477,6 +483,7 @@ void VtRendererTest::Xterm256TestColors()
qExpectedInput.push_back("\x1b[37m"); // Foreground DARK_WHITE
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes,
&renderData,
false,
false));
Log::Comment(NoThrowString().Format(
@ -485,6 +492,7 @@ void VtRendererTest::Xterm256TestColors()
qExpectedInput.push_back("\x1b[48;2;19;161;14m"); // Background RGB(19,161,14)
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes,
&renderData,
false,
false));
Log::Comment(NoThrowString().Format(
@ -493,6 +501,7 @@ void VtRendererTest::Xterm256TestColors()
qExpectedInput.push_back("\x1b[38;2;193;156;0m"); // Foreground RGB(193,156,0)
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes,
&renderData,
false,
false));
Log::Comment(NoThrowString().Format(
@ -501,6 +510,7 @@ void VtRendererTest::Xterm256TestColors()
qExpectedInput.push_back("\x1b[49m"); // Background default
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes,
&renderData,
false,
false));
Log::Comment(NoThrowString().Format(
@ -509,6 +519,7 @@ void VtRendererTest::Xterm256TestColors()
qExpectedInput.push_back("\x1b[38;5;7m"); // Foreground DARK_WHITE (256-Color Index)
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes,
&renderData,
false,
false));
Log::Comment(NoThrowString().Format(
@ -517,6 +528,7 @@ void VtRendererTest::Xterm256TestColors()
qExpectedInput.push_back("\x1b[48;5;1m"); // Background DARK_RED (256-Color Index)
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes,
&renderData,
false,
false));
Log::Comment(NoThrowString().Format(
@ -525,6 +537,7 @@ void VtRendererTest::Xterm256TestColors()
qExpectedInput.push_back("\x1b[39m"); // Background default
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes,
&renderData,
false,
false));
Log::Comment(NoThrowString().Format(
@ -533,6 +546,7 @@ void VtRendererTest::Xterm256TestColors()
qExpectedInput.push_back("\x1b[m");
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes,
&renderData,
false,
false));
});
@ -542,6 +556,7 @@ void VtRendererTest::Xterm256TestColors()
qExpectedInput.push_back(EMPTY_CALLBACK_SENTINEL);
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes({},
&renderData,
false,
false));
WriteCallback(EMPTY_CALLBACK_SENTINEL, 1); // This will make sure nothing was written to the callback
});
@ -795,7 +810,7 @@ void VtRendererTest::Xterm256TestAttributesAcrossReset()
Log::Comment(L"----Start With All Attributes Reset----");
TextAttribute textAttributes = {};
qExpectedInput.push_back("\x1b[m");
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes, &renderData, false));
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes, &renderData, false, false));
switch (renditionAttribute)
{
@ -841,29 +856,29 @@ void VtRendererTest::Xterm256TestAttributesAcrossReset()
break;
}
qExpectedInput.push_back(renditionSequence.str());
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes, &renderData, false));
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes, &renderData, false, false));
Log::Comment(L"----Set Green Foreground----");
textAttributes.SetIndexedForeground(FOREGROUND_GREEN);
qExpectedInput.push_back("\x1b[32m");
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes, &renderData, false));
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes, &renderData, false, false));
Log::Comment(L"----Reset Default Foreground and Retain Rendition----");
textAttributes.SetDefaultForeground();
qExpectedInput.push_back("\x1b[m");
qExpectedInput.push_back(renditionSequence.str());
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes, &renderData, false));
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes, &renderData, false, false));
Log::Comment(L"----Set Green Background----");
textAttributes.SetIndexedBackground(FOREGROUND_GREEN);
qExpectedInput.push_back("\x1b[42m");
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes, &renderData, false));
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes, &renderData, false, false));
Log::Comment(L"----Reset Default Background and Retain Rendition----");
textAttributes.SetDefaultBackground();
qExpectedInput.push_back("\x1b[m");
qExpectedInput.push_back(renditionSequence.str());
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes, &renderData, false));
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes, &renderData, false, false));
VerifyExpectedInputsDrained();
}
@ -1081,6 +1096,7 @@ void VtRendererTest::XtermTestColors()
qExpectedInput.push_back("\x1b[m");
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes({},
&renderData,
false,
false));
TestPaint(*engine, [&]() {
@ -1092,6 +1108,7 @@ void VtRendererTest::XtermTestColors()
qExpectedInput.push_back("\x1b[41m"); // Background DARK_RED
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes,
&renderData,
false,
false));
Log::Comment(NoThrowString().Format(
@ -1100,6 +1117,7 @@ void VtRendererTest::XtermTestColors()
qExpectedInput.push_back("\x1b[37m"); // Foreground DARK_WHITE
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes,
&renderData,
false,
false));
Log::Comment(NoThrowString().Format(
@ -1108,6 +1126,7 @@ void VtRendererTest::XtermTestColors()
qExpectedInput.push_back("\x1b[42m"); // Background DARK_GREEN
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes,
&renderData,
false,
false));
Log::Comment(NoThrowString().Format(
@ -1116,6 +1135,7 @@ void VtRendererTest::XtermTestColors()
qExpectedInput.push_back("\x1b[33m"); // Foreground DARK_YELLOW
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes,
&renderData,
false,
false));
Log::Comment(NoThrowString().Format(
@ -1125,6 +1145,7 @@ void VtRendererTest::XtermTestColors()
qExpectedInput.push_back("\x1b[33m"); // Reapply foreground DARK_YELLOW
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes,
&renderData,
false,
false));
Log::Comment(NoThrowString().Format(
@ -1133,6 +1154,7 @@ void VtRendererTest::XtermTestColors()
qExpectedInput.push_back("\x1b[37m"); // Foreground DARK_WHITE
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes,
&renderData,
false,
false));
Log::Comment(NoThrowString().Format(
@ -1141,6 +1163,7 @@ void VtRendererTest::XtermTestColors()
qExpectedInput.push_back("\x1b[41m"); // Background DARK_RED
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes,
&renderData,
false,
false));
Log::Comment(NoThrowString().Format(
@ -1150,6 +1173,7 @@ void VtRendererTest::XtermTestColors()
qExpectedInput.push_back("\x1b[41m"); // Reapply background DARK_RED
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes,
&renderData,
false,
false));
Log::Comment(NoThrowString().Format(
@ -1158,6 +1182,7 @@ void VtRendererTest::XtermTestColors()
qExpectedInput.push_back("\x1b[m");
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes,
&renderData,
false,
false));
});
@ -1167,6 +1192,7 @@ void VtRendererTest::XtermTestColors()
qExpectedInput.push_back(EMPTY_CALLBACK_SENTINEL);
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes({},
&renderData,
false,
false));
WriteCallback(EMPTY_CALLBACK_SENTINEL, 1); // This will make sure nothing was written to the callback
});
@ -1304,7 +1330,7 @@ void VtRendererTest::XtermTestAttributesAcrossReset()
Log::Comment(L"----Start With All Attributes Reset----");
TextAttribute textAttributes = {};
qExpectedInput.push_back("\x1b[m");
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes, &renderData, false));
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes, &renderData, false, false));
switch (renditionAttribute)
{
@ -1322,29 +1348,29 @@ void VtRendererTest::XtermTestAttributesAcrossReset()
break;
}
qExpectedInput.push_back(renditionSequence.str());
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes, &renderData, false));
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes, &renderData, false, false));
Log::Comment(L"----Set Green Foreground----");
textAttributes.SetIndexedForeground(FOREGROUND_GREEN);
qExpectedInput.push_back("\x1b[32m");
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes, &renderData, false));
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes, &renderData, false, false));
Log::Comment(L"----Reset Default Foreground and Retain Rendition----");
textAttributes.SetDefaultForeground();
qExpectedInput.push_back("\x1b[m");
qExpectedInput.push_back(renditionSequence.str());
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes, &renderData, false));
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes, &renderData, false, false));
Log::Comment(L"----Set Green Background----");
textAttributes.SetIndexedBackground(FOREGROUND_GREEN);
qExpectedInput.push_back("\x1b[42m");
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes, &renderData, false));
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes, &renderData, false, false));
Log::Comment(L"----Reset Default Background and Retain Rendition----");
textAttributes.SetDefaultBackground();
qExpectedInput.push_back("\x1b[m");
qExpectedInput.push_back(renditionSequence.str());
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes, &renderData, false));
VERIFY_SUCCEEDED(engine->UpdateDrawingBrushes(textAttributes, &renderData, false, false));
VerifyExpectedInputsDrained();
}

Some files were not shown because too many files have changed in this diff Show more