Skip to content

Commit

Permalink
Use a dark titlebar when we've requested dark theme (#14536)
Browse files Browse the repository at this point in the history
This applies to `"showTabsInTitlebar": false,`. We literally never set that for the `IslandWindow` before, only ever the NCIW. 

Closes #11589


![update-titlebar-for-theme](https://user-images.githubusercontent.com/18356694/207109370-a63a8b19-4c42-4b1f-8d39-8c3abdf1b403.gif)


For a dramatic example - here's the IW with mica enabled, in dark mode:

![image](https://user-images.githubusercontent.com/18356694/207109465-a6165637-31a5-45a4-bff0-51ac79404cd6.png)

Theme json:

```json
        {
            "name": "chonk",
            "tab":
            {
                "background": "#00000000",
                "unfocusedBackground": "#00000000",
                "showCloseButton": "never"
            },
            "tabRow":
            {
                "background": "#00000000",
                "unfocusedBackground": "#00000000",
            },
            "window":
            {
                "applicationTheme": "dark",
                "useMica": true
            }
        },
```
  • Loading branch information
zadjii-msft authored Jan 19, 2023
1 parent eab1c23 commit 79eb9b3
Show file tree
Hide file tree
Showing 13 changed files with 66 additions and 45 deletions.
3 changes: 1 addition & 2 deletions src/cascadia/TerminalSettingsModel/GlobalAppSettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
#include "../../types/inc/Utils.hpp"
#include "JsonUtils.h"
#include "KeyChordSerialization.h"
#include "SettingsUtils.h"

#include "GlobalAppSettings.g.cpp"

Expand Down Expand Up @@ -213,7 +212,7 @@ Json::Value GlobalAppSettings::ToJson() const

winrt::Microsoft::Terminal::Settings::Model::Theme GlobalAppSettings::CurrentTheme() noexcept
{
auto requestedTheme = IsSystemInDarkTheme() ?
auto requestedTheme = Model::Theme::IsSystemInDarkTheme() ?
winrt::Windows::UI::Xaml::ElementTheme::Dark :
winrt::Windows::UI::Xaml::ElementTheme::Light;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,6 @@
<ClInclude Include="WslDistroGenerator.h" />
<ClInclude Include="SshHostGenerator.h" />
<ClInclude Include="ModelSerializationHelpers.h" />
<ClInclude Include="SettingsUtils.h" />
</ItemGroup>
<!-- ========================= Cpp Files ======================== -->
<ItemGroup>
Expand Down
6 changes: 0 additions & 6 deletions src/cascadia/TerminalSettingsModel/SettingsUtils.h

This file was deleted.

13 changes: 1 addition & 12 deletions src/cascadia/TerminalSettingsModel/TerminalSettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,10 @@

#include "TerminalSettings.g.cpp"
#include "TerminalSettingsCreateResult.g.cpp"
#include "SettingsUtils.h"

using namespace winrt::Microsoft::Terminal::Control;
using namespace Microsoft::Console::Utils;

// I'm not even joking, this is the recommended way to do this:
// https://learn.microsoft.com/en-us/windows/apps/desktop/modernize/apply-windows-themes#know-when-dark-mode-is-enabled
bool IsSystemInDarkTheme()
{
static auto isColorLight = [](const winrt::Windows::UI::Color& clr) -> bool {
return (((5 * clr.G) + (2 * clr.R) + clr.B) > (8 * 128));
};
return isColorLight(winrt::Windows::UI::ViewManagement::UISettings().GetColorValue(winrt::Windows::UI::ViewManagement::UIColorType::Foreground));
};

namespace winrt::Microsoft::Terminal::Settings::Model::implementation
{
static std::tuple<Windows::UI::Xaml::HorizontalAlignment, Windows::UI::Xaml::VerticalAlignment> ConvertConvergedAlignment(ConvergedAlignment alignment)
Expand Down Expand Up @@ -204,7 +193,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
auto requestedTheme = currentTheme.RequestedTheme();
if (requestedTheme == winrt::Windows::UI::Xaml::ElementTheme::Default)
{
requestedTheme = IsSystemInDarkTheme() ?
requestedTheme = Model::Theme::IsSystemInDarkTheme() ?
winrt::Windows::UI::Xaml::ElementTheme::Dark :
winrt::Windows::UI::Xaml::ElementTheme::Light;
}
Expand Down
10 changes: 10 additions & 0 deletions src/cascadia/TerminalSettingsModel/Theme.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -362,3 +362,13 @@ winrt::com_ptr<ThemePair> ThemePair::Copy() const
pair->_LightName = _LightName;
return pair;
}

// I'm not even joking, this is the recommended way to do this:
// https://learn.microsoft.com/en-us/windows/apps/desktop/modernize/apply-windows-themes#know-when-dark-mode-is-enabled
bool Theme::IsSystemInDarkTheme()
{
static auto isColorLight = [](const winrt::Windows::UI::Color& clr) -> bool {
return (((5 * clr.G) + (2 * clr.R) + clr.B) > (8 * 128));
};
return isColorLight(winrt::Windows::UI::ViewManagement::UISettings().GetColorValue(winrt::Windows::UI::ViewManagement::UIColorType::Foreground));
};
2 changes: 2 additions & 0 deletions src/cascadia/TerminalSettingsModel/Theme.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation

winrt::Windows::UI::Xaml::ElementTheme RequestedTheme() const noexcept;

static bool IsSystemInDarkTheme();

WINRT_PROPERTY(winrt::hstring, Name);

MTSM_THEME_SETTINGS(THEME_SETTINGS_INITIALIZE)
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 @@ -78,6 +78,7 @@ namespace Microsoft.Terminal.Settings.Model

// A helper for retrieving the RequestedTheme out of the window property
Windows.UI.Xaml.ElementTheme RequestedTheme { get; };
static Boolean IsSystemInDarkTheme();

}
}
20 changes: 20 additions & 0 deletions src/cascadia/WindowsTerminal/AppHost.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1344,6 +1344,20 @@ winrt::fire_and_forget AppHost::_RenameWindowRequested(const winrt::Windows::Fou
}
}

bool _isActuallyDarkTheme(const auto requestedTheme)
{
switch (requestedTheme)
{
case winrt::Windows::UI::Xaml::ElementTheme::Light:
return false;
case winrt::Windows::UI::Xaml::ElementTheme::Dark:
return true;
case winrt::Windows::UI::Xaml::ElementTheme::Default:
default:
return Theme::IsSystemInDarkTheme();
}
}

void AppHost::_updateTheme()
{
auto theme = _logic.Theme();
Expand All @@ -1353,6 +1367,12 @@ void AppHost::_updateTheme()
const auto b = _logic.TitlebarBrush();
const auto opacity = b ? ThemeColor::ColorFromBrush(b).A / 255.0 : 0.0;
_window->UseMica(theme.Window() ? theme.Window().UseMica() : false, 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
// the correct theme.
// For more information, see GH#6620.
LOG_IF_FAILED(TerminalTrySetDarkTheme(_window->GetHandle(), _isActuallyDarkTheme(theme.RequestedTheme())));
}

void AppHost::_HandleSettingsChanged(const winrt::Windows::Foundation::IInspectable& /*sender*/,
Expand Down
4 changes: 2 additions & 2 deletions src/cascadia/WindowsTerminal/BaseWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class BaseWindow
WINRT_ASSERT(!that->_window);
that->_window = wil::unique_hwnd(window);

return that->_OnNcCreate(wparam, lparam);
return that->OnNcCreate(wparam, lparam);
}
else if (T* that = GetThisFromHandle(window))
{
Expand Down Expand Up @@ -214,7 +214,7 @@ class BaseWindow
// - This method is called when the window receives the WM_NCCREATE message.
// Return Value:
// - The value returned from the window proc.
virtual [[nodiscard]] LRESULT _OnNcCreate(WPARAM wParam, LPARAM lParam) noexcept
virtual [[nodiscard]] LRESULT OnNcCreate(WPARAM wParam, LPARAM lParam) noexcept
{
SetWindowLongPtr(_window.get(), GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));

Expand Down
26 changes: 26 additions & 0 deletions src/cascadia/WindowsTerminal/IslandWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1913,3 +1913,29 @@ void IslandWindow::UseMica(const bool newValue, const double /*titlebarOpacity*/
const int attribute = newValue ? DWMSBT_MAINWINDOW : DWMSBT_NONE;
std::ignore = DwmSetWindowAttribute(GetHandle(), DWMWA_SYSTEMBACKDROP_TYPE, &attribute, sizeof(attribute));
}

// Method Description:
// - This method is called when the window receives the WM_NCCREATE message.
// Return Value:
// - The value returned from the window proc.
[[nodiscard]] LRESULT IslandWindow::OnNcCreate(WPARAM wParam, LPARAM lParam) noexcept
{
const auto ret = BaseWindow::OnNcCreate(wParam, lParam);
if (!ret)
{
return FALSE;
}

// 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
// the correct theme.
// For more information, see GH#6620.
//
// Theoretically, we don't need this anymore, since _updateTheme will update
// the darkness of our window. However, we're keeping this call to prevent
// the window from appearing as a white rectangle for a frame before we load
// the rest of the settings.
LOG_IF_FAILED(TerminalTrySetDarkTheme(_window.get(), true));

return TRUE;
}
3 changes: 3 additions & 0 deletions src/cascadia/WindowsTerminal/IslandWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ class IslandWindow :
HWND GetInteropHandle() const;

[[nodiscard]] virtual LRESULT MessageHandler(UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept override;

[[nodiscard]] LRESULT OnNcCreate(WPARAM wParam, LPARAM lParam) noexcept override;

void OnResize(const UINT width, const UINT height) override;
void OnMinimize() override;
void OnRestore() override;
Expand Down
21 changes: 0 additions & 21 deletions src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1044,27 +1044,6 @@ void NonClientIslandWindow::_UpdateFrameMargins() const noexcept
return 0;
}

// Method Description:
// - This method is called when the window receives the WM_NCCREATE message.
// Return Value:
// - The value returned from the window proc.
[[nodiscard]] LRESULT NonClientIslandWindow::_OnNcCreate(WPARAM wParam, LPARAM lParam) noexcept
{
const auto ret = IslandWindow::_OnNcCreate(wParam, lParam);
if (!ret)
{
return FALSE;
}

// 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
// the correct theme.
// For more information, see GH#6620.
LOG_IF_FAILED(TerminalTrySetDarkTheme(_window.get(), true));

return TRUE;
}

// Method Description:
// - Called when the app wants to change its theme. We'll update the frame
// theme to match the new theme.
Expand Down
1 change: 0 additions & 1 deletion src/cascadia/WindowsTerminal/NonClientIslandWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ class NonClientIslandWindow : public IslandWindow
int _GetTopBorderHeight() const noexcept;
LRESULT _dragBarNcHitTest(const til::point pointer);

[[nodiscard]] LRESULT _OnNcCreate(WPARAM wParam, LPARAM lParam) noexcept override;
[[nodiscard]] LRESULT _OnNcCalcSize(const WPARAM wParam, const LPARAM lParam) noexcept;
[[nodiscard]] LRESULT _OnNcHitTest(POINT ptMouse) const noexcept;
[[nodiscard]] LRESULT _OnPaint() noexcept;
Expand Down

0 comments on commit 79eb9b3

Please sign in to comment.