Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
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
36 changes: 12 additions & 24 deletions .github/workflows/default_plugins.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,7 @@ jobs:
files: "Flow.Launcher.Plugin.BrowserBookmark.zip"
tag_name: "v${{steps.updated-version-browserbookmark.outputs.prop}}"
body: Visit Flow's [release notes](https://github.com/Flow-Launcher/Flow.Launcher/releases) for changes.
env:
GITHUB_TOKEN: ${{ secrets.PUBLISH_PLUGINS }}
token: ${{ secrets.PUBLISH_PLUGINS }}


- name: Get Calculator Version
Expand All @@ -77,8 +76,7 @@ jobs:
files: "Flow.Launcher.Plugin.Calculator.zip"
tag_name: "v${{steps.updated-version-calculator.outputs.prop}}"
body: Visit Flow's [release notes](https://github.com/Flow-Launcher/Flow.Launcher/releases) for changes.
env:
GITHUB_TOKEN: ${{ secrets.PUBLISH_PLUGINS }}
token: ${{ secrets.PUBLISH_PLUGINS }}


- name: Get Explorer Version
Expand All @@ -101,8 +99,7 @@ jobs:
files: "Flow.Launcher.Plugin.Explorer.zip"
tag_name: "v${{steps.updated-version-explorer.outputs.prop}}"
body: Visit Flow's [release notes](https://github.com/Flow-Launcher/Flow.Launcher/releases) for changes.
env:
GITHUB_TOKEN: ${{ secrets.PUBLISH_PLUGINS }}
token: ${{ secrets.PUBLISH_PLUGINS }}


- name: Get PluginIndicator Version
Expand All @@ -125,8 +122,7 @@ jobs:
files: "Flow.Launcher.Plugin.PluginIndicator.zip"
tag_name: "v${{steps.updated-version-pluginindicator.outputs.prop}}"
body: Visit Flow's [release notes](https://github.com/Flow-Launcher/Flow.Launcher/releases) for changes.
env:
GITHUB_TOKEN: ${{ secrets.PUBLISH_PLUGINS }}
token: ${{ secrets.PUBLISH_PLUGINS }}


- name: Get PluginsManager Version
Expand All @@ -149,8 +145,7 @@ jobs:
files: "Flow.Launcher.Plugin.PluginsManager.zip"
tag_name: "v${{steps.updated-version-pluginsmanager.outputs.prop}}"
body: Visit Flow's [release notes](https://github.com/Flow-Launcher/Flow.Launcher/releases) for changes.
env:
GITHUB_TOKEN: ${{ secrets.PUBLISH_PLUGINS }}
token: ${{ secrets.PUBLISH_PLUGINS }}


- name: Get ProcessKiller Version
Expand All @@ -173,8 +168,7 @@ jobs:
files: "Flow.Launcher.Plugin.ProcessKiller.zip"
tag_name: "v${{steps.updated-version-processkiller.outputs.prop}}"
body: Visit Flow's [release notes](https://github.com/Flow-Launcher/Flow.Launcher/releases) for changes.
env:
GITHUB_TOKEN: ${{ secrets.PUBLISH_PLUGINS }}
token: ${{ secrets.PUBLISH_PLUGINS }}


- name: Get Program Version
Expand All @@ -197,8 +191,7 @@ jobs:
files: "Flow.Launcher.Plugin.Program.zip"
tag_name: "v${{steps.updated-version-program.outputs.prop}}"
body: Visit Flow's [release notes](https://github.com/Flow-Launcher/Flow.Launcher/releases) for changes.
env:
GITHUB_TOKEN: ${{ secrets.PUBLISH_PLUGINS }}
token: ${{ secrets.PUBLISH_PLUGINS }}


- name: Get Shell Version
Expand All @@ -221,8 +214,7 @@ jobs:
files: "Flow.Launcher.Plugin.Shell.zip"
tag_name: "v${{steps.updated-version-shell.outputs.prop}}"
body: Visit Flow's [release notes](https://github.com/Flow-Launcher/Flow.Launcher/releases) for changes.
env:
GITHUB_TOKEN: ${{ secrets.PUBLISH_PLUGINS }}
token: ${{ secrets.PUBLISH_PLUGINS }}


- name: Get Sys Version
Expand All @@ -245,8 +237,7 @@ jobs:
files: "Flow.Launcher.Plugin.Sys.zip"
tag_name: "v${{steps.updated-version-sys.outputs.prop}}"
body: Visit Flow's [release notes](https://github.com/Flow-Launcher/Flow.Launcher/releases) for changes.
env:
GITHUB_TOKEN: ${{ secrets.PUBLISH_PLUGINS }}
token: ${{ secrets.PUBLISH_PLUGINS }}


- name: Get Url Version
Expand All @@ -269,8 +260,7 @@ jobs:
files: "Flow.Launcher.Plugin.Url.zip"
tag_name: "v${{steps.updated-version-url.outputs.prop}}"
body: Visit Flow's [release notes](https://github.com/Flow-Launcher/Flow.Launcher/releases) for changes.
env:
GITHUB_TOKEN: ${{ secrets.PUBLISH_PLUGINS }}
token: ${{ secrets.PUBLISH_PLUGINS }}


- name: Get WebSearch Version
Expand All @@ -293,8 +283,7 @@ jobs:
files: "Flow.Launcher.Plugin.WebSearch.zip"
tag_name: "v${{steps.updated-version-websearch.outputs.prop}}"
body: Visit Flow's [release notes](https://github.com/Flow-Launcher/Flow.Launcher/releases) for changes.
env:
GITHUB_TOKEN: ${{ secrets.PUBLISH_PLUGINS }}
token: ${{ secrets.PUBLISH_PLUGINS }}


- name: Get WindowsSettings Version
Expand All @@ -317,5 +306,4 @@ jobs:
files: "Flow.Launcher.Plugin.WindowsSettings.zip"
tag_name: "v${{steps.updated-version-windowssettings.outputs.prop}}"
body: Visit Flow's [release notes](https://github.com/Flow-Launcher/Flow.Launcher/releases) for changes.
env:
GITHUB_TOKEN: ${{ secrets.PUBLISH_PLUGINS }}
token: ${{ secrets.PUBLISH_PLUGINS }}
54 changes: 25 additions & 29 deletions Flow.Launcher.Core/Resource/Theme.cs
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,11 @@ public void RemoveDropShadowEffectFromCurrentTheme()
ThemeHelper.CopyStyle(windowBorderStyle, newWindowBorderStyle);

// Copy Setters, excluding the Effect setter and updating the Margin setter
// Only adjust margin if there's actually a shadow effect to remove,
// preventing it from shrinking on repeated calls.
bool hasEffect = windowBorderStyle.Setters.OfType<Setter>()
.Any(s => s.Property == UIElement.EffectProperty);

foreach (var setterBase in windowBorderStyle.Setters)
{
if (setterBase is Setter setter)
Expand All @@ -562,7 +567,7 @@ public void RemoveDropShadowEffectFromCurrentTheme()
if (setter.Property == UIElement.EffectProperty) continue;

// Update Margin by subtracting the extra margin we added for the shadow
if (setter.Property == FrameworkElement.MarginProperty)
if (hasEffect && setter.Property == FrameworkElement.MarginProperty)
{
var currentMargin = (Thickness)setter.Value;
var newMargin = new Thickness(
Expand Down Expand Up @@ -635,20 +640,8 @@ await Application.Current.Dispatcher.InvokeAsync(() =>
// Get the actual backdrop type and drop shadow effect settings
var (backdropType, useDropShadowEffect) = GetActualValue();

// Remove OS minimizing/maximizing animation
// Methods.SetWindowAttribute(new WindowInteropHelper(mainWindow).Handle, DWMWINDOWATTRIBUTE.DWMWA_TRANSITIONS_FORCEDISABLED, 3);

// The timing of adding the shadow effect should vary depending on whether the theme is transparent.
if (BlurEnabled)
{
AutoDropShadow(useDropShadowEffect);
}
SetBlurForWindow(_settings.Theme, backdropType);

if (!BlurEnabled)
{
AutoDropShadow(useDropShadowEffect);
}
AutoDropShadow(useDropShadowEffect);
}, DispatcherPriority.Render);
}

Expand Down Expand Up @@ -725,39 +718,42 @@ private void SetBlurForWindow(string theme, BackdropTypes backdropType)
// Apply the blur effect
Win32Helper.DWMSetBackdropForWindow(mainWindow, backdropType);
ColorizeWindow(theme, backdropType);

// DWM renders rounded corners for backdrop windows
SetWindowCornerPreference("Round");

// Clear any stale directly-set WindowBorderStyle that might shadow
// the merged dictionary entry we just modified above.
if (Application.Current.Resources.Contains("WindowBorderStyle"))
Application.Current.Resources.Remove("WindowBorderStyle");

// For blur themes the resize border defaults to the system thickness.
SetResizeBoarderThickness(null);
}
else
{
// Apply default style when Blur is disabled
Win32Helper.DWMSetBackdropForWindow(mainWindow, BackdropTypes.None);
ColorizeWindow(theme, backdropType);

// Non-blur themes use the default window corner preference
SetWindowCornerPreference("Default");
}

UpdateResourceDictionary(dict);
}

private void AutoDropShadow(bool useDropShadowEffect)
{
if (BlurEnabled)
return; // Blur themes have no drop shadow effect

if (useDropShadowEffect)
{
if (BlurEnabled && Win32Helper.IsBackdropSupported())
{
// For themes with blur enabled, the window border is rendered by the system,
// so we set corner preference to round and remove drop shadow effect to avoid rendering issues.
SetWindowCornerPreference("Round");
RemoveDropShadowEffectFromCurrentTheme();
}
else
{
// For themes without blur, we set corner preference to default and add drop shadow effect.
SetWindowCornerPreference("Default");
AddDropShadowEffectToCurrentTheme();
}
AddDropShadowEffectToCurrentTheme();
}
else
{
// When drop shadow effect is disabled, we set corner preference to default and remove drop shadow effect.
SetWindowCornerPreference("Default");
RemoveDropShadowEffectFromCurrentTheme();
}
}
Expand Down
5 changes: 3 additions & 2 deletions Flow.Launcher.Infrastructure/Constant.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Diagnostics;
using System.Diagnostics;
using System.IO;
using System.Reflection;

Expand Down Expand Up @@ -31,8 +31,9 @@ public static class Constant
public static readonly string ErrorIcon = Path.Combine(ImagesDirectory, "app_error.png");
public static readonly string MissingImgIcon = Path.Combine(ImagesDirectory, "app_missing_img.png");
public static readonly string LoadingImgIcon = Path.Combine(ImagesDirectory, "loading.png");
public static readonly string ImageIcon = Path.Combine(ImagesDirectory, "image.png");
public static readonly string HistoryIcon = Path.Combine(ImagesDirectory, "history.png");
public static readonly string SettingsIcon = Path.Combine(ImagesDirectory, "settings.png");
public static readonly string FolderIcon = Path.Combine(ImagesDirectory, "folder.png");

public static string PythonPath;
public static string NodePath;
Expand Down
53 changes: 41 additions & 12 deletions Flow.Launcher.Infrastructure/Image/ImageHashGenerator.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using System;
using System.IO;
using System.Buffers;
using System.Security.Cryptography;
using System.Windows.Media;
using System.Windows.Media.Imaging;
Expand All @@ -10,27 +10,56 @@ public interface IImageHashGenerator
{
string GetHashFromImage(ImageSource image);
}

public class ImageHashGenerator : IImageHashGenerator
{
public string GetHashFromImage(ImageSource imageSource)
{
if (imageSource is not BitmapSource image)
if (imageSource is not BitmapSource { IsFrozen: true } image)
{
return null;
}

try
{
using var outStream = new MemoryStream();
var enc = new JpegBitmapEncoder();
var bitmapFrame = BitmapFrame.Create(image);
bitmapFrame.Freeze();
enc.Frames.Add(bitmapFrame);
enc.Save(outStream);
var byteArray = outStream.GetBuffer();
using var sha1 = SHA1.Create();
var hash = Convert.ToBase64String(sha1.ComputeHash(byteArray));
return hash;
// Normalize to a deterministic pixel format (32-bit premultiplied BGRA)
BitmapSource normalized = image;
if (normalized.Format != PixelFormats.Pbgra32)
{
var converted = new FormatConvertedBitmap();
converted.BeginInit();
converted.Source = normalized;
converted.DestinationFormat = PixelFormats.Pbgra32;
converted.EndInit();
converted.Freeze();

normalized = converted;
}

// Since we forced Pbgra32, we know it is exactly 4 bytes per pixel.
const int bytesPerPixel = 4;

var stride = normalized.PixelWidth * bytesPerPixel;
var bufferSize = stride * normalized.PixelHeight;

if (bufferSize <= 0)
return null;

// Use ArrayPool to prevent Large Object Heap (LOH) allocations for big images
var rentedPixelBuffer = ArrayPool<byte>.Shared.Rent(bufferSize);

try
{
normalized.CopyPixels(rentedPixelBuffer, stride, 0);

// Slice the rented array to the exact buffer size (Rented arrays are often larger than the requested size)
var hashBytes = SHA1.HashData(rentedPixelBuffer.AsSpan(0, bufferSize));
return Convert.ToBase64String(hashBytes);
}
finally
{
ArrayPool<byte>.Shared.Return(rentedPixelBuffer);
}
}
catch
{
Expand Down
Loading
Loading