diff --git a/Flow.Launcher/Helper/WallpaperPathRetrieval.cs b/Flow.Launcher/Helper/WallpaperPathRetrieval.cs index 151ce97dd83..77bebe2d37d 100644 --- a/Flow.Launcher/Helper/WallpaperPathRetrieval.cs +++ b/Flow.Launcher/Helper/WallpaperPathRetrieval.cs @@ -12,9 +12,9 @@ namespace Flow.Launcher.Helper; public static class WallpaperPathRetrieval { - private static readonly int MAX_CACHE_SIZE = 3; - - private static readonly Dictionary<(string, DateTime), ImageBrush> wallpaperCache = new(); + private const int MaxCacheSize = 3; + private static readonly Dictionary<(string, DateTime), ImageBrush> WallpaperCache = new(); + private static readonly object CacheLock = new(); public static Brush GetWallpaperBrush() { @@ -27,46 +27,71 @@ public static Brush GetWallpaperBrush() try { var wallpaperPath = Win32Helper.GetWallpaperPath(); - if (wallpaperPath is not null && File.Exists(wallpaperPath)) + if (string.IsNullOrEmpty(wallpaperPath) || !File.Exists(wallpaperPath)) + { + App.API.LogInfo(nameof(WallpaperPathRetrieval), $"Wallpaper path is invalid: {wallpaperPath}"); + var wallpaperColor = GetWallpaperColor(); + return new SolidColorBrush(wallpaperColor); + } + + // Since the wallpaper file name can be the same (TranscodedWallpaper), + // we need to add the last modified date to differentiate them + var dateModified = File.GetLastWriteTime(wallpaperPath); + lock (CacheLock) { - // Since the wallpaper file name can be the same (TranscodedWallpaper), - // we need to add the last modified date to differentiate them - var dateModified = File.GetLastWriteTime(wallpaperPath); - wallpaperCache.TryGetValue((wallpaperPath, dateModified), out var cachedWallpaper); + WallpaperCache.TryGetValue((wallpaperPath, dateModified), out var cachedWallpaper); if (cachedWallpaper != null) { return cachedWallpaper; } + } + + using var fileStream = File.OpenRead(wallpaperPath); + var decoder = BitmapDecoder.Create(fileStream, BitmapCreateOptions.DelayCreation, BitmapCacheOption.None); + var frame = decoder.Frames[0]; + var originalWidth = frame.PixelWidth; + var originalHeight = frame.PixelHeight; - // We should not dispose the memory stream since the bitmap is still in use - var memStream = new MemoryStream(File.ReadAllBytes(wallpaperPath)); - var bitmap = new BitmapImage(); - bitmap.BeginInit(); - bitmap.StreamSource = memStream; - bitmap.DecodePixelWidth = 800; - bitmap.DecodePixelHeight = 600; - bitmap.EndInit(); - bitmap.Freeze(); // Make the bitmap thread-safe - var wallpaperBrush = new ImageBrush(bitmap) { Stretch = Stretch.UniformToFill }; - wallpaperBrush.Freeze(); // Make the brush thread-safe + if (originalWidth == 0 || originalHeight == 0) + { + App.API.LogInfo(nameof(WallpaperPathRetrieval), $"Failed to load bitmap: Width={originalWidth}, Height={originalHeight}"); + return new SolidColorBrush(Colors.Transparent); + } + + // Calculate the scaling factor to fit the image within 800x600 while preserving aspect ratio + var widthRatio = 800.0 / originalWidth; + var heightRatio = 600.0 / originalHeight; + var scaleFactor = Math.Min(widthRatio, heightRatio); + var decodedPixelWidth = (int)(originalWidth * scaleFactor); + var decodedPixelHeight = (int)(originalHeight * scaleFactor); + + // Set DecodePixelWidth and DecodePixelHeight to resize the image while preserving aspect ratio + var bitmap = new BitmapImage(); + bitmap.BeginInit(); + bitmap.UriSource = new Uri(wallpaperPath); + bitmap.DecodePixelWidth = decodedPixelWidth; + bitmap.DecodePixelHeight = decodedPixelHeight; + bitmap.EndInit(); + bitmap.Freeze(); // Make the bitmap thread-safe + var wallpaperBrush = new ImageBrush(bitmap) { Stretch = Stretch.UniformToFill }; + wallpaperBrush.Freeze(); // Make the brush thread-safe - // Manage cache size - if (wallpaperCache.Count >= MAX_CACHE_SIZE) + // Manage cache size + lock (CacheLock) + { + if (WallpaperCache.Count >= MaxCacheSize) { // Remove the oldest wallpaper from the cache - var oldestCache = wallpaperCache.Keys.OrderBy(k => k.Item2).FirstOrDefault(); + var oldestCache = WallpaperCache.Keys.OrderBy(k => k.Item2).FirstOrDefault(); if (oldestCache != default) { - wallpaperCache.Remove(oldestCache); + WallpaperCache.Remove(oldestCache); } } - wallpaperCache.Add((wallpaperPath, dateModified), wallpaperBrush); + WallpaperCache.Add((wallpaperPath, dateModified), wallpaperBrush); return wallpaperBrush; } - - var wallpaperColor = GetWallpaperColor(); - return new SolidColorBrush(wallpaperColor); } catch (Exception ex) { @@ -77,7 +102,7 @@ public static Brush GetWallpaperBrush() private static Color GetWallpaperColor() { - RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Control Panel\Colors", true); + RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Control Panel\Colors", false); var result = key?.GetValue("Background", null); if (result is string strResult) { @@ -86,8 +111,9 @@ private static Color GetWallpaperColor() var parts = strResult.Trim().Split(new[] { ' ' }, 3).Select(byte.Parse).ToList(); return Color.FromRgb(parts[0], parts[1], parts[2]); } - catch + catch (Exception ex) { + App.API.LogException(nameof(WallpaperPathRetrieval), "Error parsing wallpaper color", ex); } } diff --git a/Flow.Launcher/Resources/Pages/WelcomePage1.xaml b/Flow.Launcher/Resources/Pages/WelcomePage1.xaml index 1728195bde9..32fdb62fc71 100644 --- a/Flow.Launcher/Resources/Pages/WelcomePage1.xaml +++ b/Flow.Launcher/Resources/Pages/WelcomePage1.xaml @@ -110,8 +110,8 @@ - - + + diff --git a/Flow.Launcher/Resources/Pages/WelcomePage2.xaml b/Flow.Launcher/Resources/Pages/WelcomePage2.xaml index 04c76d0277f..f62cec3bf12 100644 --- a/Flow.Launcher/Resources/Pages/WelcomePage2.xaml +++ b/Flow.Launcher/Resources/Pages/WelcomePage2.xaml @@ -60,7 +60,7 @@ HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Horizontal"> - + diff --git a/Flow.Launcher/Resources/Pages/WelcomePage5.xaml b/Flow.Launcher/Resources/Pages/WelcomePage5.xaml index c898ac9a02e..3df4b506ed2 100644 --- a/Flow.Launcher/Resources/Pages/WelcomePage5.xaml +++ b/Flow.Launcher/Resources/Pages/WelcomePage5.xaml @@ -58,10 +58,10 @@ - + - - + +