terminal/src/cascadia/TerminalSettingsModel/DefaultTerminal.cpp
Leonard Hecker 39d16ba94c PREREQ: Fix default terminal setting dropdown (#11430)
WinUI/XAML requires the `SelectedItem` to be member of the list of
`ItemsSource`. `CascadiaSettings::DefaultTerminals()` is such an `ItemsSource`
and is called every time the launch settings page is visited.
It calls `DefaultTerminal::Available()` which in turn calls `Refresh()`.
While the `SelectedItem` was cached in `CascadiaSettings`, the value of
`DefaultTerminals()` wasn't. Thus every time the page was visited, it refreshed
the `ItemsSource` list without invalidating the current `SelectedItem`.

This commit prevents such accidental mishaps from occurring in the future,
by moving the responsibility of caching solely to the `CascadiaSettings` class.

* [x] Closes #11424
* [x] I work here
* [x] Tests added/passed

* Navigating between SUI pages maintains the current dropdown selection ✔️
* Saving the settings saves the correct terminal at `HKCU:\Console\%%Startup` ✔️

(cherry picked from commit 35ce8cc858)
2021-10-13 18:15:23 -05:00

80 lines
2.8 KiB
C++

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "DefaultTerminal.h"
#include "DefaultTerminal.g.cpp"
#include <LibraryResources.h>
using namespace winrt::Microsoft::Terminal::Settings;
using namespace winrt::Microsoft::Terminal::Settings::Model::implementation;
DefaultTerminal::DefaultTerminal(DelegationConfig::DelegationPackage&& pkg) :
_pkg{ pkg }
{
}
winrt::hstring DefaultTerminal::Name() const
{
return _pkg.terminal.name.empty() ? winrt::hstring{ RS_(L"InboxWindowsConsoleName") } : winrt::hstring{ _pkg.terminal.name };
}
winrt::hstring DefaultTerminal::Version() const
{
// If there's no version information... return empty string instead.
const auto& version = _pkg.terminal.version;
if (DelegationConfig::PkgVersion{} == version)
{
return winrt::hstring{};
}
fmt::wmemory_buffer buffer;
fmt::format_to(buffer, L"{}.{}.{}.{}", version.major, version.minor, version.build, version.revision);
return winrt::hstring{ buffer.data(), gsl::narrow_cast<winrt::hstring::size_type>(buffer.size()) };
}
winrt::hstring DefaultTerminal::Author() const
{
return _pkg.terminal.author.empty() ? winrt::hstring{ RS_(L"InboxWindowsConsoleAuthor") } : winrt::hstring{ _pkg.terminal.author };
}
winrt::hstring DefaultTerminal::Icon() const
{
return _pkg.terminal.logo.empty() ? winrt::hstring{ L"\uE756" } : winrt::hstring{ _pkg.terminal.logo };
}
std::pair<std::vector<Model::DefaultTerminal>, Model::DefaultTerminal> DefaultTerminal::Available()
{
// The potential of returning nullptr for defaultTerminal feels weird, but XAML can
// handle that appropriately and will select nothing as current in the dropdown.
std::vector<Model::DefaultTerminal> defaultTerminals;
Model::DefaultTerminal defaultTerminal{ nullptr };
std::vector<DelegationConfig::DelegationPackage> allPackages;
DelegationConfig::DelegationPackage currentPackage;
LOG_IF_FAILED(DelegationConfig::s_GetAvailablePackages(allPackages, currentPackage));
for (auto& pkg : allPackages)
{
// Be a bit careful here: We're moving pkg into the constructor.
// Afterwards it'll be invalid, so we need to cache isCurrent.
const auto isCurrent = pkg == currentPackage;
auto p = winrt::make<DefaultTerminal>(std::move(pkg));
if (isCurrent)
{
defaultTerminal = p;
}
defaultTerminals.emplace_back(std::move(p));
}
return { std::move(defaultTerminals), std::move(defaultTerminal) };
}
void DefaultTerminal::Current(const Model::DefaultTerminal& term)
{
THROW_IF_FAILED(DelegationConfig::s_SetDefaultByPackage(winrt::get_self<DefaultTerminal>(term)->_pkg, true));
}