diff --git a/Flow.Launcher.Core/Resource/Theme.cs b/Flow.Launcher.Core/Resource/Theme.cs
index c3bb6190f..be849228a 100644
--- a/Flow.Launcher.Core/Resource/Theme.cs
+++ b/Flow.Launcher.Core/Resource/Theme.cs
@@ -11,7 +11,6 @@ using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Effects;
using System.Windows.Shell;
-using System.Windows.Threading;
using Flow.Launcher.Infrastructure;
using Flow.Launcher.Infrastructure.UserSettings;
using Flow.Launcher.Plugin;
@@ -100,12 +99,6 @@ namespace Flow.Launcher.Core.Resource
private void UpdateResourceDictionary(ResourceDictionary dictionaryToUpdate)
{
- // Add new resources
- if (!Application.Current.Resources.MergedDictionaries.Contains(dictionaryToUpdate))
- {
- Application.Current.Resources.MergedDictionaries.Add(dictionaryToUpdate);
- }
-
// Remove old resources
if (_oldResource != null && _oldResource != dictionaryToUpdate &&
Application.Current.Resources.MergedDictionaries.Contains(_oldResource))
@@ -113,7 +106,20 @@ namespace Flow.Launcher.Core.Resource
Application.Current.Resources.MergedDictionaries.Remove(_oldResource);
}
- _oldResource = dictionaryToUpdate;
+ // Add new resources
+ try
+ {
+ if (!Application.Current.Resources.MergedDictionaries.Contains(dictionaryToUpdate))
+ {
+ Application.Current.Resources.MergedDictionaries.Add(dictionaryToUpdate);
+ }
+ _oldResource = dictionaryToUpdate;
+ }
+ catch (InvalidCastException)
+ {
+ // System.InvalidCastException: Unable to cast object of type 'System.Windows.Media.Color' to type 'System.Windows.Expression'.
+ _oldResource = null;
+ }
}
///
@@ -221,7 +227,13 @@ namespace Flow.Launcher.Core.Resource
var foregroundPropertyValue = style.Setters.OfType().Where(x => x.Property.Name == "Foreground")
.Select(x => x.Value).FirstOrDefault();
if (!caretBrushPropertyValue && foregroundPropertyValue != null)
- style.Setters.Add(new Setter(TextBoxBase.CaretBrushProperty, foregroundPropertyValue));
+ {
+ var newCaretValue = GetNewCaretValue(foregroundPropertyValue);
+ if (newCaretValue != null)
+ {
+ style.Setters.Add(new Setter(TextBoxBase.CaretBrushProperty, newCaretValue));
+ }
+ }
}
else
{
@@ -246,6 +258,37 @@ namespace Flow.Launcher.Core.Resource
}
}
+ private static object GetNewCaretValue(object foregroundPropertyValue)
+ {
+ object newCaretValue;
+ if (foregroundPropertyValue is DynamicResourceExtension dynamicResource)
+ {
+ newCaretValue = new DynamicResourceExtension(dynamicResource.ResourceKey);
+ }
+ else if (foregroundPropertyValue is SolidColorBrush solidBrush)
+ {
+ // Create a new brush to avoid sharing mutable freezables with potential expressions
+ if (solidBrush.IsFrozen)
+ {
+ newCaretValue = solidBrush;
+ }
+ else
+ {
+ var newBrush = new SolidColorBrush(solidBrush.Color)
+ {
+ Opacity = solidBrush.Opacity
+ };
+ if (newBrush.CanFreeze) newBrush.Freeze();
+ newCaretValue = newBrush;
+ }
+ }
+ else
+ {
+ newCaretValue = foregroundPropertyValue;
+ }
+ return newCaretValue;
+ }
+
private ResourceDictionary GetThemeResourceDictionary(string theme)
{
var uri = GetThemePath(theme);
@@ -275,10 +318,15 @@ namespace Flow.Launcher.Core.Resource
queryBoxStyle.Setters.Add(new Setter(Control.FontStretchProperty, fontStretch));
var caretBrushPropertyValue = queryBoxStyle.Setters.OfType().Any(x => x.Property.Name == "CaretBrush");
- var foregroundPropertyValue = queryBoxStyle.Setters.OfType().Where(x => x.Property.Name == "Foreground")
- .Select(x => x.Value).FirstOrDefault();
+ var foregroundPropertyValue = queryBoxStyle.Setters.OfType().FirstOrDefault(x => x.Property.Name == "Foreground")?.Value;
if (!caretBrushPropertyValue && foregroundPropertyValue != null) //otherwise BaseQueryBoxStyle will handle styling
- queryBoxStyle.Setters.Add(new Setter(TextBoxBase.CaretBrushProperty, foregroundPropertyValue));
+ {
+ var newCaretValue = GetNewCaretValue(foregroundPropertyValue);
+ if (newCaretValue != null)
+ {
+ queryBoxStyle.Setters.Add(new Setter(TextBoxBase.CaretBrushProperty, newCaretValue));
+ }
+ }
// Query suggestion box's font style is aligned with query box
querySuggestionBoxStyle.Setters.Add(new Setter(Control.FontFamilyProperty, fontFamily));
@@ -596,26 +644,32 @@ namespace Flow.Launcher.Core.Resource
///
public async Task RefreshFrameAsync()
{
- await Application.Current.Dispatcher.InvokeAsync(() =>
+ if (Application.Current == null) return;
+ if (!Application.Current.Dispatcher.CheckAccess())
{
- // Get the actual backdrop type and drop shadow effect settings
- var (backdropType, useDropShadowEffect) = GetActualValue();
+ await Application.Current?.Dispatcher.InvokeAsync(RefreshFrameAsync);
+ return;
+ }
- // Remove OS minimizing/maximizing animation
- // Methods.SetWindowAttribute(new WindowInteropHelper(mainWindow).Handle, DWMWINDOWATTRIBUTE.DWMWA_TRANSITIONS_FORCEDISABLED, 3);
+ // Get the actual backdrop type and drop shadow effect settings
+ var (backdropType, useDropShadowEffect) = GetActualValue();
- // The timing of adding the shadow effect should vary depending on whether the theme is transparent.
- if (BlurEnabled)
- {
- AutoDropShadow(useDropShadowEffect);
- }
- SetBlurForWindow(_settings.Theme, backdropType);
+ // Remove OS minimizing/maximizing animation
+ // Methods.SetWindowAttribute(new WindowInteropHelper(mainWindow).Handle, DWMWINDOWATTRIBUTE.DWMWA_TRANSITIONS_FORCEDISABLED, 3);
- if (!BlurEnabled)
- {
- AutoDropShadow(useDropShadowEffect);
- }
- }, DispatcherPriority.Render);
+ // The timing of adding the shadow effect should vary depending on whether the theme is transparent.
+ if (BlurEnabled)
+ {
+ AutoDropShadow(useDropShadowEffect);
+ }
+#pragma warning disable VSTHRD103 // Call async methods when in an async method
+ SetBlurForWindow(_settings.Theme, backdropType);
+#pragma warning restore VSTHRD103 // Call async methods when in an async method
+
+ if (!BlurEnabled)
+ {
+ AutoDropShadow(useDropShadowEffect);
+ }
}
///
@@ -623,13 +677,17 @@ namespace Flow.Launcher.Core.Resource
///
public async Task SetBlurForWindowAsync()
{
- await Application.Current.Dispatcher.InvokeAsync(() =>
+ if (Application.Current == null) return;
+ if (!Application.Current.Dispatcher.CheckAccess())
{
- // Get the actual backdrop type and drop shadow effect settings
- var (backdropType, _) = GetActualValue();
+ await Application.Current?.Dispatcher.InvokeAsync(SetBlurForWindowAsync);
+ return;
+ }
- SetBlurForWindow(_settings.Theme, backdropType);
- }, DispatcherPriority.Render);
+ // Get the actual backdrop type and drop shadow effect settings
+ var (backdropType, _) = GetActualValue();
+
+ SetBlurForWindow(_settings.Theme, backdropType);
}
///
@@ -674,14 +732,18 @@ namespace Flow.Launcher.Core.Resource
if (backdropType == BackdropTypes.Mica || backdropType == BackdropTypes.MicaAlt)
{
windowBorderStyle.Setters.Remove(windowBorderStyle.Setters.OfType().FirstOrDefault(x => x.Property.Name == "Background"));
- windowBorderStyle.Setters.Add(new Setter(Border.BackgroundProperty, new SolidColorBrush(Color.FromArgb(1, 0, 0, 0))));
+ var brush = new SolidColorBrush(Color.FromArgb(1, 0, 0, 0));
+ brush.Freeze();
+ windowBorderStyle.Setters.Add(new Setter(Border.BackgroundProperty, brush));
}
else if (backdropType == BackdropTypes.Acrylic)
{
windowBorderStyle.Setters.Remove(windowBorderStyle.Setters.OfType().FirstOrDefault(x => x.Property.Name == "Background"));
- windowBorderStyle.Setters.Add(new Setter(Border.BackgroundProperty, new SolidColorBrush(Colors.Transparent)));
+ var brush = new SolidColorBrush(Colors.Transparent);
+ brush.Freeze();
+ windowBorderStyle.Setters.Add(new Setter(Border.BackgroundProperty, brush));
}
-
+
// For themes with blur enabled, the window border is rendered by the system, so it's treated as a simple rectangle regardless of thickness.
//(This is to avoid issues when the window is forcibly changed to a rectangular shape during snap scenarios.)
var cornerRadiusSetter = windowBorderStyle.Setters.OfType().FirstOrDefault(x => x.Property == Border.CornerRadiusProperty);
@@ -689,7 +751,7 @@ namespace Flow.Launcher.Core.Resource
cornerRadiusSetter.Value = new CornerRadius(0);
else
windowBorderStyle.Setters.Add(new Setter(Border.CornerRadiusProperty, new CornerRadius(0)));
-
+
// Apply the blur effect
Win32Helper.DWMSetBackdropForWindow(mainWindow, backdropType);
ColorizeWindow(theme, backdropType);
@@ -706,13 +768,12 @@ namespace Flow.Launcher.Core.Resource
private void AutoDropShadow(bool useDropShadowEffect)
{
- SetWindowCornerPreference("Default");
- RemoveDropShadowEffectFromCurrentTheme();
if (useDropShadowEffect)
{
if (BlurEnabled && Win32Helper.IsBackdropSupported())
{
SetWindowCornerPreference("Round");
+ RemoveDropShadowEffectFromCurrentTheme();
}
else
{
@@ -725,9 +786,11 @@ namespace Flow.Launcher.Core.Resource
if (BlurEnabled && Win32Helper.IsBackdropSupported())
{
SetWindowCornerPreference("Default");
+ RemoveDropShadowEffectFromCurrentTheme();
}
else
{
+ SetWindowCornerPreference("Default");
RemoveDropShadowEffectFromCurrentTheme();
}
}
@@ -765,7 +828,7 @@ namespace Flow.Launcher.Core.Resource
else if (backgroundValue is DynamicResourceExtension dynamicResource)
{
// When DynamicResource Extension it is, Key is resource's name.
- var resourceKey = backgroundSetter.Value.ToString();
+ var resourceKey = dynamicResource.ResourceKey.ToString();
// find key in resource and return color.
if (Resources.Contains(resourceKey))
@@ -803,7 +866,9 @@ namespace Flow.Launcher.Core.Resource
// Apply background color (remove transparency in color)
Color backgroundColor = Color.FromRgb(bgColor.Value.R, bgColor.Value.G, bgColor.Value.B);
- previewStyle.Setters.Add(new Setter(Border.BackgroundProperty, new SolidColorBrush(backgroundColor)));
+ var brush = new SolidColorBrush(backgroundColor);
+ brush.Freeze();
+ previewStyle.Setters.Add(new Setter(Border.BackgroundProperty, brush));
// The blur theme keeps the corner round fixed (applying DWM code to modify it causes rendering issues).
// The non-blur theme retains the previously set WindowBorderStyle.
@@ -817,7 +882,7 @@ namespace Flow.Launcher.Core.Resource
Application.Current.Resources["PreviewWindowBorderStyle"] = previewStyle;
}
- private void CopyStyle(Style originalStyle, Style targetStyle)
+ private static void CopyStyle(Style originalStyle, Style targetStyle)
{
// If the style is based on another style, copy the base style first
if (originalStyle.BasedOn != null)
diff --git a/Flow.Launcher/MainWindow.xaml.cs b/Flow.Launcher/MainWindow.xaml.cs
index 06b2dda9e..113f1f583 100644
--- a/Flow.Launcher/MainWindow.xaml.cs
+++ b/Flow.Launcher/MainWindow.xaml.cs
@@ -109,7 +109,10 @@ namespace Flow.Launcher
private void ViewModel_ActualApplicationThemeChanged(object sender, ActualApplicationThemeChangedEventArgs args)
{
- _ = _theme.RefreshFrameAsync();
+ if (_settings.ColorScheme == Constant.System)
+ {
+ _ = _theme.RefreshFrameAsync();
+ }
}
private void OnSourceInitialized(object sender, EventArgs e)