Skip to content

Commit

Permalink
Improve WPF dark titlebar handling (#1071)
Browse files Browse the repository at this point in the history
* Avoid spawning an invisible window by setting dark titlebar during SourceInitialized

* Force titlebar repaint when selecting theme or on Windows app theme change
  • Loading branch information
ScrubN authored May 23, 2024
1 parent 6a12088 commit a26fccd
Show file tree
Hide file tree
Showing 17 changed files with 45 additions and 36 deletions.
2 changes: 1 addition & 1 deletion TwitchDownloaderWPF/App.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
<SolidColorBrush x:Key="StatusBarText" Color="#212121" />
<SolidColorBrush x:Key="ProgressBarForeground" Color="#326CF3" />

<Style TargetType="{x:Type Window}">
<Style TargetType="{x:Type local:MainWindow}">
<Setter Property="behave:WindowIntegrityCheckBehavior.IntegrityCheck" Value="True"></Setter>
</Style>
</ResourceDictionary>
Expand Down
4 changes: 2 additions & 2 deletions TwitchDownloaderWPF/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ private static void CurrentDomain_UnhandledException(object sender, UnhandledExc
Current?.Shutdown();
}

public static void RequestAppThemeChange()
=> ThemeServiceSingleton.ChangeAppTheme();
public static void RequestAppThemeChange(bool forceRepaint = false)
=> ThemeServiceSingleton.ChangeAppTheme(forceRepaint);

public static void RequestTitleBarChange()
=> ThemeServiceSingleton.SetTitleBarTheme(Current.Windows);
Expand Down
2 changes: 1 addition & 1 deletion TwitchDownloaderWPF/MainWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
lex:ResxLocalizationProvider.DefaultAssembly="TwitchDownloaderWPF"
lex:ResxLocalizationProvider.DefaultDictionary="Strings"
mc:Ignorable="d"
Title="Twitch Downloader" MinHeight="440" Height="500" MinWidth="700" Width="850" Loaded="Window_Loaded">
Title="Twitch Downloader" MinHeight="440" Height="500" MinWidth="700" Width="850" Loaded="Window_Loaded" SourceInitialized="Window_OnSourceInitialized">
<Grid Background="{DynamicResource AppBackground}">
<Grid.RowDefinitions>
<RowDefinition Height="2" />
Expand Down
5 changes: 4 additions & 1 deletion TwitchDownloaderWPF/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,13 @@ private void btnQueue_Click(object sender, RoutedEventArgs e)
Main.Content = pageQueue;
}

private async void Window_Loaded(object sender, RoutedEventArgs e)
private void Window_OnSourceInitialized(object sender, EventArgs e)
{
App.RequestAppThemeChange();
}

private async void Window_Loaded(object sender, RoutedEventArgs e)
{
Main.Content = pageVodDownload;
if (Settings.Default.UpgradeRequired)
{
Expand Down
31 changes: 16 additions & 15 deletions TwitchDownloaderWPF/Services/ThemeService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,11 @@ private void WindowsThemeChanged(object sender, string newWindowsTheme)

if (Settings.Default.GuiTheme.Equals("System", StringComparison.OrdinalIgnoreCase))
{
ChangeAppTheme();
ChangeAppTheme(true);
}
}

public void ChangeAppTheme()
public void ChangeAppTheme(bool forceRepaint = false)
{
var newTheme = Settings.Default.GuiTheme;
if (newTheme.Equals("System", StringComparison.OrdinalIgnoreCase))
Expand All @@ -87,6 +87,20 @@ public void ChangeAppTheme()
{
SetTitleBarTheme(_wpfApplication.Windows);
}

if (forceRepaint)
{
// Cause an NC repaint by changing focus
var wnd = new Window
{
SizeToContent = SizeToContent.WidthAndHeight,
Top = int.MinValue + 1,
WindowStyle = WindowStyle.None,
ShowInTaskbar = false
};
wnd.Show();
wnd.Close();
}
}

[SupportedOSPlatform("windows")]
Expand All @@ -111,19 +125,6 @@ public void SetTitleBarTheme(WindowCollection windows)
_ = NativeFunctions.SetWindowAttribute(windowHandle, darkTitleBarAttribute, &shouldUseDarkTitleBar, sizeof(int));
}
}

Window wnd = new()
{
SizeToContent = SizeToContent.WidthAndHeight,
Top = int.MinValue + 1,
WindowStyle = WindowStyle.None,
ShowInTaskbar = false
};
wnd.Show();
wnd.Close();
// Dark title bar is a bit buggy, requires window redraw (focus change, resize, transparency change) to fully apply.
// We *could* send a repaint message to win32.dll, but this solution works and is way easier.
// Win11 might not have this issue but Win10 does so please leave this
}

private void ChangeThemePath(string newTheme)
Expand Down
2 changes: 1 addition & 1 deletion TwitchDownloaderWPF/WindowMassDownload.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
xmlns:emoji="clr-namespace:Emoji.Wpf;assembly=Emoji.Wpf"
xmlns:gif="http://wpfanimatedgif.codeplex.com"
mc:Ignorable="d"
Title="Mass Downloader" MinHeight="250" Height="700" MinWidth="775" Width="1100" Loaded="Window_Loaded">
Title="Mass Downloader" MinHeight="250" Height="700" MinWidth="775" Width="1100" Loaded="Window_Loaded" SourceInitialized="Window_OnSourceInitialized">
<Window.Resources>
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
<Setter Property="behave:TextBoxTripleClickBehavior.TripleClickSelectLine" Value="True" />
Expand Down
6 changes: 5 additions & 1 deletion TwitchDownloaderWPF/WindowMassDownload.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -254,12 +254,16 @@ private void btnSelectAll_Click(object sender, RoutedEventArgs e)
textCount.Text = selectedItems.Count.ToString();
}

private void Window_OnSourceInitialized(object sender, EventArgs e)
{
App.RequestTitleBarChange();
}

private void Window_Loaded(object sender, RoutedEventArgs e)
{
Title = downloaderType == DownloadType.Video
? Translations.Strings.TitleVideoMassDownloader
: Translations.Strings.TitleClipMassDownloader;
App.RequestTitleBarChange();
}

private async void TextChannel_OnKeyDown(object sender, KeyEventArgs e)
Expand Down
2 changes: 1 addition & 1 deletion TwitchDownloaderWPF/WindowOldVideoCacheManager.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
lex:ResxLocalizationProvider.DefaultAssembly="TwitchDownloaderWPF"
lex:ResxLocalizationProvider.DefaultDictionary="Strings"
mc:Ignorable="d"
Title="{lex:Loc TitleWindowOldVideoCacheManager}" MinHeight="350" MinWidth="500" Height="450" Width="800" Loaded="OnLoaded" Closing="OnClosing" d:DataContext="{d:DesignInstance local:WindowOldVideoCacheManager}">
Title="{lex:Loc TitleWindowOldVideoCacheManager}" MinHeight="350" MinWidth="500" Height="450" Width="800" Loaded="OnLoaded" SourceInitialized="OnSourceInitialized" Closing="OnClosing" d:DataContext="{d:DesignInstance local:WindowOldVideoCacheManager}">
<Window.Resources>
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
<Setter Property="behave:TextBoxTripleClickBehavior.TripleClickSelectLine" Value="True" />
Expand Down
9 changes: 5 additions & 4 deletions TwitchDownloaderWPF/WindowOldVideoCacheManager.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,17 @@ public WindowOldVideoCacheManager(IEnumerable<DirectoryInfo> directories)
InitializeComponent();
}

private void OnLoaded(object sender, RoutedEventArgs e)
private void OnSourceInitialized(object sender, EventArgs e)
{
App.RequestTitleBarChange();
}

// For some stupid reason, this does not work unless I manually set it, even though its a binding
DataGrid.ItemsSource = GridItems;

private void OnLoaded(object sender, RoutedEventArgs e)
{
// Do this the dumb way because bindings are annoying without view models
var sizeString = VideoSizeEstimator.StringifyByteCount(_totalSize);
TextTotalSize.Text = string.IsNullOrEmpty(sizeString) ? "0B" : sizeString;
DataGrid.ItemsSource = GridItems;
}

private void OnClosing(object sender, CancelEventArgs e)
Expand Down
2 changes: 1 addition & 1 deletion TwitchDownloaderWPF/WindowQueueOptions.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
lex:ResxLocalizationProvider.DefaultAssembly="TwitchDownloaderWPF"
lex:ResxLocalizationProvider.DefaultDictionary="Strings"
mc:Ignorable="d"
Title="{lex:Loc TitleEnqueueOptions}" MinHeight="280" Height="280" MinWidth="500" Width="500" SizeToContent="WidthAndHeight" Loaded="Window_loaded" Background="{DynamicResource AppBackground}">
Title="{lex:Loc TitleEnqueueOptions}" MinHeight="280" Height="280" MinWidth="500" Width="500" SizeToContent="WidthAndHeight" SourceInitialized="Window_OnSourceInitialized" Background="{DynamicResource AppBackground}">
<Window.Resources>
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
<Setter Property="behave:TextBoxTripleClickBehavior.TripleClickSelectLine" Value="True" />
Expand Down
2 changes: 1 addition & 1 deletion TwitchDownloaderWPF/WindowQueueOptions.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -682,7 +682,7 @@ private void radioHTML_Checked(object sender, RoutedEventArgs e)
}
}

private void Window_loaded(object sender, RoutedEventArgs e)
private void Window_OnSourceInitialized(object sender, EventArgs e)
{
App.RequestTitleBarChange();
}
Expand Down
2 changes: 1 addition & 1 deletion TwitchDownloaderWPF/WindowRangeSelect.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
lex:ResxLocalizationProvider.DefaultAssembly="TwitchDownloaderWPF"
lex:ResxLocalizationProvider.DefaultDictionary="Strings"
mc:Ignorable="d"
Title="{lex:Loc TitleRenderRange}" Height="150" Width="400" Background="#FFEFEFEF" Initialized="Window_Initialized" Loaded="Window_Loaded">
Title="{lex:Loc TitleRenderRange}" Height="150" Width="400" Background="#FFEFEFEF" Initialized="Window_Initialized" SourceInitialized="Window_OnSourceInitialized">
<Window.Resources>
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
<Setter Property="behave:TextBoxTripleClickBehavior.TripleClickSelectLine" Value="True" />
Expand Down
2 changes: 1 addition & 1 deletion TwitchDownloaderWPF/WindowRangeSelect.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ private void numEnd_TextChanged(object sender, TextChangedEventArgs e)
catch (OverflowException) { }
}

private void Window_Loaded(object sender, RoutedEventArgs e)
private void Window_OnSourceInitialized(object sender, EventArgs e)
{
App.RequestTitleBarChange();
}
Expand Down
2 changes: 1 addition & 1 deletion TwitchDownloaderWPF/WindowSettings.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
xmlns:hc="https://handyorg.github.io/handycontrol"
xmlns:fa="http://schemas.fontawesome.com/icons/"
mc:Ignorable="d"
Title="{lex:Loc TitleGlobalSettings}" MinWidth="400" MinHeight="500" Width="500" Height="592" SizeToContent="Height" Initialized="Window_Initialized" Closing="Window_Closing" Loaded="Window_Loaded" Background="{DynamicResource AppBackground}">
Title="{lex:Loc TitleGlobalSettings}" MinWidth="400" MinHeight="500" Width="500" Height="592" SizeToContent="Height" Initialized="Window_Initialized" Closing="Window_Closing" SourceInitialized="Window_OnSourceInitialized" Background="{DynamicResource AppBackground}">
<Window.Resources>
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
<Setter Property="behave:TextBoxTripleClickBehavior.TripleClickSelectLine" Value="True" />
Expand Down
4 changes: 2 additions & 2 deletions TwitchDownloaderWPF/WindowSettings.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ private void BtnClearCache_Click(object sender, RoutedEventArgs e)
}
}

private void Window_Loaded(object sender, RoutedEventArgs e)
private void Window_OnSourceInitialized(object sender, EventArgs e)
{
App.RequestTitleBarChange();
}
Expand Down Expand Up @@ -162,7 +162,7 @@ private void ComboTheme_OnSelectionChanged(object sender, SelectionChangedEventA
{
_refreshThemeOnCancel = true;
Settings.Default.GuiTheme = (string)ComboTheme.SelectedItem;
App.RequestAppThemeChange();
App.RequestAppThemeChange(true);
}
}

Expand Down
2 changes: 1 addition & 1 deletion TwitchDownloaderWPF/WindowUrlList.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
lex:ResxLocalizationProvider.DefaultAssembly="TwitchDownloaderWPF"
lex:ResxLocalizationProvider.DefaultDictionary="Strings"
mc:Ignorable="d"
Title="{lex:Loc TitleUrlList}" MinHeight="590" Height="600" MinWidth="485" Width="500" Loaded="Window_Loaded">
Title="{lex:Loc TitleUrlList}" MinHeight="590" Height="600" MinWidth="485" Width="500" SourceInitialized="Window_OnSourceInitialized">
<Window.Resources>
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
<Setter Property="behave:TextBoxTripleClickBehavior.TripleClickSelectLine" Value="True" />
Expand Down
2 changes: 1 addition & 1 deletion TwitchDownloaderWPF/WindowUrlList.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ private async void btnQueue_Click(object sender, RoutedEventArgs e)
btnQueue.IsEnabled = true;
}

private void Window_Loaded(object sender, RoutedEventArgs e)
private void Window_OnSourceInitialized(object sender, EventArgs e)
{
App.RequestTitleBarChange();
}
Expand Down

0 comments on commit a26fccd

Please sign in to comment.