mirror of
https://github.com/microsoft/terminal.git
synced 2026-07-08 18:16:28 +00:00
Merge branch 'user/migrie/per-window-prequel' of https://github.com/microsoft/terminal into user/migrie/per-window-prequel
This commit is contained in:
1
.github/actions/spelling/allow/microsoft.txt
vendored
1
.github/actions/spelling/allow/microsoft.txt
vendored
@@ -78,4 +78,5 @@ wtl
|
||||
wtt
|
||||
wttlog
|
||||
Xamarin
|
||||
XBOX
|
||||
xfgcheck
|
||||
|
||||
2
.github/actions/spelling/expect/expect.txt
vendored
2
.github/actions/spelling/expect/expect.txt
vendored
@@ -1139,7 +1139,7 @@ nullopts
|
||||
NUMSCROLL
|
||||
NUnit
|
||||
nupkg
|
||||
NVIDIA
|
||||
nvidia
|
||||
NVT
|
||||
OACR
|
||||
ocolor
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||

|
||||

|
||||
|
||||
[](https://dev.azure.com/shine-oss/terminal/_build/latest?definitionId=1&branchName=main)
|
||||
|
||||
|
||||
@@ -161,6 +161,40 @@ namespace winrt::TerminalApp::implementation
|
||||
}
|
||||
});
|
||||
|
||||
// BODGY: Work around a fail-fast crash in WinUI 2's TabView. When a
|
||||
// game controller (e.g. an XBOX controller's d-pad/stick) moves focus
|
||||
// Up or Down between two TabViewItems, MUX's TabView::OnListViewGettingFocus
|
||||
// runs a GameController-only code path that calls
|
||||
// DispatcherQueue.TryEnqueue, which fails with E_INVALIDARG. That
|
||||
// unhandled error inside a GettingFocus callback makes XAML fail-fast,
|
||||
// and the whole window vanishes. See
|
||||
// microsoft-ui-xaml/blob/840c6cd4ac9d16d9aa99b24f0bd43997fe21bef8/dev/TabView/TabView.cpp#L246
|
||||
//
|
||||
// This GettingFocus handler is on the TabViewItem, which is closer to
|
||||
// the focus source than the TabViewListView that MUX's handler lives
|
||||
// on, so it runs first. Marking the event Handled - and cancelling the
|
||||
// focus move, which is exactly what MUX itself does for the keyboard
|
||||
// case - preempts MUX's broken handler. Keyboard navigation is left
|
||||
// untouched; MUX handles that path safely.
|
||||
TabViewItem().GettingFocus([](auto&&, const winrt::WUX::Input::GettingFocusEventArgs& args) {
|
||||
const auto direction{ args.Direction() };
|
||||
if (direction != winrt::WUX::Input::FocusNavigationDirection::Up &&
|
||||
direction != winrt::WUX::Input::FocusNavigationDirection::Down)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (args.InputDevice() != winrt::WUX::Input::FocusInputDeviceKind::GameController)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (args.OldFocusedElement().try_as<winrt::MUX::Controls::TabViewItem>() &&
|
||||
args.NewFocusedElement().try_as<winrt::MUX::Controls::TabViewItem>())
|
||||
{
|
||||
args.Cancel(true);
|
||||
args.Handled(true);
|
||||
}
|
||||
});
|
||||
|
||||
UpdateTitle();
|
||||
_RecalculateAndApplyTabColor();
|
||||
}
|
||||
|
||||
@@ -547,40 +547,10 @@ namespace winrt::TerminalApp::implementation
|
||||
// 1. We want to customize this behavior (e.g., use MRU logic)
|
||||
// 2. In fullscreen (GH#5799) and focus (GH#7916) modes the _OnTabItemsChanged is not fired
|
||||
// 3. When rearranging tabs (GH#7916) _OnTabItemsChanged is suppressed
|
||||
const auto tabSwitchMode = _currentWindowSettings().TabSwitcherMode();
|
||||
|
||||
if (tabSwitchMode == TabSwitcherMode::MostRecentlyUsed)
|
||||
{
|
||||
const auto newSelectedTab = _mruTabs.GetAt(0);
|
||||
_UpdatedSelectedTab(newSelectedTab);
|
||||
_tabView.SelectedItem(newSelectedTab.TabViewItem());
|
||||
}
|
||||
else
|
||||
{
|
||||
// We can't use
|
||||
// auto selectedIndex = _tabView.SelectedIndex();
|
||||
// Because this will always return -1 in this scenario unfortunately.
|
||||
//
|
||||
// So, what we're going to try to do is move the focus to the tab
|
||||
// to the right, within the bounds of how many tabs we have.
|
||||
//
|
||||
// EX: we have 4 tabs: [A, B, C, D]. If we close:
|
||||
// * A (tabIndex=0): We'll want to focus tab B (now in index 0)
|
||||
// * B (tabIndex=1): We'll want to focus tab C (now in index 1)
|
||||
// * C (tabIndex=2): We'll want to focus tab D (now in index 2)
|
||||
// * D (tabIndex=3): We'll want to focus tab C (now in index 2)
|
||||
const auto newSelectedIndex = std::clamp<int32_t>(tabIndex, 0, _tabs.Size() - 1);
|
||||
// _UpdatedSelectedTab will do the work of setting up the new tab as
|
||||
// the focused one, and unfocusing all the others.
|
||||
auto newSelectedTab{ _tabs.GetAt(newSelectedIndex) };
|
||||
_UpdatedSelectedTab(newSelectedTab);
|
||||
|
||||
// Also, we need to _manually_ set the SelectedItem of the tabView
|
||||
// here. If we don't, then the TabView will technically not have a
|
||||
// selected item at all, which can make things like ClosePane not
|
||||
// work correctly.
|
||||
_tabView.SelectedItem(newSelectedTab.TabViewItem());
|
||||
}
|
||||
const auto newSelectedTab = _mruTabs.GetAt(0);
|
||||
_UpdatedSelectedTab(newSelectedTab);
|
||||
_tabView.SelectedItem(newSelectedTab.TabViewItem());
|
||||
}
|
||||
|
||||
// GH#5559 - If we were in the middle of a drag/drop, end it by clearing
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "Appearances.g.cpp"
|
||||
|
||||
using namespace winrt::Windows::UI::Text;
|
||||
using namespace winrt::Windows::UI::Core;
|
||||
using namespace winrt::Windows::UI::Xaml;
|
||||
using namespace winrt::Windows::UI::Xaml::Controls;
|
||||
using namespace winrt::Windows::UI::Xaml::Data;
|
||||
@@ -1221,8 +1222,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
fontSpec = fontName;
|
||||
}
|
||||
|
||||
sender.Text(fontSpec);
|
||||
|
||||
// Normally we'd just update the model property in LostFocus above, but because WinUI is the Ralph Wiggum
|
||||
// among the UI frameworks, it raises the LostFocus event _before_ the QuerySubmitted event.
|
||||
// So, when you press Save, the model will have the wrong font face string, because LostFocus was raised too early.
|
||||
@@ -1233,11 +1232,20 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
// You can't just do IsSuggestionListOpen(false) either, because you can show the list with that property but not hide it.
|
||||
// So, we update the model manually and assign focus to the parent container.
|
||||
//
|
||||
// BUT you can't just focus the parent container, because of a weird interaction with AutoSuggestBox where it'll refuse to lose
|
||||
// focus if you picked a suggestion that matches the current fontSpec. So, we unfocus it first and then focus the parent container.
|
||||
_updateFontName(fontSpec);
|
||||
sender.Focus(FocusState::Unfocused);
|
||||
FontFaceContainer().Focus(FocusState::Programmatic);
|
||||
// Queue the selected-suggestion commit so AutoSuggestBox can finish processing Enter before we change its text/model.
|
||||
// Do not manually unfocus the AutoSuggestBox here. Its Focus(FocusState::Unfocused) path crashes during keyboard commits.
|
||||
Dispatcher().RunAsync(CoreDispatcherPriority::Normal, [weakThis{ get_weak() }, weakSender{ winrt::make_weak(sender) }, fontSpec{ std::move(fontSpec) }]() {
|
||||
if (const auto self{ weakThis.get() })
|
||||
{
|
||||
if (const auto box{ weakSender.get() })
|
||||
{
|
||||
box.Text(fontSpec);
|
||||
}
|
||||
|
||||
self->_updateFontName(fontSpec);
|
||||
self->FontFaceContainer().Focus(FocusState::Programmatic);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void Appearances::FontFaceBox_TextChanged(const AutoSuggestBox& sender, const AutoSuggestBoxTextChangedEventArgs& args)
|
||||
|
||||
@@ -395,7 +395,14 @@ void SettingsLoader::FindFragmentsAndMergeIntoUserSettings(bool generateExtensio
|
||||
try
|
||||
{
|
||||
const auto catalog = AppExtensionCatalog::Open(AppExtensionHostName);
|
||||
extensions = extractValueFromTaskWithoutMainThreadAwait(catalog.FindAllAsync());
|
||||
if (auto catalog2{ catalog.try_as<IAppExtensionCatalog2>() })
|
||||
{
|
||||
extensions = catalog2.FindAll();
|
||||
}
|
||||
else
|
||||
{
|
||||
extensions = extractValueFromTaskWithoutMainThreadAwait(catalog.FindAllAsync());
|
||||
}
|
||||
}
|
||||
CATCH_LOG();
|
||||
|
||||
@@ -417,20 +424,37 @@ void SettingsLoader::FindFragmentsAndMergeIntoUserSettings(bool generateExtensio
|
||||
continue;
|
||||
}
|
||||
|
||||
// Likewise, getting the public folder from an extension is an async operation.
|
||||
auto foundFolder = extractValueFromTaskWithoutMainThreadAwait(ext.GetPublicFolderAsync());
|
||||
if (!foundFolder)
|
||||
winrt::hstring publicFolderPath;
|
||||
if (auto ext3{ ext.try_as<IAppExtension3>() })
|
||||
{
|
||||
continue;
|
||||
// Windows 11 24H2 and above support a much faster, much less
|
||||
// Windows.Storage-y API.
|
||||
publicFolderPath = ext3.GetPublicPath();
|
||||
if (publicFolderPath.empty())
|
||||
{
|
||||
// No point in falling through to GetPublicFolderAsync;
|
||||
// it won't work.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Likewise, getting the public folder from an extension is an async operation.
|
||||
auto foundFolder = extractValueFromTaskWithoutMainThreadAwait(ext.GetPublicFolderAsync());
|
||||
if (!foundFolder)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// the StorageFolder class has its own methods for obtaining the files within the folder
|
||||
// however, all those methods are Async methods
|
||||
// you may have noticed that we need to resort to clunky implementations for async operations
|
||||
// (they are in extractValueFromTaskWithoutMainThreadAwait)
|
||||
// so for now we will just take the folder path and access the files that way
|
||||
publicFolderPath = foundFolder.Path();
|
||||
}
|
||||
|
||||
// the StorageFolder class has its own methods for obtaining the files within the folder
|
||||
// however, all those methods are Async methods
|
||||
// you may have noticed that we need to resort to clunky implementations for async operations
|
||||
// (they are in extractValueFromTaskWithoutMainThreadAwait)
|
||||
// so for now we will just take the folder path and access the files that way
|
||||
const auto path = buildPath(foundFolder.Path(), FragmentsSubDirectory);
|
||||
|
||||
const auto path = buildPath(publicFolderPath, FragmentsSubDirectory);
|
||||
if (std::filesystem::is_directory(path))
|
||||
{
|
||||
// MSIX does not support machine-wide scope
|
||||
|
||||
@@ -544,6 +544,15 @@ void WindowEmperor::HandleCommandlineArgs(int nCmdShow)
|
||||
__assume(false);
|
||||
}
|
||||
|
||||
// !! LOAD BEARING !!
|
||||
// This prevents loader lock contention with some versions of the nvidia
|
||||
// driver, which calls SHGetKnownFolderPath triggering a delay load while
|
||||
// under lock during application startup. See GH#20348.
|
||||
{
|
||||
wil::unique_cotaskmem_string localAppDataFolder;
|
||||
SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, nullptr, &localAppDataFolder);
|
||||
}
|
||||
|
||||
_app = winrt::TerminalApp::App{};
|
||||
_app.Logic().ReloadSettings();
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ Abstract:
|
||||
#include <shellscalingapi.h>
|
||||
#include <windowsx.h>
|
||||
#include <ShObjIdl.h>
|
||||
#include <shlobj_core.h>
|
||||
|
||||
// Manually include til after we include Windows.Foundation to give it winrt superpowers
|
||||
#define BLOCK_TIL
|
||||
|
||||
@@ -10,6 +10,10 @@
|
||||
},
|
||||
"Dependencies": {
|
||||
"Files": [
|
||||
{
|
||||
"SourcePath": "$(PROJECT_ROOT)\\core\\console\\open\\src\\Terminal.wprp",
|
||||
"DestinationFolderPath": "$$(TEST_DEPLOY_BIN)"
|
||||
},
|
||||
{
|
||||
"SourcePath": "$(PROJECT_ROOT)\\core\\console\\open\\src\\ConsolePerf.wprp",
|
||||
"DestinationFolderPath": "$$(TEST_DEPLOY_BIN)"
|
||||
@@ -23,7 +27,22 @@
|
||||
"Packages": [ "Microsoft.Console.Tools.Nihilist" ]
|
||||
},
|
||||
"Logs": [ ],
|
||||
"Plugins": [ ],
|
||||
"Plugins": [
|
||||
{
|
||||
"Type": "Microsoft.TestInfrastructure.UniversalTest.TestMD.Plugins.Etw.EtwPlugin",
|
||||
"Name": "Collecting conhost logs during feature tests",
|
||||
"Parameters": {
|
||||
"$schema": "Microsoft.TestInfrastructure.UniversalTest.TestMD.Plugins.Etw.EtwPlugin-1.json",
|
||||
"Profiles": [
|
||||
{
|
||||
"ProfileFile": "Terminal.wprp",
|
||||
"Profile": "DefTerm"
|
||||
}
|
||||
],
|
||||
"InstanceName": "conhost_FeatureTests"
|
||||
}
|
||||
}
|
||||
],
|
||||
"Profiles": [
|
||||
{
|
||||
"Name": "Performance",
|
||||
|
||||
Reference in New Issue
Block a user