Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions doc/cascadia/profiles.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -2022,9 +2022,21 @@
"type": "string"
},
"useMica": {
"description": "True if the Terminal should use a Mica backdrop for the window. This will apply underneath all controls (including the terminal panes and the titlebar)",
"type": "boolean",
"default": false
"description": "Controls the Mica backdrop type for the window. Can be a boolean (true/false for backward compatibility) or a string specifying the Mica type. This will apply underneath all controls (including the terminal panes and the titlebar)",
"default": false,
"oneOf": [
{
"type": "boolean"
},
{
"type": "string",
"enum": [
"none",
"mica",
"micaAlt"
]
}
]
},
"experimental.rainbowFrame": {
"description": "When enabled, the frame of the window will cycle through all the colors. Enabling this will override the `frame` and `unfocusedFrame` settings.",
Expand Down
2 changes: 1 addition & 1 deletion src/cascadia/TerminalSettingsEditor/MainPage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -984,7 +984,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
// that our theme is different than the app's.
const bool actuallyUseMica = isMicaAvailable && (appTheme == requestedTheme);

const auto bgKey = (theme.Window() != nullptr && theme.Window().UseMica()) && actuallyUseMica ?
const auto bgKey = (theme.Window() != nullptr && theme.Window().UseMica() != winrt::Microsoft::Terminal::Settings::Model::MicaKind::None) && actuallyUseMica ?
L"SettingsPageMicaBackground" :
L"SettingsPageBackground";

Expand Down
12 changes: 6 additions & 6 deletions src/cascadia/TerminalSettingsModel/MTSMSettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,12 +152,12 @@ Author(s):
X(winrt::Microsoft::Terminal::Settings::Model::TabRowTheme, TabRow, "tabRow", nullptr) \
X(winrt::Microsoft::Terminal::Settings::Model::TabTheme, Tab, "tab", nullptr)

#define MTSM_THEME_WINDOW_SETTINGS(X) \
X(winrt::Windows::UI::Xaml::ElementTheme, RequestedTheme, "applicationTheme", winrt::Windows::UI::Xaml::ElementTheme::Default) \
X(winrt::Microsoft::Terminal::Settings::Model::ThemeColor, Frame, "frame", nullptr) \
X(winrt::Microsoft::Terminal::Settings::Model::ThemeColor, UnfocusedFrame, "unfocusedFrame", nullptr) \
X(bool, RainbowFrame, "experimental.rainbowFrame", false) \
X(bool, UseMica, "useMica", false)
#define MTSM_THEME_WINDOW_SETTINGS(X) \
X(winrt::Windows::UI::Xaml::ElementTheme, RequestedTheme, "applicationTheme", winrt::Windows::UI::Xaml::ElementTheme::Default) \
X(winrt::Microsoft::Terminal::Settings::Model::ThemeColor, Frame, "frame", nullptr) \
X(winrt::Microsoft::Terminal::Settings::Model::ThemeColor, UnfocusedFrame, "unfocusedFrame", nullptr) \
X(bool, RainbowFrame, "experimental.rainbowFrame", false) \
X(winrt::Microsoft::Terminal::Settings::Model::MicaKind, UseMica, "useMica", winrt::Microsoft::Terminal::Settings::Model::MicaKind::None)

#define MTSM_THEME_SETTINGS_SETTINGS(X) \
X(winrt::Windows::UI::Xaml::ElementTheme, RequestedTheme, "theme", winrt::Windows::UI::Xaml::ElementTheme::Default)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -660,13 +660,39 @@ JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::Model::TabCloseButtonVi
};
};

JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::Model::IconStyle)
{
JSON_MAPPINGS(3) = {
pair_type{ "default", ValueType::Default },
pair_type{ "hidden", ValueType::Hidden },
pair_type{ "monochrome", ValueType::Monochrome },
};
JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::Model::IconStyle)
{
JSON_MAPPINGS(3) = {
pair_type{ "default", ValueType::Default },
pair_type{ "hidden", ValueType::Hidden },
pair_type{ "monochrome", ValueType::Monochrome },
};
};

JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::Model::MicaKind)
{
JSON_MAPPINGS(3) = {
pair_type{ "none", ValueType::None },
pair_type{ "mica", ValueType::Mica },
pair_type{ "micaAlt", ValueType::MicaAlt },
};

// Override mapping parser to add boolean parsing for backward compatibility
::winrt::Microsoft::Terminal::Settings::Model::MicaKind FromJson(const Json::Value& json)
{
if (json.isBool())
{
return json.asBool() ? ValueType::Mica : ValueType::None;
}
return EnumMapper::FromJson(json);
}

bool CanConvert(const Json::Value& json)
{
return EnumMapper::CanConvert(json) || json.isBool();
}

using EnumMapper::TypeDescription;
};

// Possible ScrollToMarkDirection values
Expand Down
31 changes: 19 additions & 12 deletions src/cascadia/TerminalSettingsModel/Theme.idl
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,19 @@ namespace Microsoft.Terminal.Settings.Model
TerminalBackground
};

enum TabCloseButtonVisibility
{
Always,
Hover,
Never,
ActiveOnly
enum TabCloseButtonVisibility
{
Always,
Hover,
Never,
ActiveOnly
};

enum MicaKind
{
None,
Mica,
MicaAlt
};

[default_interface] runtimeclass ThemePair
Expand Down Expand Up @@ -58,12 +65,12 @@ namespace Microsoft.Terminal.Settings.Model
Windows.UI.Xaml.ElementTheme RequestedTheme { get; };
}

runtimeclass WindowTheme {
Windows.UI.Xaml.ElementTheme RequestedTheme { get; };
Boolean UseMica { get; };
Boolean RainbowFrame { get; };
ThemeColor Frame { get; };
ThemeColor UnfocusedFrame { get; };
runtimeclass WindowTheme {
Windows.UI.Xaml.ElementTheme RequestedTheme { get; };
MicaKind UseMica { get; };
Boolean RainbowFrame { get; };
ThemeColor Frame { get; };
ThemeColor UnfocusedFrame { get; };
}

runtimeclass TabRowTheme {
Expand Down
109 changes: 100 additions & 9 deletions src/cascadia/UnitTests_SettingsModel/ThemeTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@ namespace SettingsModelUnitTests
{
TEST_CLASS(ThemeTests);

TEST_METHOD(ParseSimpleTheme);
TEST_METHOD(ParseEmptyTheme);
TEST_METHOD(ParseNoWindowTheme);
TEST_METHOD(ParseNullWindowTheme);
TEST_METHOD(ParseThemeWithNullThemeColor);
TEST_METHOD(InvalidCurrentTheme);
TEST_METHOD(ParseSimpleTheme);
TEST_METHOD(ParseEmptyTheme);
TEST_METHOD(ParseNoWindowTheme);
TEST_METHOD(ParseNullWindowTheme);
TEST_METHOD(ParseThemeWithNullThemeColor);
TEST_METHOD(InvalidCurrentTheme);
TEST_METHOD(ParseMicaKindEnumValues);

static Core::Color rgb(uint8_t r, uint8_t g, uint8_t b) noexcept
{
Expand Down Expand Up @@ -68,7 +69,7 @@ namespace SettingsModelUnitTests

VERIFY_IS_NOT_NULL(theme->Window());
VERIFY_ARE_EQUAL(winrt::Windows::UI::Xaml::ElementTheme::Light, theme->Window().RequestedTheme());
VERIFY_ARE_EQUAL(true, theme->Window().UseMica());
VERIFY_ARE_EQUAL(winrt::Microsoft::Terminal::Settings::Model::MicaKind::Mica, theme->Window().UseMica());
}

void ThemeTests::ParseEmptyTheme()
Expand Down Expand Up @@ -263,6 +264,96 @@ namespace SettingsModelUnitTests
auto deserializationErrorMessage = til::u8u16(e.what());
Log::Comment(NoThrowString().Format(deserializationErrorMessage.c_str()));
throw e;
}
}
}
}

void ThemeTests::ParseMicaKindEnumValues()
{
Log::Comment(L"Test parsing of MicaKind enum values and backward compatibility with boolean");

// Test with boolean true (should map to Mica)
static constexpr std::string_view booleanTrueTheme{ R"({
"name": "booleanTrue",
"window": {
"useMica": true
}
})" };

// Test with boolean false (should map to None)
static constexpr std::string_view booleanFalseTheme{ R"({
"name": "booleanFalse",
"window": {
"useMica": false
}
})" };

// Test with string "mica" (should map to Mica)
static constexpr std::string_view stringMicaTheme{ R"({
"name": "stringMica",
"window": {
"useMica": "mica"
}
})" };

// Test with string "micaAlt" (should map to MicaAlt)
static constexpr std::string_view stringMicaAltTheme{ R"({
"name": "stringMicaAlt",
"window": {
"useMica": "micaAlt"
}
})" };

// Test with string "none" (should map to None)
static constexpr std::string_view stringNoneTheme{ R"({
"name": "stringNone",
"window": {
"useMica": "none"
}
})" };

// Test boolean true
{
const auto schemeObject = VerifyParseSucceeded(booleanTrueTheme);
auto theme = Theme::FromJson(schemeObject);
VERIFY_ARE_EQUAL(L"booleanTrue", theme->Name());
VERIFY_IS_NOT_NULL(theme->Window());
VERIFY_ARE_EQUAL(winrt::Microsoft::Terminal::Settings::Model::MicaKind::Mica, theme->Window().UseMica());
}

// Test boolean false
{
const auto schemeObject = VerifyParseSucceeded(booleanFalseTheme);
auto theme = Theme::FromJson(schemeObject);
VERIFY_ARE_EQUAL(L"booleanFalse", theme->Name());
VERIFY_IS_NOT_NULL(theme->Window());
VERIFY_ARE_EQUAL(winrt::Microsoft::Terminal::Settings::Model::MicaKind::None, theme->Window().UseMica());
}

// Test string "mica"
{
const auto schemeObject = VerifyParseSucceeded(stringMicaTheme);
auto theme = Theme::FromJson(schemeObject);
VERIFY_ARE_EQUAL(L"stringMica", theme->Name());
VERIFY_IS_NOT_NULL(theme->Window());
VERIFY_ARE_EQUAL(winrt::Microsoft::Terminal::Settings::Model::MicaKind::Mica, theme->Window().UseMica());
}

// Test string "micaAlt"
{
const auto schemeObject = VerifyParseSucceeded(stringMicaAltTheme);
auto theme = Theme::FromJson(schemeObject);
VERIFY_ARE_EQUAL(L"stringMicaAlt", theme->Name());
VERIFY_IS_NOT_NULL(theme->Window());
VERIFY_ARE_EQUAL(winrt::Microsoft::Terminal::Settings::Model::MicaKind::MicaAlt, theme->Window().UseMica());
}

// Test string "none"
{
const auto schemeObject = VerifyParseSucceeded(stringNoneTheme);
auto theme = Theme::FromJson(schemeObject);
VERIFY_ARE_EQUAL(L"stringNone", theme->Name());
VERIFY_IS_NOT_NULL(theme->Window());
VERIFY_ARE_EQUAL(winrt::Microsoft::Terminal::Settings::Model::MicaKind::None, theme->Window().UseMica());
}
}
}
2 changes: 1 addition & 1 deletion src/cascadia/WindowsTerminal/AppHost.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -941,7 +941,7 @@ void AppHost::_updateTheme()
const auto colorOpacity = b ? color.A / 255.0 : 0.0;
const auto brushOpacity = _opacityFromBrush(b);
const auto opacity = std::min(colorOpacity, brushOpacity);
_window->UseMica(windowTheme ? windowTheme.UseMica() : false, opacity);
_window->UseMica(windowTheme ? windowTheme.UseMica() : winrt::Microsoft::Terminal::Settings::Model::MicaKind::None, opacity);

// This is a hack to make the window borders dark instead of light.
// It must be done before WM_NCPAINT so that the borders are rendered with
Expand Down
47 changes: 33 additions & 14 deletions src/cascadia/WindowsTerminal/IslandWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,14 @@
#include "../types/inc/Viewport.hpp"
#include "resource.h"
#include "icon.h"
#include <dwmapi.h>
#include <TerminalThemeHelpers.h>
#include <CoreWindow.h>
#include <dwmapi.h>
#include <TerminalThemeHelpers.h>
#include <CoreWindow.h>

// Define DWMSBT_TRANSIENTWINDOW if not available (for Mica Alt)

Check failure

Code scanning / check-spelling

Unrecognized Spelling Error

TRANSIENTWINDOW is not a recognized word. (unrecognized-spelling)
#ifndef DWMSBT_TRANSIENTWINDOW

Check failure

Code scanning / check-spelling

Unrecognized Spelling Error

TRANSIENTWINDOW is not a recognized word. (unrecognized-spelling)
#define DWMSBT_TRANSIENTWINDOW 3

Check failure

Code scanning / check-spelling

Unrecognized Spelling Error

TRANSIENTWINDOW is not a recognized word. (unrecognized-spelling)
#endif

extern "C" IMAGE_DOS_HEADER __ImageBase;

Expand Down Expand Up @@ -1839,17 +1844,31 @@
std::ignore = DwmSetWindowAttribute(GetHandle(), DWMWA_USE_IMMERSIVE_DARK_MODE, &attribute, sizeof(attribute));
}

void IslandWindow::UseMica(const bool newValue, const double /*titlebarOpacity*/)
{
// This block of code enables Mica for our window. By all accounts, this
// version of the code will only work on Windows 11, SV2. There's a slightly
// different API surface for enabling Mica on Windows 11 22000.0.
//
// This API was only publicly supported as of Windows 11 SV2, 22621. Before
// that version, this API will just return an error and do nothing silently.

const int attribute = newValue ? DWMSBT_MAINWINDOW : DWMSBT_NONE;
std::ignore = DwmSetWindowAttribute(GetHandle(), DWMWA_SYSTEMBACKDROP_TYPE, &attribute, sizeof(attribute));
void IslandWindow::UseMica(const winrt::Microsoft::Terminal::Settings::Model::MicaKind micaKind, const double /*titlebarOpacity*/)
{
// This block of code enables Mica for our window. By all accounts, this
// version of the code will only work on Windows 11, SV2. There's a slightly
// different API surface for enabling Mica on Windows 11 22000.0.
//
// This API was only publicly supported as of Windows 11 SV2, 22621. Before
// that version, this API will just return an error and do nothing silently.

int attribute = DWMSBT_NONE; // Default to no backdrop
switch (micaKind)
{
case winrt::Microsoft::Terminal::Settings::Model::MicaKind::None:
attribute = DWMSBT_NONE;
break;
case winrt::Microsoft::Terminal::Settings::Model::MicaKind::Mica:
attribute = DWMSBT_MAINWINDOW;
break;
case winrt::Microsoft::Terminal::Settings::Model::MicaKind::MicaAlt:
// DWMSBT_TRANSIENTWINDOW is the constant for Mica Alt

Check failure

Code scanning / check-spelling

Unrecognized Spelling Error

TRANSIENTWINDOW is not a recognized word. (unrecognized-spelling)
attribute = DWMSBT_TRANSIENTWINDOW;

Check failure

Code scanning / check-spelling

Unrecognized Spelling Error

TRANSIENTWINDOW is not a recognized word. (unrecognized-spelling)
break;
}

std::ignore = DwmSetWindowAttribute(GetHandle(), DWMWA_SYSTEMBACKDROP_TYPE, &attribute, sizeof(attribute));
}

// Method Description:
Expand Down
3 changes: 2 additions & 1 deletion src/cascadia/WindowsTerminal/IslandWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#pragma once
#include "BaseWindow.h"
#include <TerminalSettingsModel/Theme.h>

struct SystemMenuItemInfo
{
Expand Down Expand Up @@ -70,7 +71,7 @@ class IslandWindow :
void RemoveFromSystemMenu(const winrt::hstring& itemLabel);

void UseDarkTheme(const bool v);
virtual void UseMica(const bool newValue, const double titlebarOpacity);
virtual void UseMica(const winrt::Microsoft::Terminal::Settings::Model::MicaKind micaKind, const double titlebarOpacity);

til::event<winrt::delegate<>> DragRegionClicked;
til::event<winrt::delegate<>> WindowCloseButtonClicked;
Expand Down
22 changes: 11 additions & 11 deletions src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1189,15 +1189,15 @@ void NonClientIslandWindow::SetTitlebarBackground(winrt::Windows::UI::Xaml::Medi
_titlebar.Background(brush);
}

void NonClientIslandWindow::UseMica(const bool newValue, const double titlebarOpacity)
{
// Stash internally if we're using Mica. If we aren't, we don't want to
// totally blow away our titlebar with DwmExtendFrameIntoClientArea,
// especially on Windows 10
_useMica = newValue;
_titlebarOpacity = titlebarOpacity;
IslandWindow::UseMica(newValue, titlebarOpacity);
_UpdateFrameMargins();
void NonClientIslandWindow::UseMica(const winrt::Microsoft::Terminal::Settings::Model::MicaKind micaKind, const double titlebarOpacity)
{
// Stash internally if we're using Mica. If we aren't, we don't want to
// totally blow away our titlebar with DwmExtendFrameIntoClientArea,
// especially on Windows 10
_useMica = micaKind != winrt::Microsoft::Terminal::Settings::Model::MicaKind::None;
_titlebarOpacity = titlebarOpacity;

IslandWindow::UseMica(micaKind, titlebarOpacity);

_UpdateFrameMargins();
}
2 changes: 1 addition & 1 deletion src/cascadia/WindowsTerminal/NonClientIslandWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class NonClientIslandWindow : public IslandWindow
void SetTitlebarBackground(winrt::Windows::UI::Xaml::Media::Brush brush);
void SetShowTabsFullscreen(const bool newShowTabsFullscreen) override;

virtual void UseMica(const bool newValue, const double titlebarOpacity) override;
virtual void UseMica(const winrt::Microsoft::Terminal::Settings::Model::MicaKind micaKind, const double titlebarOpacity) override;

private:
std::optional<til::point> _oldIslandPos;
Expand Down