Skip to content

Commit 8d94edd

Browse files
authored
Dim the caption buttons for unfocused windows (#19668)
This PR closes #12632 by dimming the caption controls in the titlebar when unfocused. Leaves them intact when in high contrast mode. The color used is borrowed from PowerToys' unfocused color. ## Validation Steps Performed Tested by hovering and unhovering in focused and unfocused states, as well as in high contrast mode. States are consistent and applied correctly. I did notice that clicking on the titlebar wouldn't put it into focus unless I also moved my mouse though, but that is also present in the release branch. Closes #12632
1 parent e8971c8 commit 8d94edd

File tree

9 files changed

+96
-15
lines changed

9 files changed

+96
-15
lines changed

.github/actions/spelling/expect/expect.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1064,6 +1064,7 @@ Mypair
10641064
Myval
10651065
NAMELENGTH
10661066
namestream
1067+
NCACTIVATE
10671068
NCCALCSIZE
10681069
NCCREATE
10691070
NCLBUTTONDOWN

src/cascadia/TerminalApp/MinMaxCloseControl.cpp

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,18 @@ namespace winrt::TerminalApp::implementation
8888
CloseClick.raise(*this, e);
8989
}
9090

91+
bool MinMaxCloseControl::Focused() const
92+
{
93+
return _focused;
94+
}
95+
96+
void MinMaxCloseControl::Focused(bool focused)
97+
{
98+
_focused = focused;
99+
100+
ReleaseButtons();
101+
}
102+
91103
void MinMaxCloseControl::SetWindowVisualState(WindowVisualState visualState)
92104
{
93105
// Look up the heights we should use for the caption buttons from our
@@ -169,25 +181,25 @@ namespace winrt::TerminalApp::implementation
169181
// animate the fade in/out transition between colors.
170182
case CaptionButton::Minimize:
171183
VisualStateManager::GoToState(MinimizeButton(), L"PointerOver", true);
172-
VisualStateManager::GoToState(MaximizeButton(), L"Normal", true);
173-
VisualStateManager::GoToState(CloseButton(), L"Normal", true);
184+
VisualStateManager::GoToState(MaximizeButton(), _normalState(), true);
185+
VisualStateManager::GoToState(CloseButton(), _normalState(), true);
174186

175187
_displayToolTip->Run(MinimizeButton());
176188
closeToolTipForButton(MaximizeButton());
177189
closeToolTipForButton(CloseButton());
178190
break;
179191
case CaptionButton::Maximize:
180-
VisualStateManager::GoToState(MinimizeButton(), L"Normal", true);
192+
VisualStateManager::GoToState(MinimizeButton(), _normalState(), true);
181193
VisualStateManager::GoToState(MaximizeButton(), L"PointerOver", true);
182-
VisualStateManager::GoToState(CloseButton(), L"Normal", true);
194+
VisualStateManager::GoToState(CloseButton(), _normalState(), true);
183195

184196
closeToolTipForButton(MinimizeButton());
185197
_displayToolTip->Run(MaximizeButton());
186198
closeToolTipForButton(CloseButton());
187199
break;
188200
case CaptionButton::Close:
189-
VisualStateManager::GoToState(MinimizeButton(), L"Normal", true);
190-
VisualStateManager::GoToState(MaximizeButton(), L"Normal", true);
201+
VisualStateManager::GoToState(MinimizeButton(), _normalState(), true);
202+
VisualStateManager::GoToState(MaximizeButton(), _normalState(), true);
191203
VisualStateManager::GoToState(CloseButton(), L"PointerOver", true);
192204

193205
closeToolTipForButton(MinimizeButton());
@@ -210,17 +222,17 @@ namespace winrt::TerminalApp::implementation
210222
{
211223
case CaptionButton::Minimize:
212224
VisualStateManager::GoToState(MinimizeButton(), L"Pressed", true);
213-
VisualStateManager::GoToState(MaximizeButton(), L"Normal", true);
214-
VisualStateManager::GoToState(CloseButton(), L"Normal", true);
225+
VisualStateManager::GoToState(MaximizeButton(), _normalState(), true);
226+
VisualStateManager::GoToState(CloseButton(), _normalState(), true);
215227
break;
216228
case CaptionButton::Maximize:
217-
VisualStateManager::GoToState(MinimizeButton(), L"Normal", true);
229+
VisualStateManager::GoToState(MinimizeButton(), _normalState(), true);
218230
VisualStateManager::GoToState(MaximizeButton(), L"Pressed", true);
219-
VisualStateManager::GoToState(CloseButton(), L"Normal", true);
231+
VisualStateManager::GoToState(CloseButton(), _normalState(), true);
220232
break;
221233
case CaptionButton::Close:
222-
VisualStateManager::GoToState(MinimizeButton(), L"Normal", true);
223-
VisualStateManager::GoToState(MaximizeButton(), L"Normal", true);
234+
VisualStateManager::GoToState(MinimizeButton(), _normalState(), true);
235+
VisualStateManager::GoToState(MaximizeButton(), _normalState(), true);
224236
VisualStateManager::GoToState(CloseButton(), L"Pressed", true);
225237
break;
226238
}
@@ -233,14 +245,21 @@ namespace winrt::TerminalApp::implementation
233245
void MinMaxCloseControl::ReleaseButtons()
234246
{
235247
_displayToolTip->Run(nullptr);
236-
VisualStateManager::GoToState(MinimizeButton(), L"Normal", true);
237-
VisualStateManager::GoToState(MaximizeButton(), L"Normal", true);
238-
VisualStateManager::GoToState(CloseButton(), L"Normal", true);
248+
VisualStateManager::GoToState(MinimizeButton(), _normalState(), true);
249+
VisualStateManager::GoToState(MaximizeButton(), _normalState(), true);
250+
VisualStateManager::GoToState(CloseButton(), _normalState(), true);
239251

240252
closeToolTipForButton(MinimizeButton());
241253
closeToolTipForButton(MaximizeButton());
242254
closeToolTipForButton(CloseButton());
243255

244256
_lastPressedButton = std::nullopt;
245257
}
258+
259+
const winrt::param::hstring& MinMaxCloseControl::_normalState() const
260+
{
261+
static const winrt::param::hstring normal = L"Normal";
262+
static const winrt::param::hstring unfocused = L"Unfocused";
263+
return (_focused ? normal : unfocused);
264+
}
246265
}

src/cascadia/TerminalApp/MinMaxCloseControl.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ namespace winrt::TerminalApp::implementation
2121
void PressButton(CaptionButton button);
2222
void ReleaseButtons();
2323

24+
bool Focused() const;
25+
void Focused(bool focused);
26+
2427
void _MinimizeClick(const winrt::Windows::Foundation::IInspectable& sender,
2528
const winrt::Windows::UI::Xaml::RoutedEventArgs& e);
2629
void _MaximizeClick(const winrt::Windows::Foundation::IInspectable& sender,
@@ -32,8 +35,12 @@ namespace winrt::TerminalApp::implementation
3235
til::typed_event<TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs> MaximizeClick;
3336
til::typed_event<TerminalApp::MinMaxCloseControl, winrt::Windows::UI::Xaml::RoutedEventArgs> CloseClick;
3437

38+
bool _focused{ false };
3539
std::shared_ptr<ThrottledFunc<winrt::Windows::UI::Xaml::Controls::Button>> _displayToolTip{ nullptr };
3640
std::optional<CaptionButton> _lastPressedButton{ std::nullopt };
41+
42+
private:
43+
const winrt::param::hstring& _normalState() const;
3744
};
3845
}
3946

src/cascadia/TerminalApp/MinMaxCloseControl.idl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ namespace TerminalApp
1414
void HoverButton(CaptionButton button);
1515
void PressButton(CaptionButton button);
1616
void ReleaseButtons();
17+
Boolean Focused { get; set; };
1718

1819
event Windows.Foundation.TypedEventHandler<MinMaxCloseControl, Windows.UI.Xaml.RoutedEventArgs> MinimizeClick;
1920
event Windows.Foundation.TypedEventHandler<MinMaxCloseControl, Windows.UI.Xaml.RoutedEventArgs> MaximizeClick;

src/cascadia/TerminalApp/MinMaxCloseControl.xaml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@
3232
ResourceKey="SystemControlForegroundBaseHighBrush" />
3333
<StaticResource x:Key="CaptionButtonForegroundPressed"
3434
ResourceKey="SystemControlForegroundBaseHighBrush" />
35+
<StaticResource x:Key="CaptionButtonForegroundUnfocusedColor"
36+
ResourceKey="TextFillColorDisabled" />
37+
<SolidColorBrush x:Key="CaptionButtonForegroundUnfocused"
38+
Color="{ThemeResource CaptionButtonForegroundUnfocusedColor}" />
3539
<SolidColorBrush x:Key="CaptionButtonBackground"
3640
Color="Transparent" />
3741
<Color x:Key="CaptionButtonBackgroundColor">Transparent</Color>
@@ -66,6 +70,10 @@
6670
ResourceKey="SystemControlForegroundBaseHighBrush" />
6771
<StaticResource x:Key="CaptionButtonForegroundPressed"
6872
ResourceKey="SystemControlForegroundBaseHighBrush" />
73+
<StaticResource x:Key="CaptionButtonForegroundUnfocusedColor"
74+
ResourceKey="TextFillColorDisabled" />
75+
<SolidColorBrush x:Key="CaptionButtonForegroundUnfocused"
76+
Color="{ThemeResource CaptionButtonForegroundUnfocusedColor}" />
6977
<SolidColorBrush x:Key="CaptionButtonBackground"
7078
Color="Transparent" />
7179
<Color x:Key="CaptionButtonBackgroundColor">Transparent</Color>
@@ -103,6 +111,10 @@
103111
Color="{ThemeResource SystemColorHighlightTextColor}" />
104112
<SolidColorBrush x:Key="CaptionButtonForegroundPressed"
105113
Color="{ThemeResource SystemColorHighlightTextColor}" />
114+
<SolidColorBrush x:Key="CaptionButtonForegroundUnfocused"
115+
Color="{ThemeResource SystemColorButtonTextColor}" />
116+
<StaticResource x:Key="CaptionButtonForegroundUnfocusedColor"
117+
ResourceKey="SystemColorButtonTextColor" />
106118
<SolidColorBrush x:Key="CloseButtonBackgroundPointerOver"
107119
Color="{ThemeResource SystemColorHighlightColor}" />
108120
<SolidColorBrush x:Key="CloseButtonForegroundPointerOver"
@@ -189,6 +201,20 @@
189201
Duration="0:0:0.1" />
190202
</Storyboard>
191203
</VisualTransition>
204+
205+
<VisualTransition From="PointerOver"
206+
To="Unfocused">
207+
<Storyboard>
208+
<ColorAnimation Storyboard.TargetName="ButtonBaseElement"
209+
Storyboard.TargetProperty="(UIElement.Background).(SolidColorBrush.Color)"
210+
To="{ThemeResource CaptionButtonBackgroundColor}"
211+
Duration="0:0:0.15" />
212+
<ColorAnimation Storyboard.TargetName="ButtonIcon"
213+
Storyboard.TargetProperty="(UIElement.Foreground).(SolidColorBrush.Color)"
214+
To="{ThemeResource CaptionButtonForegroundUnfocusedColor}"
215+
Duration="0:0:0.1" />
216+
</Storyboard>
217+
</VisualTransition>
192218
</VisualStateGroup.Transitions>
193219

194220
<VisualState x:Name="Normal">
@@ -198,6 +224,13 @@
198224
</VisualState.Setters>
199225
</VisualState>
200226

227+
<VisualState x:Name="Unfocused">
228+
<VisualState.Setters>
229+
<Setter Target="ButtonBaseElement.Background" Value="{ThemeResource CaptionButtonBackground}" />
230+
<Setter Target="ButtonIcon.Foreground" Value="{ThemeResource CaptionButtonForegroundUnfocused}" />
231+
</VisualState.Setters>
232+
</VisualState>
233+
201234
<VisualState x:Name="PointerOver">
202235
<VisualState.Setters>
203236
<Setter Target="ButtonBaseElement.Background" Value="{ThemeResource CaptionButtonBackgroundPointerOver}" />

src/cascadia/TerminalApp/TitlebarControl.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,16 @@ namespace winrt::TerminalApp::implementation
5353
return static_cast<float>(minMaxCloseWidth) / 3.0f;
5454
}
5555

56+
bool TitlebarControl::Focused()
57+
{
58+
return MinMaxCloseControl().Focused();
59+
}
60+
61+
void TitlebarControl::Focused(bool focused)
62+
{
63+
MinMaxCloseControl().Focused(focused);
64+
}
65+
5666
IInspectable TitlebarControl::Content()
5767
{
5868
return ContentRoot().Content();

src/cascadia/TerminalApp/TitlebarControl.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ namespace winrt::TerminalApp::implementation
1717
void ReleaseButtons();
1818
float CaptionButtonWidth();
1919

20+
bool Focused();
21+
void Focused(bool focused);
22+
2023
IInspectable Content();
2124
void Content(IInspectable content);
2225

src/cascadia/TerminalApp/TitlebarControl.idl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ namespace TerminalApp
2929
void ClickButton(CaptionButton button);
3030
void ReleaseButtons();
3131
Single CaptionButtonWidth { get; };
32+
Boolean Focused { get; set; };
3233

3334
IInspectable Content;
3435
Windows.UI.Xaml.Controls.Border DragBar { get; };

src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -958,6 +958,12 @@ void NonClientIslandWindow::_UpdateFrameMargins() const noexcept
958958
{
959959
switch (message)
960960
{
961+
case WM_NCACTIVATE:
962+
{
963+
const bool activated = LOWORD(wParam) != 0;
964+
_titlebar.Focused(activated);
965+
break;
966+
}
961967
case WM_SETCURSOR:
962968
return _OnSetCursor(wParam, lParam);
963969
case WM_DISPLAYCHANGE:

0 commit comments

Comments
 (0)