Skip to content

Re-add support for Mica, transparent titlebars #13935

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
20 commits merged into from
Dec 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
8c3c8fe
Revert "Remove the `useMica` key (#13872)"
zadjii-msft Sep 6, 2022
0a3a537
Clip the drag rect to the right side of the window. I don't think thi…
zadjii-msft Sep 6, 2022
2fcc420
add support for transparent titlebars back, for testing.
zadjii-msft Sep 6, 2022
337c5e9
hey this works - let's clean it up and figure out what is/n't important
zadjii-msft Sep 6, 2022
c77173b
Add better support in the Theme objects themselves for transparency
zadjii-msft Sep 6, 2022
df6d4cd
way easier
zadjii-msft Sep 6, 2022
2895a34
notes, mostly
zadjii-msft Sep 6, 2022
c42965e
Merge branch 'main' into dev/migrie/f/transparent-tab-row-002
zadjii-msft Nov 2, 2022
e9f8569
hey, we can use the real api now
zadjii-msft Nov 3, 2022
4964d8b
Merge remote-tracking branch 'origin/main' into dev/migrie/f/transpar…
zadjii-msft Nov 14, 2022
9058c41
runformat
zadjii-msft Nov 14, 2022
28cf394
Migrate spelling-0.0.21 changes from main
DHowett Nov 14, 2022
816c249
Merge remote-tracking branch 'origin/main' into dev/migrie/f/transpar…
zadjii-msft Nov 30, 2022
74cf07e
Merge remote-tracking branch 'origin/main' into dev/migrie/f/transpar…
zadjii-msft Dec 1, 2022
28a718a
REAALLY
zadjii-msft Dec 1, 2022
c652e95
uhg
zadjii-msft Dec 1, 2022
a22f433
Merge remote-tracking branch 'origin/main' into dev/migrie/f/transpar…
zadjii-msft Dec 8, 2022
976688a
THIS WONT WORK Don't blow away titlebar This should satisfy the remai…
zadjii-msft Dec 8, 2022
6dd6726
also, account for how transparent a titlebar might be
zadjii-msft Dec 8, 2022
2b00052
runformat
zadjii-msft Dec 9, 2022
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
16 changes: 11 additions & 5 deletions src/cascadia/LocalTests_SettingsModel/ThemeTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ namespace SettingsModelLocalTests
},
"window":
{
"applicationTheme": "light"
"applicationTheme": "light",
"useMica": true
}
})" };

Expand All @@ -80,6 +81,7 @@ namespace SettingsModelLocalTests

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());
}

void ThemeTests::ParseEmptyTheme()
Expand Down Expand Up @@ -161,7 +163,8 @@ namespace SettingsModelLocalTests
},
"window":
{
"applicationTheme": "light"
"applicationTheme": "light",
"useMica": true
}
},
{
Expand All @@ -172,14 +175,16 @@ namespace SettingsModelLocalTests
},
"window":
{
"applicationTheme": "light"
"applicationTheme": "light",
"useMica": true
}
},
{
"name": "backgroundOmittedEntirely",
"window":
{
"applicationTheme": "light"
"applicationTheme": "light",
"useMica": true
}
}
]
Expand Down Expand Up @@ -234,7 +239,8 @@ namespace SettingsModelLocalTests
"tabRow": {},
"window":
{
"applicationTheme": "light"
"applicationTheme": "light",
"useMica": true
}
}
]
Expand Down
12 changes: 10 additions & 2 deletions src/cascadia/TerminalControl/TermControl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -630,7 +630,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
//
// Firing it manually makes sure it does.
_BackgroundBrush = RootGrid().Background();
_PropertyChangedHandlers(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"BackgroundBrush" });
_PropertyChangedHandlers(*this, Data::PropertyChangedEventArgs{ L"BackgroundBrush" });

_isBackgroundLight = _isColorLight(bg);
}
Expand All @@ -652,7 +652,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
{
const auto opacity{ _core.Opacity() };
const auto useAcrylic{ _core.UseAcrylic() };

auto changed = false;
// GH#11743, #11619: If we're changing whether or not acrylic is used,
// then just entirely reinitialize the brush. The primary way that this
// happens is on Windows 10, where we need to enable acrylic when the
Expand All @@ -666,6 +666,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_InitializeBackgroundBrush();
return;
}
changed = acrylic.TintOpacity() != opacity;
acrylic.TintOpacity(opacity);
}
else if (auto solidColor = RootGrid().Background().try_as<Media::SolidColorBrush>())
Expand All @@ -675,8 +676,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_InitializeBackgroundBrush();
return;
}
changed = solidColor.Opacity() != opacity;
solidColor.Opacity(opacity);
}
// Send a BG brush changed event, so you can mouse wheel the
// transparency of the titlebar too.
if (changed)
{
_PropertyChangedHandlers(*this, Data::PropertyChangedEventArgs{ L"BackgroundBrush" });
}
}

TermControl::~TermControl()
Expand Down
5 changes: 3 additions & 2 deletions src/cascadia/TerminalSettingsModel/MTSMSettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,9 @@ 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)
#define MTSM_THEME_WINDOW_SETTINGS(X) \
X(winrt::Windows::UI::Xaml::ElementTheme, RequestedTheme, "applicationTheme", winrt::Windows::UI::Xaml::ElementTheme::Default) \
X(bool, UseMica, "useMica", false)

#define MTSM_THEME_TABROW_SETTINGS(X) \
X(winrt::Microsoft::Terminal::Settings::Model::ThemeColor, Background, "background", nullptr) \
Expand Down
47 changes: 1 addition & 46 deletions src/cascadia/TerminalSettingsModel/Theme.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,6 @@ winrt::WUX::Media::Brush ThemeColor::Evaluate(const winrt::WUX::ResourceDictiona
{
static const auto accentColorKey{ winrt::box_value(L"SystemAccentColor") };

// NOTE: Currently, the DWM titlebar is always drawn, underneath our XAML
// content. If the opacity is <1.0, then you'll be able to see it, including
// the original caption buttons, which we don't want.

switch (ColorType())
{
case ThemeColorType::Accent:
Expand All @@ -148,51 +144,10 @@ winrt::WUX::Media::Brush ThemeColor::Evaluate(const winrt::WUX::ResourceDictiona
}
case ThemeColorType::Color:
{
return winrt::WUX::Media::SolidColorBrush{ forTitlebar ?
Color().with_alpha(255) :
Color() };
return winrt::WUX::Media::SolidColorBrush{ Color() };
}
case ThemeColorType::TerminalBackground:
{
// If we're evaluating this color for the tab row, there are some rules
// we have to follow, unfortunately. We can't allow a transparent
// background, so we have to make sure to fill that in with Opacity(1.0)
// manually.
//
// So for that case, just make a new brush with the relevant properties
// set.
if (forTitlebar)
{
if (auto acrylic = terminalBackground.try_as<winrt::WUX::Media::AcrylicBrush>())
{
winrt::WUX::Media::AcrylicBrush newBrush{};
newBrush.TintColor(acrylic.TintColor());
newBrush.FallbackColor(acrylic.FallbackColor());
newBrush.TintLuminosityOpacity(acrylic.TintLuminosityOpacity());

// Allow acrylic opacity, but it's gotta be HostBackdrop acrylic.
//
// For now, just always use 50% opacity for this. If we do ever
// figure out how to get rid of our titlebar under the XAML tab
// row (GH#10509), we can always get rid of the HostBackdrop
// thing, and all this copying, and just return the
// terminalBackground brush directly.
//
// Because we're wholesale copying the brush, we won't be able
// to adjust it's opacity with the mouse wheel. This seems like
// an acceptable tradeoff for now.
newBrush.TintOpacity(.5);
newBrush.BackgroundSource(winrt::WUX::Media::AcrylicBackgroundSource::HostBackdrop);
return newBrush;
}
else if (auto solidColor = terminalBackground.try_as<winrt::WUX::Media::SolidColorBrush>())
{
winrt::WUX::Media::SolidColorBrush newBrush{};
newBrush.Color(til::color{ solidColor.Color() }.with_alpha(255));
return newBrush;
}
}

return terminalBackground;
}
}
Expand Down
1 change: 1 addition & 0 deletions src/cascadia/TerminalSettingsModel/Theme.idl
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ namespace Microsoft.Terminal.Settings.Model

runtimeclass WindowTheme {
Windows.UI.Xaml.ElementTheme RequestedTheme { get; };
Boolean UseMica { get; };
}

runtimeclass TabRowTheme {
Expand Down
14 changes: 3 additions & 11 deletions src/cascadia/WindowsTerminal/AppHost.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1350,17 +1350,9 @@ void AppHost::_updateTheme()

_window->OnApplicationThemeChanged(theme.RequestedTheme());

// 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 code is left here, commented out, for future enablement of Mica.
// We'll revisit this in GH#10509. Because we can't enable transparent
// titlebars for showing Mica currently, we're just gonna disable it
// entirely while we sort that out.
//
// const int attribute = theme.Window().UseMica() ? /*DWMSBT_MAINWINDOW*/ 2 : /*DWMSBT_NONE*/ 1;
// DwmSetWindowAttribute(_window->GetHandle(), /* DWMWA_SYSTEMBACKDROP_TYPE */ 38, &attribute, sizeof(attribute));
const auto b = _logic.TitlebarBrush();
const auto opacity = b ? ThemeColor::ColorFromBrush(b).A / 255.0 : 0.0;
_window->UseMica(theme.Window().UseMica(), opacity);
}

void AppHost::_HandleSettingsChanged(const winrt::Windows::Foundation::IInspectable& /*sender*/,
Expand Down
13 changes: 13 additions & 0 deletions src/cascadia/WindowsTerminal/IslandWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1894,3 +1894,16 @@ void IslandWindow::RemoveFromSystemMenu(const winrt::hstring& itemLabel)
}
_systemMenuItems.erase(it->first);
}

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));
}
2 changes: 2 additions & 0 deletions src/cascadia/WindowsTerminal/IslandWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ class IslandWindow :
void AddToSystemMenu(const winrt::hstring& itemLabel, winrt::delegate<void()> callback);
void RemoveFromSystemMenu(const winrt::hstring& itemLabel);

virtual void UseMica(const bool newValue, const double titlebarOpacity);

WINRT_CALLBACK(DragRegionClicked, winrt::delegate<>);
WINRT_CALLBACK(WindowCloseButtonClicked, winrt::delegate<>);
WINRT_CALLBACK(MouseScrolled, winrt::delegate<void(til::point, int32_t)>);
Expand Down
48 changes: 45 additions & 3 deletions src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -442,11 +442,21 @@ til::rect NonClientIslandWindow::_GetDragAreaRect() const noexcept
static_cast<float>(_rootGrid.ActualWidth()),
static_cast<float>(_dragBar.ActualHeight())
};

const auto clientDragBarRect = transform.TransformBounds(logicalDragBarRect);

// Make sure to trim the right side of the rectangle, so that it doesn't
// hang off the right side of the root window. This normally wouldn't
// matter, but UIA will still think its bounds can extend past the right
// of the parent HWND.
Comment on lines +448 to +451
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whoa, what does THIS fix?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the thing that does nothing for 13631? Should we revert it since it does nothing?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't do nothing - it actually makes the UIA bounding box sane, rather than hanging way off the edge of the window.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can pull that into a separate PR if you want.

//
// x here is the width of the tabs.
const auto x = gsl::narrow_cast<til::CoordType>(clientDragBarRect.X * scale);

return {
gsl::narrow_cast<til::CoordType>(clientDragBarRect.X * scale),
x,
gsl::narrow_cast<til::CoordType>(clientDragBarRect.Y * scale),
gsl::narrow_cast<til::CoordType>((clientDragBarRect.Width + clientDragBarRect.X) * scale),
gsl::narrow_cast<til::CoordType>((clientDragBarRect.Width + clientDragBarRect.X) * scale) - x,
gsl::narrow_cast<til::CoordType>((clientDragBarRect.Height + clientDragBarRect.Y) * scale),
};
}
Expand Down Expand Up @@ -879,7 +889,26 @@ void NonClientIslandWindow::_UpdateFrameMargins() const noexcept
// at the top) in the WM_PAINT handler. This eliminates the transparency
// bug and it's what a lot of Win32 apps that customize the title bar do
// so it should work fine.
margins.cyTopHeight = -frame.top;
//
// Notes #3 (circa late 2022): We want to make some changes here to
// support Mica. This introduces some complications.
// - If we leave the titlebar visible AT ALL, then a transparent
// titlebar (theme.tabRow.background:#ff00ff00 for example) will allow
// the DWM titlebar to be visible, underneath our content. EVEN MORE
// SO: Mica + "show accent color on title bars" will _always_ show the
// accent-colored strip of the titlebar, even on top of the Mica.
// - It _seems_ like we can just set this to 0, and have it work. You'd
// be wrong. On Windows 10, setting this to 0 will cause the topmost
// pixel of our window to be just a little darker than the rest of the
// frame. So ONLY set this to 0 when the user has explicitly asked for
// Mica. Though it won't do anything on Windows 10, they should be
// able to opt back out of having that weird dark pixel.
// - This is LOAD-BEARING. By having the titlebar a totally empty rect,
// DWM will know that we don't have the traditional titlebar, and will
// use NCHITTEST to determine where to place the Snap Flyout. The drag
// rect will handle that.

margins.cyTopHeight = (_useMica || _titlebarOpacity < 1.0) ? 0 : -frame.top;
}

// Extend the frame into the client area. microsoft/terminal#2735 - Just log
Expand Down Expand Up @@ -1132,3 +1161,16 @@ 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();
}
5 changes: 5 additions & 0 deletions src/cascadia/WindowsTerminal/NonClientIslandWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ class NonClientIslandWindow : public IslandWindow

void SetTitlebarBackground(winrt::Windows::UI::Xaml::Media::Brush brush);

virtual void UseMica(const bool newValue, const double titlebarOpacity) override;

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

Expand All @@ -63,6 +65,9 @@ class NonClientIslandWindow : public IslandWindow

winrt::Windows::UI::Xaml::ElementTheme _theme;

bool _useMica{ false };
double _titlebarOpacity{ 1.0 };

bool _isMaximized;
bool _trackingMouse{ false };

Expand Down