Skip to content

Improve Wallpaper Retrieval #3279

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Feb 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 68 additions & 4 deletions Flow.Launcher/Helper/WallpaperPathRetrieval.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Documents;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Microsoft.Win32;
using Windows.Win32;
using Windows.Win32.UI.WindowsAndMessaging;
Expand All @@ -13,8 +15,70 @@ namespace Flow.Launcher.Helper;
public static class WallpaperPathRetrieval
{
private static readonly int MAX_PATH = 260;
private static readonly int MAX_CACHE_SIZE = 3;

public static unsafe string GetWallpaperPath()
private static readonly Dictionary<(string, DateTime), ImageBrush> wallpaperCache = new();

public static Brush GetWallpaperBrush()
{
// Invoke the method on the UI thread
if (!Application.Current.Dispatcher.CheckAccess())
{
return Application.Current.Dispatcher.Invoke(GetWallpaperBrush);
}

try
{
var wallpaperPath = GetWallpaperPath();
if (wallpaperPath is not null && File.Exists(wallpaperPath))
{
// 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);
if (cachedWallpaper != null)
{
return cachedWallpaper;
}

// 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

// Manage cache size
if (wallpaperCache.Count >= MAX_CACHE_SIZE)
{
// Remove the oldest wallpaper from the cache
var oldestCache = wallpaperCache.Keys.OrderBy(k => k.Item2).FirstOrDefault();
if (oldestCache != default)
{
wallpaperCache.Remove(oldestCache);
}
}

wallpaperCache.Add((wallpaperPath, dateModified), wallpaperBrush);
return wallpaperBrush;
}

var wallpaperColor = GetWallpaperColor();
return new SolidColorBrush(wallpaperColor);
}
catch (Exception ex)
{
App.API.LogException(nameof(WallpaperPathRetrieval), "Error retrieving wallpaper", ex);
return new SolidColorBrush(Colors.Transparent);
}
}

private static unsafe string GetWallpaperPath()
{
var wallpaperPtr = stackalloc char[MAX_PATH];
PInvoke.SystemParametersInfo(SYSTEM_PARAMETERS_INFO_ACTION.SPI_GETDESKWALLPAPER, (uint)MAX_PATH,
Expand All @@ -25,7 +89,7 @@ public static unsafe string GetWallpaperPath()
return wallpaper.ToString();
}

public static Color GetWallpaperColor()
private static Color GetWallpaperColor()
{
RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Control Panel\Colors", true);
var result = key?.GetValue("Background", null);
Expand Down
21 changes: 1 addition & 20 deletions Flow.Launcher/Resources/Pages/WelcomePage2.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
using System.Windows.Navigation;
using CommunityToolkit.Mvvm.Input;
using Flow.Launcher.ViewModel;
using System.IO;
using System.Windows.Media.Imaging;
using System.Windows.Media;

namespace Flow.Launcher.Resources.Pages
Expand All @@ -33,24 +31,7 @@ private static void SetTogglingHotkey(HotkeyModel hotkey)

public Brush PreviewBackground
{
get
{
var wallpaper = WallpaperPathRetrieval.GetWallpaperPath();
if (wallpaper is not null && File.Exists(wallpaper))
{
var memStream = new MemoryStream(File.ReadAllBytes(wallpaper));
var bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.StreamSource = memStream;
bitmap.DecodePixelWidth = 800;
bitmap.DecodePixelHeight = 600;
bitmap.EndInit();
return new ImageBrush(bitmap) { Stretch = Stretch.UniformToFill };
}

var wallpaperColor = WallpaperPathRetrieval.GetWallpaperColor();
return new SolidColorBrush(wallpaperColor);
}
get => WallpaperPathRetrieval.GetWallpaperBrush();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
using System.IO;
using System.Linq;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using CommunityToolkit.Mvvm.Input;
using Flow.Launcher.Core.Resource;
using Flow.Launcher.Helper;
Expand All @@ -14,7 +13,6 @@
using Flow.Launcher.Plugin;
using Flow.Launcher.ViewModel;
using ModernWpf;
using Flow.Launcher.Core;
using ThemeManager = Flow.Launcher.Core.Resource.ThemeManager;
using ThemeManagerForColorSchemeSwitch = ModernWpf.ThemeManager;

Expand Down Expand Up @@ -212,24 +210,7 @@ public bool UseDate

public Brush PreviewBackground
{
get
{
var wallpaper = WallpaperPathRetrieval.GetWallpaperPath();
if (wallpaper is not null && File.Exists(wallpaper))
{
var memStream = new MemoryStream(File.ReadAllBytes(wallpaper));
var bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.StreamSource = memStream;
bitmap.DecodePixelWidth = 800;
bitmap.DecodePixelHeight = 600;
bitmap.EndInit();
return new ImageBrush(bitmap) { Stretch = Stretch.UniformToFill };
}

var wallpaperColor = WallpaperPathRetrieval.GetWallpaperColor();
return new SolidColorBrush(wallpaperColor);
}
get => WallpaperPathRetrieval.GetWallpaperBrush();
}

public ResultsViewModel PreviewResults
Expand Down
Loading