From 275a4167683e176ee1a92506b961d6be5021120f Mon Sep 17 00:00:00 2001 From: David Brett Date: Sun, 31 May 2026 14:16:57 +0200 Subject: [PATCH 01/32] Move custom title bar UI from PluginSettingsWindow to new CustomWindowTitleBar --- Flow.Launcher/PluginSettingsWindow.xaml | 123 +---------------- Flow.Launcher/PluginSettingsWindow.xaml.cs | 14 +- .../Controls/CustomWindowTitleBar.xaml | 125 ++++++++++++++++++ .../Controls/CustomWindowTitleBar.xaml.cs | 102 ++++++++++++++ 4 files changed, 244 insertions(+), 120 deletions(-) create mode 100644 Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml create mode 100644 Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml.cs diff --git a/Flow.Launcher/PluginSettingsWindow.xaml b/Flow.Launcher/PluginSettingsWindow.xaml index ac1abd9e2c8..fe8e569e1f0 100644 --- a/Flow.Launcher/PluginSettingsWindow.xaml +++ b/Flow.Launcher/PluginSettingsWindow.xaml @@ -2,6 +2,7 @@ x:Class="Flow.Launcher.PluginSettingsWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:controls="clr-namespace:Flow.Launcher.Resources.Controls" xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern" Width="800" Height="Auto" @@ -50,131 +51,21 @@ - - - - - - - - - - - - - - + CloseButtonClick="OnCloseButtonClick" + IconSource="/Images/app.png" + MaximizeRestoreButtonClick="OnMaximizeRestoreButtonClick" + MinimizeButtonClick="OnMinimizeButtonClick" /> diff --git a/Flow.Launcher/PluginSettingsWindow.xaml.cs b/Flow.Launcher/PluginSettingsWindow.xaml.cs index 3dfad752da0..4b3f6150ba5 100644 --- a/Flow.Launcher/PluginSettingsWindow.xaml.cs +++ b/Flow.Launcher/PluginSettingsWindow.xaml.cs @@ -4,6 +4,7 @@ using CommunityToolkit.Mvvm.DependencyInjection; using Flow.Launcher.Core.Plugin; using Flow.Launcher.Infrastructure.UserSettings; +using Flow.Launcher.Resources.Controls; using Flow.Launcher.ViewModel; using iNKORE.UI.WPF.Modern.Controls; @@ -115,15 +116,20 @@ private void Window_Activated(object sender, EventArgs e) private void RefreshMaximizeRestoreButton() { + if (FindName("CustomWindowTitleBar") is not CustomWindowTitleBar titleBar) + { + return; + } + if (WindowState == WindowState.Maximized) { - MaximizeButton.Visibility = Visibility.Hidden; - RestoreButton.Visibility = Visibility.Visible; + titleBar.MaximizeButtonVisibility = Visibility.Hidden; + titleBar.RestoreButtonVisibility = Visibility.Visible; } else { - MaximizeButton.Visibility = Visibility.Visible; - RestoreButton.Visibility = Visibility.Hidden; + titleBar.MaximizeButtonVisibility = Visibility.Visible; + titleBar.RestoreButtonVisibility = Visibility.Hidden; } } diff --git a/Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml b/Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml new file mode 100644 index 00000000000..b1f79ab4b7f --- /dev/null +++ b/Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + diff --git a/Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml.cs b/Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml.cs new file mode 100644 index 00000000000..16475cbe318 --- /dev/null +++ b/Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml.cs @@ -0,0 +1,102 @@ +using System.Windows; +using System.Windows.Controls; + +namespace Flow.Launcher.Resources.Controls +{ + public partial class CustomWindowTitleBar : UserControl + { + public static readonly DependencyProperty IconSourceProperty = + DependencyProperty.Register( + name: nameof(IconSource), + propertyType: typeof(string), + ownerType: typeof(CustomWindowTitleBar), + typeMetadata: new PropertyMetadata(defaultValue: "/Images/app.png") + ); + + public static readonly DependencyProperty MinimizeButtonVisibilityProperty = + DependencyProperty.Register( + name: nameof(MinimizeButtonVisibility), + propertyType: typeof(Visibility), + ownerType: typeof(CustomWindowTitleBar), + typeMetadata: new PropertyMetadata(defaultValue: Visibility.Visible) + ); + + public static readonly DependencyProperty MaximizeButtonVisibilityProperty = + DependencyProperty.Register( + name: nameof(MaximizeButtonVisibility), + propertyType: typeof(Visibility), + ownerType: typeof(CustomWindowTitleBar), + typeMetadata: new PropertyMetadata(defaultValue: Visibility.Visible) + ); + + public static readonly DependencyProperty RestoreButtonVisibilityProperty = + DependencyProperty.Register( + name: nameof(RestoreButtonVisibility), + propertyType: typeof(Visibility), + ownerType: typeof(CustomWindowTitleBar), + typeMetadata: new PropertyMetadata(defaultValue: Visibility.Hidden) + ); + + public static readonly DependencyProperty CloseButtonVisibilityProperty = + DependencyProperty.Register( + name: nameof(CloseButtonVisibility), + propertyType: typeof(Visibility), + ownerType: typeof(CustomWindowTitleBar), + typeMetadata: new PropertyMetadata(defaultValue: Visibility.Visible) + ); + + public event RoutedEventHandler MinimizeButtonClick; + public event RoutedEventHandler MaximizeRestoreButtonClick; + public event RoutedEventHandler CloseButtonClick; + + public CustomWindowTitleBar() + { + InitializeComponent(); + } + + public string IconSource + { + get => (string)GetValue(IconSourceProperty); + set => SetValue(IconSourceProperty, value); + } + + public Visibility MinimizeButtonVisibility + { + get => (Visibility)GetValue(MinimizeButtonVisibilityProperty); + set => SetValue(MinimizeButtonVisibilityProperty, value); + } + + public Visibility MaximizeButtonVisibility + { + get => (Visibility)GetValue(MaximizeButtonVisibilityProperty); + set => SetValue(MaximizeButtonVisibilityProperty, value); + } + + public Visibility RestoreButtonVisibility + { + get => (Visibility)GetValue(RestoreButtonVisibilityProperty); + set => SetValue(RestoreButtonVisibilityProperty, value); + } + + public Visibility CloseButtonVisibility + { + get => (Visibility)GetValue(CloseButtonVisibilityProperty); + set => SetValue(CloseButtonVisibilityProperty, value); + } + + private void MinimizeButton_OnClick(object sender, RoutedEventArgs e) + { + MinimizeButtonClick?.Invoke(this, e); + } + + private void MaximizeRestoreButton_OnClick(object sender, RoutedEventArgs e) + { + MaximizeRestoreButtonClick?.Invoke(this, e); + } + + private void CloseButton_OnClick(object sender, RoutedEventArgs e) + { + CloseButtonClick?.Invoke(this, e); + } + } +} From 59ceab6a125da14ec9cdcdb1708755be847bc4a5 Mon Sep 17 00:00:00 2001 From: David Brett Date: Sun, 31 May 2026 15:29:06 +0200 Subject: [PATCH 02/32] Move title bar logic from PluginSettingsWindow to CustomWindowTitleBar --- Flow.Launcher/PluginSettingsWindow.xaml | 9 +- Flow.Launcher/PluginSettingsWindow.xaml.cs | 70 ---------- .../Controls/CustomWindowTitleBar.xaml.cs | 131 +++++++++++++++++- 3 files changed, 131 insertions(+), 79 deletions(-) diff --git a/Flow.Launcher/PluginSettingsWindow.xaml b/Flow.Launcher/PluginSettingsWindow.xaml index fe8e569e1f0..81a012d9e42 100644 --- a/Flow.Launcher/PluginSettingsWindow.xaml +++ b/Flow.Launcher/PluginSettingsWindow.xaml @@ -8,11 +8,8 @@ Height="Auto" MinWidth="600" MinHeight="300" - Loaded="OnLoaded" ResizeMode="CanResize" SnapsToDevicePixels="True" - StateChanged="Window_StateChanged" - Activated="Window_Activated" UseLayoutRounding="True" WindowStartupLocation="CenterScreen"> @@ -57,12 +54,8 @@ + IconSource="/Images/app.png" /> WindowState.Normal, - _ => WindowState.Maximized - }; - } - - private void OnCloseButtonClick(object sender, RoutedEventArgs e) - { - Close(); - } - private void OnCloseExecuted(object sender, ExecutedRoutedEventArgs e) { Close(); } - private void OnLoaded(object sender, RoutedEventArgs e) - { - if (WindowState != WindowState.Minimized) - { - _lastNonMinimizedWindowState = WindowState; - } - - RefreshMaximizeRestoreButton(); - } - - private void Window_StateChanged(object sender, EventArgs e) - { - if (WindowState != WindowState.Minimized) - { - _lastNonMinimizedWindowState = WindowState; - } - - RefreshMaximizeRestoreButton(); - } - - private void Window_Activated(object sender, EventArgs e) - { - // Band-aid fix: Rare edge case where Alt+Tab activates the window but doesn't trigger StateChanged - // So we need to restore/maximize it here if it's still minimized - if (WindowState == WindowState.Minimized) - { - WindowState = _lastNonMinimizedWindowState; - } - } - - private void RefreshMaximizeRestoreButton() - { - if (FindName("CustomWindowTitleBar") is not CustomWindowTitleBar titleBar) - { - return; - } - - if (WindowState == WindowState.Maximized) - { - titleBar.MaximizeButtonVisibility = Visibility.Hidden; - titleBar.RestoreButtonVisibility = Visibility.Visible; - } - else - { - titleBar.MaximizeButtonVisibility = Visibility.Visible; - titleBar.RestoreButtonVisibility = Visibility.Hidden; - } - } - protected override void OnClosed(EventArgs e) { if (!App.LoadingOrExiting) diff --git a/Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml.cs b/Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml.cs index 16475cbe318..25ec154d0f6 100644 --- a/Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml.cs +++ b/Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml.cs @@ -1,5 +1,6 @@ -using System.Windows; +using System; using System.Windows.Controls; +using System.Windows; namespace Flow.Launcher.Resources.Controls { @@ -49,9 +50,14 @@ public partial class CustomWindowTitleBar : UserControl public event RoutedEventHandler MaximizeRestoreButtonClick; public event RoutedEventHandler CloseButtonClick; + private Window _hostWindow; + private WindowState _lastNonMinimizedWindowState = WindowState.Normal; + public CustomWindowTitleBar() { InitializeComponent(); + Loaded += CustomWindowTitleBar_Loaded; + Unloaded += CustomWindowTitleBar_Unloaded; } public string IconSource @@ -84,19 +90,142 @@ public Visibility CloseButtonVisibility set => SetValue(CloseButtonVisibilityProperty, value); } + private void CustomWindowTitleBar_Loaded(object sender, RoutedEventArgs e) + { + AttachToHostWindow(); + RefreshMaximizeRestoreButton(); + } + + private void CustomWindowTitleBar_Unloaded(object sender, RoutedEventArgs e) + { + DetachFromHostWindow(); + } + + private void AttachToHostWindow() + { + var window = Window.GetWindow(this); + if (_hostWindow == window) + { + return; + } + + DetachFromHostWindow(); + + _hostWindow = window; + if (_hostWindow == null) + { + return; + } + + if (_hostWindow.WindowState != WindowState.Minimized) + { + _lastNonMinimizedWindowState = _hostWindow.WindowState; + } + + _hostWindow.StateChanged += HostWindow_StateChanged; + _hostWindow.Activated += HostWindow_Activated; + _hostWindow.Closed += HostWindow_Closed; + } + + private void DetachFromHostWindow() + { + if (_hostWindow == null) + { + return; + } + + _hostWindow.StateChanged -= HostWindow_StateChanged; + _hostWindow.Activated -= HostWindow_Activated; + _hostWindow.Closed -= HostWindow_Closed; + _hostWindow = null; + } + + private void HostWindow_StateChanged(object sender, EventArgs e) + { + if (_hostWindow == null) + { + return; + } + + if (_hostWindow.WindowState != WindowState.Minimized) + { + _lastNonMinimizedWindowState = _hostWindow.WindowState; + } + + RefreshMaximizeRestoreButton(); + } + + private void HostWindow_Activated(object sender, EventArgs e) + { + if (_hostWindow == null) + { + return; + } + + // Band-aid fix: Rare edge case where Alt+Tab activates the window but doesn't trigger StateChanged. + if (_hostWindow.WindowState == WindowState.Minimized) + { + _hostWindow.WindowState = _lastNonMinimizedWindowState; + } + } + + private void HostWindow_Closed(object sender, EventArgs e) + { + DetachFromHostWindow(); + } + + private void RefreshMaximizeRestoreButton() + { + if (_hostWindow?.WindowState == WindowState.Maximized) + { + MaximizeButtonVisibility = Visibility.Hidden; + RestoreButtonVisibility = Visibility.Visible; + } + else + { + MaximizeButtonVisibility = Visibility.Visible; + RestoreButtonVisibility = Visibility.Hidden; + } + } + private void MinimizeButton_OnClick(object sender, RoutedEventArgs e) { MinimizeButtonClick?.Invoke(this, e); + + if (_hostWindow == null) + { + return; + } + + _hostWindow.WindowState = WindowState.Minimized; } private void MaximizeRestoreButton_OnClick(object sender, RoutedEventArgs e) { MaximizeRestoreButtonClick?.Invoke(this, e); + + if (_hostWindow == null) + { + return; + } + + _hostWindow.WindowState = _hostWindow.WindowState switch + { + WindowState.Maximized => WindowState.Normal, + _ => WindowState.Maximized + }; } private void CloseButton_OnClick(object sender, RoutedEventArgs e) { CloseButtonClick?.Invoke(this, e); + + if (_hostWindow == null) + { + return; + } + + _hostWindow.Close(); } } } From d23be52eda5ab870c7cd60dcbed9307128544046 Mon Sep 17 00:00:00 2001 From: David Brett Date: Sun, 31 May 2026 16:32:53 +0200 Subject: [PATCH 03/32] Make click events handleable in CustomWindowTitleBar --- .../Controls/CustomWindowTitleBar.xaml.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml.cs b/Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml.cs index 25ec154d0f6..8be0ec1aeb4 100644 --- a/Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml.cs +++ b/Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml.cs @@ -192,6 +192,11 @@ private void MinimizeButton_OnClick(object sender, RoutedEventArgs e) { MinimizeButtonClick?.Invoke(this, e); + if (e.Handled) + { + return; + } + if (_hostWindow == null) { return; @@ -204,6 +209,11 @@ private void MaximizeRestoreButton_OnClick(object sender, RoutedEventArgs e) { MaximizeRestoreButtonClick?.Invoke(this, e); + if (e.Handled) + { + return; + } + if (_hostWindow == null) { return; @@ -220,6 +230,11 @@ private void CloseButton_OnClick(object sender, RoutedEventArgs e) { CloseButtonClick?.Invoke(this, e); + if (e.Handled) + { + return; + } + if (_hostWindow == null) { return; From 019d6942c10815911d33071860fc905636e0e802 Mon Sep 17 00:00:00 2001 From: David Brett Date: Sun, 31 May 2026 17:48:08 +0200 Subject: [PATCH 04/32] Make changes to LastNonMinimizedWindowState public and listenable in CustomWindowTitleBar --- .../Controls/CustomWindowTitleBar.xaml.cs | 36 +++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml.cs b/Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml.cs index 8be0ec1aeb4..2e11cbd331c 100644 --- a/Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml.cs +++ b/Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml.cs @@ -6,6 +6,19 @@ namespace Flow.Launcher.Resources.Controls { public partial class CustomWindowTitleBar : UserControl { + public sealed class WindowStateChangedEventArgs : EventArgs + { + public WindowStateChangedEventArgs(WindowState previousState, WindowState currentState) + { + PreviousState = previousState; + CurrentState = currentState; + } + + public WindowState PreviousState { get; } + + public WindowState CurrentState { get; } + } + public static readonly DependencyProperty IconSourceProperty = DependencyProperty.Register( name: nameof(IconSource), @@ -49,6 +62,7 @@ public partial class CustomWindowTitleBar : UserControl public event RoutedEventHandler MinimizeButtonClick; public event RoutedEventHandler MaximizeRestoreButtonClick; public event RoutedEventHandler CloseButtonClick; + public event EventHandler LastNonMinimizedWindowStateChanged; private Window _hostWindow; private WindowState _lastNonMinimizedWindowState = WindowState.Normal; @@ -90,6 +104,10 @@ public Visibility CloseButtonVisibility set => SetValue(CloseButtonVisibilityProperty, value); } + public WindowState LastNonMinimizedWindowState { + get => _lastNonMinimizedWindowState; + } + private void CustomWindowTitleBar_Loaded(object sender, RoutedEventArgs e) { AttachToHostWindow(); @@ -119,7 +137,7 @@ private void AttachToHostWindow() if (_hostWindow.WindowState != WindowState.Minimized) { - _lastNonMinimizedWindowState = _hostWindow.WindowState; + UpdateLastNonMinimizedWindowState(_hostWindow.WindowState); } _hostWindow.StateChanged += HostWindow_StateChanged; @@ -149,7 +167,7 @@ private void HostWindow_StateChanged(object sender, EventArgs e) if (_hostWindow.WindowState != WindowState.Minimized) { - _lastNonMinimizedWindowState = _hostWindow.WindowState; + UpdateLastNonMinimizedWindowState(_hostWindow.WindowState); } RefreshMaximizeRestoreButton(); @@ -174,6 +192,20 @@ private void HostWindow_Closed(object sender, EventArgs e) DetachFromHostWindow(); } + private void UpdateLastNonMinimizedWindowState(WindowState state) + { + if (state == WindowState.Minimized || _lastNonMinimizedWindowState == state) + { + return; + } + + var previousState = _lastNonMinimizedWindowState; + _lastNonMinimizedWindowState = state; + LastNonMinimizedWindowStateChanged?.Invoke(this, + new WindowStateChangedEventArgs(previousState, _lastNonMinimizedWindowState) + ); + } + private void RefreshMaximizeRestoreButton() { if (_hostWindow?.WindowState == WindowState.Maximized) From 82f8355673b8dd91e06296b3a7d15a5e9ed31194 Mon Sep 17 00:00:00 2001 From: David Brett Date: Sun, 31 May 2026 18:10:52 +0200 Subject: [PATCH 05/32] Make SettingWindow use CustomWindowTitleBar instead of duplicating its own version --- Flow.Launcher/SettingWindow.xaml | 123 +--------------------------- Flow.Launcher/SettingWindow.xaml.cs | 57 +------------ 2 files changed, 8 insertions(+), 172 deletions(-) diff --git a/Flow.Launcher/SettingWindow.xaml b/Flow.Launcher/SettingWindow.xaml index df0df101f4c..35219e0c795 100644 --- a/Flow.Launcher/SettingWindow.xaml +++ b/Flow.Launcher/SettingWindow.xaml @@ -4,6 +4,7 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:controls="clr-namespace:Flow.Launcher.Resources.Controls" xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern" xmlns:vm="clr-namespace:Flow.Launcher.ViewModel" Title="{DynamicResource flowlauncher_settings}" @@ -21,8 +22,6 @@ MouseDown="window_MouseDown" ResizeMode="CanResize" SnapsToDevicePixels="True" - StateChanged="Window_StateChanged" - Activated="Window_Activated" Top="{Binding SettingWindowTop, Mode=TwoWay}" UseLayoutRounding="True" WindowStartupLocation="Manual" @@ -41,132 +40,18 @@ - - - - - - - - - - - - - - - + LastNonMinimizedWindowStateChanged="OnLastNonMinimizedWindowStateChanged" /> WindowState.Normal, - _ => WindowState.Maximized - }; - } - - private void OnCloseButtonClick(object sender, RoutedEventArgs e) - { - Close(); - } - - private void RefreshMaximizeRestoreButton() - { - if (WindowState == WindowState.Maximized) - { - MaximizeButton.Visibility = Visibility.Hidden; - RestoreButton.Visibility = Visibility.Visible; - } - else - { - MaximizeButton.Visibility = Visibility.Visible; - RestoreButton.Visibility = Visibility.Hidden; - } - } - - #endregion - #region Window Position public void UpdatePositionAndState() From 540a5230b312d863a450d5e3043f79f68bc89f78 Mon Sep 17 00:00:00 2001 From: David Brett Date: Sun, 31 May 2026 18:20:47 +0200 Subject: [PATCH 06/32] Removed visibility dependency properties from CustomWindowTitleBar These are internal details that are no longer needed externally --- .../Controls/CustomWindowTitleBar.xaml | 11 ++-- .../Controls/CustomWindowTitleBar.xaml.cs | 64 ++----------------- 2 files changed, 8 insertions(+), 67 deletions(-) diff --git a/Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml b/Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml index b1f79ab4b7f..ecbd52d0b24 100644 --- a/Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml +++ b/Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml @@ -34,8 +34,7 @@ Grid.Column="2" Click="MinimizeButton_OnClick" RenderOptions.EdgeMode="Aliased" - Style="{DynamicResource TitleBarButtonStyle}" - Visibility="{Binding MinimizeButtonVisibility, RelativeSource={RelativeSource AncestorType={x:Type local:CustomWindowTitleBar}}}"> + Style="{DynamicResource TitleBarButtonStyle}"> + Style="{StaticResource TitleBarButtonStyle}"> + Visibility="Hidden"> + Style="{StaticResource TitleBarCloseButtonStyle}"> SetValue(IconSourceProperty, value); } - public Visibility MinimizeButtonVisibility - { - get => (Visibility)GetValue(MinimizeButtonVisibilityProperty); - set => SetValue(MinimizeButtonVisibilityProperty, value); - } - - public Visibility MaximizeButtonVisibility - { - get => (Visibility)GetValue(MaximizeButtonVisibilityProperty); - set => SetValue(MaximizeButtonVisibilityProperty, value); - } - - public Visibility RestoreButtonVisibility - { - get => (Visibility)GetValue(RestoreButtonVisibilityProperty); - set => SetValue(RestoreButtonVisibilityProperty, value); - } - - public Visibility CloseButtonVisibility - { - get => (Visibility)GetValue(CloseButtonVisibilityProperty); - set => SetValue(CloseButtonVisibilityProperty, value); - } - public WindowState LastNonMinimizedWindowState { get => _lastNonMinimizedWindowState; } @@ -210,13 +154,13 @@ private void RefreshMaximizeRestoreButton() { if (_hostWindow?.WindowState == WindowState.Maximized) { - MaximizeButtonVisibility = Visibility.Hidden; - RestoreButtonVisibility = Visibility.Visible; + MaximizeButton.Visibility = Visibility.Hidden; + RestoreButton.Visibility = Visibility.Visible; } else { - MaximizeButtonVisibility = Visibility.Visible; - RestoreButtonVisibility = Visibility.Hidden; + MaximizeButton.Visibility = Visibility.Visible; + RestoreButton.Visibility = Visibility.Hidden; } } From 4053a4e85562b6d30ce455feac79823b4232d36c Mon Sep 17 00:00:00 2001 From: David Brett Date: Sun, 31 May 2026 18:53:49 +0200 Subject: [PATCH 07/32] Allow hiding of buttons in CustomWindowTitleBar --- .../Controls/CustomWindowTitleBar.xaml | 2 + .../Controls/CustomWindowTitleBar.xaml.cs | 110 ++++++++++++++++-- 2 files changed, 105 insertions(+), 7 deletions(-) diff --git a/Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml b/Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml index ecbd52d0b24..b12737fb0dd 100644 --- a/Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml +++ b/Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml @@ -31,6 +31,7 @@ Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=Title}" /> - - + + Date: Sun, 31 May 2026 19:00:44 +0200 Subject: [PATCH 12/32] Make SelectFileManagerWindow use CustomWindowTitleBar instead of duplicating its own version --- Flow.Launcher/SelectFileManagerWindow.xaml | 37 +++++----------------- 1 file changed, 8 insertions(+), 29 deletions(-) diff --git a/Flow.Launcher/SelectFileManagerWindow.xaml b/Flow.Launcher/SelectFileManagerWindow.xaml index b81b1b0f4a6..08d9ccddc9e 100644 --- a/Flow.Launcher/SelectFileManagerWindow.xaml +++ b/Flow.Launcher/SelectFileManagerWindow.xaml @@ -3,6 +3,7 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:controls="clr-namespace:Flow.Launcher.Resources.Controls" xmlns:local="clr-namespace:Flow.Launcher" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern" @@ -26,35 +27,13 @@ - - - - - - - - - + + Date: Sun, 31 May 2026 20:12:48 +0200 Subject: [PATCH 13/32] Make ReleaseNotesWindow use CustomWindowTitleBar instead of duplicating its own version --- Flow.Launcher/ReleaseNotesWindow.xaml | 110 +---------------------- Flow.Launcher/ReleaseNotesWindow.xaml.cs | 43 --------- 2 files changed, 2 insertions(+), 151 deletions(-) diff --git a/Flow.Launcher/ReleaseNotesWindow.xaml b/Flow.Launcher/ReleaseNotesWindow.xaml index 6072f40f13c..24240aa40d8 100644 --- a/Flow.Launcher/ReleaseNotesWindow.xaml +++ b/Flow.Launcher/ReleaseNotesWindow.xaml @@ -20,7 +20,6 @@ Foreground="{DynamicResource PopupTextColor}" Loaded="Window_Loaded" ResizeMode="CanResize" - StateChanged="Window_StateChanged" WindowStartupLocation="CenterScreen" mc:Ignorable="d"> @@ -48,115 +47,10 @@ - - - - - - - - + Grid.ColumnSpan="5" /> WindowState.Normal, - _ => WindowState.Maximized - }; - } - - private void OnCloseButtonClick(object sender, RoutedEventArgs e) - { - Close(); - } - - private void RefreshMaximizeRestoreButton() - { - if (WindowState == WindowState.Maximized) - { - MaximizeButton.Visibility = Visibility.Hidden; - RestoreButton.Visibility = Visibility.Visible; - } - else - { - MaximizeButton.Visibility = Visibility.Visible; - RestoreButton.Visibility = Visibility.Hidden; - } - } - - private void Window_StateChanged(object sender, EventArgs e) - { - RefreshMaximizeRestoreButton(); - } - - #endregion - #region Control Events private void MarkdownViewer_Loaded(object sender, RoutedEventArgs e) From 89803fafb71e03b5d44fec74073cad79ca618e4e Mon Sep 17 00:00:00 2001 From: David Brett Date: Sun, 31 May 2026 20:53:08 +0200 Subject: [PATCH 14/32] Make WelcomeWindow use CustomWindowTitleBar instead of duplicating its own version --- Flow.Launcher/WelcomeWindow.xaml | 53 +++++--------------------------- 1 file changed, 7 insertions(+), 46 deletions(-) diff --git a/Flow.Launcher/WelcomeWindow.xaml b/Flow.Launcher/WelcomeWindow.xaml index a37e38eb833..a00f2dd56e5 100644 --- a/Flow.Launcher/WelcomeWindow.xaml +++ b/Flow.Launcher/WelcomeWindow.xaml @@ -2,6 +2,7 @@ x:Class="Flow.Launcher.WelcomeWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:controls="clr-namespace:Flow.Launcher.Resources.Controls" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:Flow.Launcher" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" @@ -23,7 +24,6 @@ MouseDown="window_MouseDown" WindowStartupLocation="CenterScreen" mc:Ignorable="d"> - @@ -33,51 +33,12 @@ - - - - - - - - - - - - - + + + Date: Mon, 1 Jun 2026 11:52:09 +0200 Subject: [PATCH 15/32] Simplify layout in ReleaseNotesWindow Now that CustomWindowTitleBar is its own control we don't need the complicated grid columns --- Flow.Launcher/ReleaseNotesWindow.xaml | 30 ++++++--------------------- 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/Flow.Launcher/ReleaseNotesWindow.xaml b/Flow.Launcher/ReleaseNotesWindow.xaml index 24240aa40d8..57492f4a6fd 100644 --- a/Flow.Launcher/ReleaseNotesWindow.xaml +++ b/Flow.Launcher/ReleaseNotesWindow.xaml @@ -35,40 +35,24 @@ - - - - - - - - + - - - + Margin="6 0 18 0" + x:Name="SeeMore" + Content="{DynamicResource seeMoreReleaseNotes}" + NavigateUri="{Binding ReleaseNotes}" /> Date: Mon, 1 Jun 2026 14:30:33 +0200 Subject: [PATCH 16/32] Make ReportWindow use CustomWindowTitleBar instead of duplicating its own version --- Flow.Launcher/ReportWindow.xaml | 51 ++++++------------------------ Flow.Launcher/ReportWindow.xaml.cs | 4 --- 2 files changed, 9 insertions(+), 46 deletions(-) diff --git a/Flow.Launcher/ReportWindow.xaml b/Flow.Launcher/ReportWindow.xaml index 5e799e2a339..075097fb169 100644 --- a/Flow.Launcher/ReportWindow.xaml +++ b/Flow.Launcher/ReportWindow.xaml @@ -2,6 +2,7 @@ x:Class="Flow.Launcher.ReportWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:controls="clr-namespace:Flow.Launcher.Resources.Controls" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" Title="{DynamicResource reportWindow_flowlauncher_got_an_error}" @@ -26,48 +27,14 @@ - - - - - - - - - - + + + Date: Mon, 1 Jun 2026 14:50:50 +0200 Subject: [PATCH 17/32] Make MessageBoxEx use CustomWindowTitleBar instead of duplicating its own version --- Flow.Launcher/MessageBoxEx.xaml | 42 ++++++++---------------------- Flow.Launcher/MessageBoxEx.xaml.cs | 2 ++ 2 files changed, 13 insertions(+), 31 deletions(-) diff --git a/Flow.Launcher/MessageBoxEx.xaml b/Flow.Launcher/MessageBoxEx.xaml index e58c2f1c71b..c7e39b97188 100644 --- a/Flow.Launcher/MessageBoxEx.xaml +++ b/Flow.Launcher/MessageBoxEx.xaml @@ -2,6 +2,7 @@ x:Class="Flow.Launcher.MessageBoxEx" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:controls="clr-namespace:Flow.Launcher.Resources.Controls" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:Flow.Launcher" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" @@ -30,37 +31,16 @@ - - - - - - - - - - - + + + diff --git a/Flow.Launcher/MessageBoxEx.xaml.cs b/Flow.Launcher/MessageBoxEx.xaml.cs index 907bfb926d5..c50c732396e 100644 --- a/Flow.Launcher/MessageBoxEx.xaml.cs +++ b/Flow.Launcher/MessageBoxEx.xaml.cs @@ -189,6 +189,8 @@ private void Button_Click(object sender, RoutedEventArgs e) private void Button_Cancel(object sender, RoutedEventArgs e) { + e.Handled = true; + if (_button == MessageBoxButton.YesNo) // Follow System.Windows.MessageBox behavior return; From 5a85353ed9cc635ad26204b7351c40972348091c Mon Sep 17 00:00:00 2001 From: David Brett Date: Mon, 1 Jun 2026 15:16:02 +0200 Subject: [PATCH 18/32] Use collapse instead of hidden when hiding buttons in CustomWindowTitleBar This removes the space reserved for the hidden button Otherwise if the restore button was hidden there would still be a gap between minimize and close buttons --- .../Resources/Controls/CustomWindowTitleBar.xaml | 2 +- .../Controls/CustomWindowTitleBar.xaml.cs | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml b/Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml index 0d866b0ecb4..32983381b72 100644 --- a/Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml +++ b/Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml @@ -82,7 +82,7 @@ Grid.Column="3" Click="MaximizeRestoreButton_OnClick" Style="{StaticResource TitleBarButtonStyle}" - Visibility="Hidden"> + Visibility="Collapsed"> Date: Mon, 1 Jun 2026 15:20:45 +0200 Subject: [PATCH 19/32] Make ProgressBoxEx use CustomWindowTitleBar instead of duplicating its own version --- Flow.Launcher/ProgressBoxEx.xaml | 65 +++++------------------------ Flow.Launcher/ProgressBoxEx.xaml.cs | 6 +-- 2 files changed, 12 insertions(+), 59 deletions(-) diff --git a/Flow.Launcher/ProgressBoxEx.xaml b/Flow.Launcher/ProgressBoxEx.xaml index e7d7a7b2a77..f6d7fd9ce70 100644 --- a/Flow.Launcher/ProgressBoxEx.xaml +++ b/Flow.Launcher/ProgressBoxEx.xaml @@ -2,6 +2,7 @@ x:Class="Flow.Launcher.ProgressBoxEx" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:controls="clr-namespace:Flow.Launcher.Resources.Controls" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:Flow.Launcher" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" @@ -30,60 +31,16 @@ - - - - - - - - - - - - - + + + diff --git a/Flow.Launcher/ProgressBoxEx.xaml.cs b/Flow.Launcher/ProgressBoxEx.xaml.cs index 11946334869..49693e0c475 100644 --- a/Flow.Launcher/ProgressBoxEx.xaml.cs +++ b/Flow.Launcher/ProgressBoxEx.xaml.cs @@ -98,14 +98,10 @@ private void KeyEsc_OnPress(object sender, ExecutedRoutedEventArgs e) private void Button_Cancel(object sender, RoutedEventArgs e) { + e.Handled = true; ForceClose(); } - private void Button_Minimize(object sender, RoutedEventArgs e) - { - WindowState = WindowState.Minimized; - } - private void Button_Background(object sender, RoutedEventArgs e) { Hide(); From aab925f7f09a62dbf7e4ec524039a068f4afa8e2 Mon Sep 17 00:00:00 2001 From: David Brett Date: Mon, 1 Jun 2026 15:45:31 +0200 Subject: [PATCH 20/32] Convert IconSource on CustomWindowTitleBar to an ImageSource and use the Icon set on the host window if no other value set --- .../Controls/CustomWindowTitleBar.xaml.cs | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml.cs b/Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml.cs index 96c50116a85..b44cb14d89f 100644 --- a/Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml.cs +++ b/Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml.cs @@ -1,11 +1,15 @@ using System; using System.Windows.Controls; using System.Windows; +using System.Windows.Media; +using System.Windows.Media.Imaging; namespace Flow.Launcher.Resources.Controls { public partial class CustomWindowTitleBar : UserControl { + private static readonly ImageSource DefaultWindowIcon = CreateDefaultWindowIcon(); + public sealed class WindowStateChangedEventArgs : EventArgs { public WindowStateChangedEventArgs(WindowState previousState, WindowState currentState) @@ -22,9 +26,9 @@ public WindowStateChangedEventArgs(WindowState previousState, WindowState curren public static readonly DependencyProperty IconSourceProperty = DependencyProperty.Register( name: nameof(IconSource), - propertyType: typeof(string), + propertyType: typeof(ImageSource), ownerType: typeof(CustomWindowTitleBar), - typeMetadata: new PropertyMetadata(defaultValue: "/Images/app.png") + typeMetadata: new PropertyMetadata(defaultValue: null) ); public static readonly DependencyProperty TitleProperty = @@ -97,9 +101,9 @@ public CustomWindowTitleBar() Unloaded += CustomWindowTitleBar_Unloaded; } - public string IconSource + public ImageSource IconSource { - get => (string)GetValue(IconSourceProperty); + get => (ImageSource)GetValue(IconSourceProperty); set => SetValue(IconSourceProperty, value); } @@ -178,6 +182,11 @@ private void AttachToHostWindow() return; } + if (IconSource is null) + { + IconSource = _hostWindow.Icon ?? DefaultWindowIcon; + } + if (Title is null && !string.IsNullOrEmpty(_hostWindow.Title)) { Title = _hostWindow.Title; @@ -375,5 +384,15 @@ private void CloseButton_OnClick(object sender, RoutedEventArgs e) _hostWindow.Close(); } + + private static ImageSource CreateDefaultWindowIcon() + { + var icon = new BitmapImage(); + icon.BeginInit(); + icon.UriSource = new Uri("/Images/app.png", UriKind.Relative); + icon.EndInit(); + icon.Freeze(); + return icon; + } } } From ed988426515e6f935e030ffff5881e4f128fda26 Mon Sep 17 00:00:00 2001 From: David Brett Date: Tue, 2 Jun 2026 12:15:47 +0200 Subject: [PATCH 21/32] Remove unnecessary specification of titlebar IconSource from report window Since this now defaults to the Icon set on the window, it is better not to duplciate that --- Flow.Launcher/ReportWindow.xaml | 1 - 1 file changed, 1 deletion(-) diff --git a/Flow.Launcher/ReportWindow.xaml b/Flow.Launcher/ReportWindow.xaml index 075097fb169..0a4e4276470 100644 --- a/Flow.Launcher/ReportWindow.xaml +++ b/Flow.Launcher/ReportWindow.xaml @@ -30,7 +30,6 @@ From 98364299c85bcbeb74c6a6b5b73c7c06b82b4892 Mon Sep 17 00:00:00 2001 From: David Brett Date: Mon, 1 Jun 2026 15:48:54 +0200 Subject: [PATCH 22/32] Make PluginUpdateWindow use CustomWindowTitleBar instead of duplicating its own version --- Flow.Launcher/PluginUpdateWindow.xaml | 39 ++++++------------------ Flow.Launcher/PluginUpdateWindow.xaml.cs | 1 + 2 files changed, 11 insertions(+), 29 deletions(-) diff --git a/Flow.Launcher/PluginUpdateWindow.xaml b/Flow.Launcher/PluginUpdateWindow.xaml index a4bb0643169..edd23a95298 100644 --- a/Flow.Launcher/PluginUpdateWindow.xaml +++ b/Flow.Launcher/PluginUpdateWindow.xaml @@ -2,6 +2,7 @@ x:Class="Flow.Launcher.PluginUpdateWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:controls="clr-namespace:Flow.Launcher.Resources.Controls" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:flowlauncher="clr-namespace:Flow.Launcher" xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern" @@ -30,35 +31,15 @@ - - - - - - - - - + + + Date: Mon, 1 Jun 2026 15:54:07 +0200 Subject: [PATCH 23/32] Make CustomShortcutSetting use CustomWindowTitleBar instead of duplicating its own version --- Flow.Launcher/CustomShortcutSetting.xaml | 39 ++++++--------------- Flow.Launcher/CustomShortcutSetting.xaml.cs | 1 + 2 files changed, 11 insertions(+), 29 deletions(-) diff --git a/Flow.Launcher/CustomShortcutSetting.xaml b/Flow.Launcher/CustomShortcutSetting.xaml index 5185354e772..3ed7a06894f 100644 --- a/Flow.Launcher/CustomShortcutSetting.xaml +++ b/Flow.Launcher/CustomShortcutSetting.xaml @@ -2,6 +2,7 @@ x:Class="Flow.Launcher.CustomShortcutSetting" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:controls="clr-namespace:Flow.Launcher.Resources.Controls" xmlns:flowlauncher="clr-namespace:Flow.Launcher" Title="{DynamicResource customeQueryShortcutTitle}" Width="530" @@ -27,35 +28,15 @@ - - - - - - - - - + + + Date: Mon, 1 Jun 2026 16:02:02 +0200 Subject: [PATCH 24/32] Make CustomQueryHotkeySetting use CustomWindowTitleBar instead of duplicating its own version --- Flow.Launcher/CustomQueryHotkeySetting.xaml | 37 ++++--------------- .../CustomQueryHotkeySetting.xaml.cs | 1 + 2 files changed, 9 insertions(+), 29 deletions(-) diff --git a/Flow.Launcher/CustomQueryHotkeySetting.xaml b/Flow.Launcher/CustomQueryHotkeySetting.xaml index db99b704a52..b70bd41248f 100644 --- a/Flow.Launcher/CustomQueryHotkeySetting.xaml +++ b/Flow.Launcher/CustomQueryHotkeySetting.xaml @@ -2,6 +2,7 @@ x:Class="Flow.Launcher.CustomQueryHotkeySetting" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:controls="clr-namespace:Flow.Launcher.Resources.Controls" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:flowlauncher="clr-namespace:Flow.Launcher" Title="{DynamicResource customeQueryHotkeyTitle}" @@ -29,35 +30,13 @@ - - - - - - - - - + Date: Mon, 1 Jun 2026 16:09:11 +0200 Subject: [PATCH 25/32] Make ActionKeywords use CustomWindowTitleBar instead of duplicating its own version --- Flow.Launcher/ActionKeywords.xaml | 32 +++++++++------------------- Flow.Launcher/ActionKeywords.xaml.cs | 1 + 2 files changed, 11 insertions(+), 22 deletions(-) diff --git a/Flow.Launcher/ActionKeywords.xaml b/Flow.Launcher/ActionKeywords.xaml index 5af76f37f39..b575b3859df 100644 --- a/Flow.Launcher/ActionKeywords.xaml +++ b/Flow.Launcher/ActionKeywords.xaml @@ -2,6 +2,7 @@ x:Class="Flow.Launcher.ActionKeywords" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:controls="clr-namespace:Flow.Launcher.Resources.Controls" Title="{DynamicResource actionKeywordsTitle}" Width="450" Background="{DynamicResource PopuBGColor}" @@ -29,29 +30,16 @@ - + Grid.Column="0" + Grid.ColumnSpan="2" + ShowIcon="False" + ShowTitle="False" + ShowMinimizeButton="False" + ShowMaximizeRestoreButton="False" + ShowCloseButton="True" + CloseButtonClick="BtnCancel_OnClick" /> Date: Tue, 2 Jun 2026 11:48:09 +0200 Subject: [PATCH 26/32] Add comments & docstrings to CustomWindowTitleBar --- .../Controls/CustomWindowTitleBar.xaml.cs | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml.cs b/Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml.cs index b44cb14d89f..f07eb294c2b 100644 --- a/Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml.cs +++ b/Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml.cs @@ -79,9 +79,36 @@ public WindowStateChangedEventArgs(WindowState previousState, WindowState curren typeMetadata: new PropertyMetadata(defaultValue: true, propertyChangedCallback: OnButtonVisibilityOptionChanged) ); + /// + /// Occurs when the minimize button is clicked. + /// + /// + /// Set to in a subscriber to suppress + /// the control's default minimize behavior. + /// public event RoutedEventHandler MinimizeButtonClick; + + /// + /// Occurs when the maximize or restore button is clicked. + /// + /// + /// Set to in a subscriber to suppress + /// the control's default maximize/restore toggle behavior. + /// public event RoutedEventHandler MaximizeRestoreButtonClick; + + /// + /// Occurs when the close button is clicked. + /// + /// + /// Set to in a subscriber to suppress + /// the control's default host-window close behavior. + /// public event RoutedEventHandler CloseButtonClick; + + /// + /// Occurs when changes. + /// public event EventHandler LastNonMinimizedWindowStateChanged; private Window _hostWindow; @@ -94,6 +121,9 @@ public WindowStateChangedEventArgs(WindowState previousState, WindowState curren private Image IconImageElement => FindName("IconImage") as Image; private TextBlock TitleTextBlockElement => FindName("TitleTextBlock") as TextBlock; + /// + /// Initializes a new instance of the class. + /// public CustomWindowTitleBar() { InitializeComponent(); @@ -101,48 +131,78 @@ public CustomWindowTitleBar() Unloaded += CustomWindowTitleBar_Unloaded; } + /// + /// Gets or sets the icon source shown in the title bar. + /// + /// + /// If unset (), the control falls back to the host window icon, then to the default app icon. + /// public ImageSource IconSource { get => (ImageSource)GetValue(IconSourceProperty); set => SetValue(IconSourceProperty, value); } + /// + /// Gets or sets the title text shown in the title bar. + /// + /// + /// If unset (), the control uses the host window title when available. + /// public string Title { get => (string)GetValue(TitleProperty); set => SetValue(TitleProperty, value); } + /// + /// Gets or sets a value indicating whether the window icon is visible. + /// public bool ShowIcon { get => (bool)GetValue(ShowIconProperty); set => SetValue(ShowIconProperty, value); } + /// + /// Gets or sets a value indicating whether the title text is visible. + /// public bool ShowTitle { get => (bool)GetValue(ShowTitleProperty); set => SetValue(ShowTitleProperty, value); } + /// + /// Gets or sets a value indicating whether the minimize button is visible. + /// public bool ShowMinimizeButton { get => (bool)GetValue(ShowMinimizeButtonProperty); set => SetValue(ShowMinimizeButtonProperty, value); } + /// + /// Gets or sets a value indicating whether the maximize/restore button is visible. + /// public bool ShowMaximizeRestoreButton { get => (bool)GetValue(ShowMaximizeRestoreButtonProperty); set => SetValue(ShowMaximizeRestoreButtonProperty, value); } + /// + /// Gets or sets a value indicating whether the close button is visible. + /// public bool ShowCloseButton { get => (bool)GetValue(ShowCloseButtonProperty); set => SetValue(ShowCloseButtonProperty, value); } + /// + /// Gets the last observed window state that was not minimized. + /// public WindowState LastNonMinimizedWindowState { get => _lastNonMinimizedWindowState; } @@ -324,6 +384,7 @@ private void MinimizeButton_OnClick(object sender, RoutedEventArgs e) MinimizeButtonClick?.Invoke(this, e); + // External handlers can override the built-in behavior by marking the routed event as handled. if (e.Handled) { return; @@ -346,6 +407,7 @@ private void MaximizeRestoreButton_OnClick(object sender, RoutedEventArgs e) MaximizeRestoreButtonClick?.Invoke(this, e); + // External handlers can override the built-in behavior by marking the routed event as handled. if (e.Handled) { return; @@ -372,6 +434,7 @@ private void CloseButton_OnClick(object sender, RoutedEventArgs e) CloseButtonClick?.Invoke(this, e); + // External handlers can override the built-in behavior by marking the routed event as handled. if (e.Handled) { return; From 7aa625093c5265f04fb5ee152ce907591250c498 Mon Sep 17 00:00:00 2001 From: David Brett Date: Tue, 2 Jun 2026 12:09:08 +0200 Subject: [PATCH 27/32] Make MinimizeButton in CustomWindowTitleBar use StaticResource for its style like the other buttons --- Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml b/Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml index 32983381b72..ebac26e84b9 100644 --- a/Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml +++ b/Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml @@ -37,7 +37,7 @@ Grid.Column="2" Click="MinimizeButton_OnClick" RenderOptions.EdgeMode="Aliased" - Style="{DynamicResource TitleBarButtonStyle}"> + Style="{StaticResource TitleBarButtonStyle}"> Date: Tue, 2 Jun 2026 13:38:44 +0200 Subject: [PATCH 28/32] Extract repeated path styling in CustomWindowTitleBar to new TitleBarButtonPathStyle --- .../Controls/CustomWindowTitleBar.xaml | 68 +++---------------- .../Resources/CustomControlTemplate.xaml | 12 ++++ 2 files changed, 20 insertions(+), 60 deletions(-) diff --git a/Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml b/Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml index ebac26e84b9..01c1c1afd5e 100644 --- a/Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml +++ b/Flow.Launcher/Resources/Controls/CustomWindowTitleBar.xaml @@ -38,44 +38,18 @@ Click="MinimizeButton_OnClick" RenderOptions.EdgeMode="Aliased" Style="{StaticResource TitleBarButtonStyle}"> - - - - - + Style="{StaticResource TitleBarButtonPathStyle}" /> diff --git a/Flow.Launcher/Resources/CustomControlTemplate.xaml b/Flow.Launcher/Resources/CustomControlTemplate.xaml index a2d1ba13aa1..a1d516a156b 100644 --- a/Flow.Launcher/Resources/CustomControlTemplate.xaml +++ b/Flow.Launcher/Resources/CustomControlTemplate.xaml @@ -169,6 +169,18 @@ + +