mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
Merge branch 'dev' into administrator_mode
This commit is contained in:
commit
7a702eb7de
9 changed files with 135 additions and 13 deletions
|
|
@ -83,6 +83,11 @@
|
|||
"resolved": "1.0.0",
|
||||
"contentHash": "nwbZAYd+DblXAIzlnwDSnl0CiCm8jWLfHSYnoN4wYhtIav6AegB3+T/vKzLbU2IZlPB8Bvl8U3NXpx3eaz+N5w=="
|
||||
},
|
||||
"ini-parser": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.5.2",
|
||||
"contentHash": "hp3gKmC/14+6eKLgv7Jd1Z7OV86lO+tNfOXr/stQbwmRhdQuXVSvrRAuAe7G5+lwhkov0XkqZ8/bn1PYWMx6eg=="
|
||||
},
|
||||
"InputSimulator": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.0.4",
|
||||
|
|
@ -263,7 +268,8 @@
|
|||
"NLog.OutputDebugString": "[6.0.4, )",
|
||||
"SharpVectors.Wpf": "[1.8.5, )",
|
||||
"System.Drawing.Common": "[7.0.0, )",
|
||||
"ToolGood.Words.Pinyin": "[3.1.0.3, )"
|
||||
"ToolGood.Words.Pinyin": "[3.1.0.3, )",
|
||||
"ini-parser": "[2.5.2, )"
|
||||
}
|
||||
},
|
||||
"flow.launcher.plugin": {
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@
|
|||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="ini-parser" Version="2.5.2" />
|
||||
<PackageReference Include="InputSimulator" Version="1.0.4" />
|
||||
<PackageReference Include="MemoryPack" Version="1.21.4" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Threading" Version="17.14.15" />
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows;
|
||||
using System.Windows.Interop;
|
||||
using System.Windows.Media.Imaging;
|
||||
using IniParser;
|
||||
using Windows.Win32;
|
||||
using Windows.Win32.Foundation;
|
||||
using Windows.Win32.UI.Shell;
|
||||
using Windows.Win32.Graphics.Gdi;
|
||||
using Windows.Win32.UI.Shell;
|
||||
|
||||
namespace Flow.Launcher.Infrastructure.Image
|
||||
{
|
||||
|
|
@ -35,9 +36,32 @@ namespace Flow.Launcher.Infrastructure.Image
|
|||
|
||||
private static readonly HRESULT S_PATHNOTFOUND = (HRESULT)0x8004B205;
|
||||
|
||||
private const string UrlExtension = ".url";
|
||||
|
||||
/// <summary>
|
||||
/// Obtains a BitmapSource thumbnail for the specified file.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If the file is a Windows URL shortcut (".url"), the method attempts to resolve the shortcut's icon and use that for the thumbnail; otherwise it requests a thumbnail for the file path. The native HBITMAP used to create the BitmapSource is always released to avoid native memory leaks.
|
||||
/// </remarks>
|
||||
/// <param name="fileName">Path to the file (can be a regular file or a ".url" shortcut).</param>
|
||||
/// <param name="width">Requested thumbnail width in pixels.</param>
|
||||
/// <param name="height">Requested thumbnail height in pixels.</param>
|
||||
/// <param name="options">Thumbnail extraction options (flags) controlling fallback and caching behavior.</param>
|
||||
/// <returns>A BitmapSource representing the requested thumbnail.</returns>
|
||||
public static BitmapSource GetThumbnail(string fileName, int width, int height, ThumbnailOptions options)
|
||||
{
|
||||
HBITMAP hBitmap = GetHBitmap(Path.GetFullPath(fileName), width, height, options);
|
||||
HBITMAP hBitmap;
|
||||
|
||||
var extension = Path.GetExtension(fileName);
|
||||
if (string.Equals(extension, UrlExtension, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
hBitmap = GetHBitmapForUrlFile(fileName, width, height, options);
|
||||
}
|
||||
else
|
||||
{
|
||||
hBitmap = GetHBitmap(Path.GetFullPath(fileName), width, height, options);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
|
|
@ -50,6 +74,21 @@ namespace Flow.Launcher.Infrastructure.Image
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Obtains a native HBITMAP for the specified file at the requested size using the Windows Shell image factory.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If <paramref name="options"/> is <see cref="ThumbnailOptions.ThumbnailOnly"/> and thumbnail extraction fails
|
||||
/// due to extraction errors or a missing path, the method falls back to requesting an icon (<see cref="ThumbnailOptions.IconOnly"/>).
|
||||
/// The returned HBITMAP is a raw GDI handle; the caller is responsible for releasing it (e.g., via DeleteObject) to avoid native memory leaks.
|
||||
/// </remarks>
|
||||
/// <param name="fileName">Path to the file to thumbnail.</param>
|
||||
/// <param name="width">Requested thumbnail width in pixels.</param>
|
||||
/// <param name="height">Requested thumbnail height in pixels.</param>
|
||||
/// <param name="options">Thumbnail request flags that control behavior (e.g., ThumbnailOnly, IconOnly).</param>
|
||||
/// <returns>An HBITMAP handle containing the image. Caller must free the handle when finished.</returns>
|
||||
/// <exception cref="COMException">If creating the shell item fails (HRESULT returned by SHCreateItemFromParsingName).</exception>
|
||||
/// <exception cref="InvalidOperationException">If the shell item does not expose IShellItemImageFactory or if an unexpected error occurs while obtaining the image.</exception>
|
||||
private static unsafe HBITMAP GetHBitmap(string fileName, int width, int height, ThumbnailOptions options)
|
||||
{
|
||||
var retCode = PInvoke.SHCreateItemFromParsingName(
|
||||
|
|
@ -108,5 +147,44 @@ namespace Flow.Launcher.Infrastructure.Image
|
|||
|
||||
return hBitmap;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Obtains an HBITMAP for a Windows .url shortcut by resolving its IconFile entry and delegating to GetHBitmap.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The method parses the .url file as an INI, looks in the "InternetShortcut" section for the "IconFile" entry,
|
||||
/// and requests a bitmap for that icon path. If no IconFile is present or any error occurs while reading or
|
||||
/// resolving the icon, it falls back to requesting a thumbnail for the .url file itself.
|
||||
/// </remarks>
|
||||
/// <param name="fileName">Path to the .url shortcut file.</param>
|
||||
/// <param name="width">Requested thumbnail width (pixels).</param>
|
||||
/// <param name="height">Requested thumbnail height (pixels).</param>
|
||||
/// <param name="options">ThumbnailOptions flags controlling extraction behavior.</param>
|
||||
/// <returns>An HBITMAP containing the requested image; callers are responsible for freeing the native handle.</returns>
|
||||
private static unsafe HBITMAP GetHBitmapForUrlFile(string fileName, int width, int height, ThumbnailOptions options)
|
||||
{
|
||||
HBITMAP hBitmap;
|
||||
|
||||
try
|
||||
{
|
||||
var parser = new FileIniDataParser();
|
||||
var data = parser.ReadFile(fileName);
|
||||
var urlSection = data["InternetShortcut"];
|
||||
|
||||
var iconPath = urlSection?["IconFile"];
|
||||
if (!File.Exists(iconPath))
|
||||
{
|
||||
// If the IconFile is missing, throw exception to fallback to the default icon
|
||||
throw new FileNotFoundException("Icon file not specified in Internet shortcut (.url) file.");
|
||||
}
|
||||
hBitmap = GetHBitmap(Path.GetFullPath(iconPath), width, height, options);
|
||||
}
|
||||
catch
|
||||
{
|
||||
hBitmap = GetHBitmap(Path.GetFullPath(fileName), width, height, options);
|
||||
}
|
||||
|
||||
return hBitmap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,12 @@
|
|||
"resolved": "6.9.3",
|
||||
"contentHash": "1CUGgFdyECDKgi5HaUBhdv6k+VG9Iy4OCforGfHyar3xQXAJypZkzymgKtWj/4SPd6nSG0Qi7NH71qHrDSZLaA=="
|
||||
},
|
||||
"ini-parser": {
|
||||
"type": "Direct",
|
||||
"requested": "[2.5.2, )",
|
||||
"resolved": "2.5.2",
|
||||
"contentHash": "hp3gKmC/14+6eKLgv7Jd1Z7OV86lO+tNfOXr/stQbwmRhdQuXVSvrRAuAe7G5+lwhkov0XkqZ8/bn1PYWMx6eg=="
|
||||
},
|
||||
"InputSimulator": {
|
||||
"type": "Direct",
|
||||
"requested": "[1.0.4, )",
|
||||
|
|
|
|||
|
|
@ -150,6 +150,16 @@ namespace Flow.Launcher.Plugin.SharedCommands
|
|||
return File.Exists(filePath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a file or directory exists
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <returns></returns>
|
||||
public static bool FileOrLocationExists(this string path)
|
||||
{
|
||||
return LocationExists(path) || FileExists(path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Open a directory window (using the OS's default handler, usually explorer)
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -595,6 +595,7 @@
|
|||
<system:String x:Key="errorTitle">Error</system:String>
|
||||
<system:String x:Key="folderOpenError">An error occurred while opening the folder. {0}</system:String>
|
||||
<system:String x:Key="browserOpenError">An error occurred while opening the URL in the browser. Please check your Default Web Browser configuration in the General section of the settings window</system:String>
|
||||
<system:String x:Key="fileNotFoundError">File or directory not found: {0}</system:String>
|
||||
|
||||
<!-- General Notice -->
|
||||
<system:String x:Key="pleaseWait">Please wait...</system:String>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
|
|
@ -182,7 +182,7 @@ namespace Flow.Launcher
|
|||
|
||||
Clipboard.SetFileDropList(paths);
|
||||
});
|
||||
|
||||
|
||||
if (exception == null)
|
||||
{
|
||||
if (showDefaultNotification)
|
||||
|
|
@ -221,7 +221,7 @@ namespace Flow.Launcher
|
|||
{
|
||||
LogException(nameof(PublicAPIInstance), "Failed to copy text to clipboard", exception);
|
||||
ShowMsgError(GetTranslation("failedToCopy"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -330,7 +330,7 @@ namespace Flow.Launcher
|
|||
|
||||
((PluginJsonStorage<T>)_pluginJsonStorages[type]).Save();
|
||||
}
|
||||
|
||||
|
||||
public void OpenDirectory(string directoryPath, string fileNameOrFilePath = null)
|
||||
{
|
||||
try
|
||||
|
|
@ -415,6 +415,12 @@ namespace Flow.Launcher
|
|||
|
||||
private void OpenUri(Uri uri, bool? inPrivate = null, bool forceBrowser = false)
|
||||
{
|
||||
if (uri.IsFile && !FilesFolders.FileOrLocationExists(uri.LocalPath))
|
||||
{
|
||||
ShowMsgError(GetTranslation("errorTitle"), string.Format(GetTranslation("fileNotFoundError"), uri.LocalPath));
|
||||
return;
|
||||
}
|
||||
|
||||
if (forceBrowser || uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps)
|
||||
{
|
||||
var browserInfo = _settings.CustomBrowser;
|
||||
|
|
@ -444,7 +450,15 @@ namespace Flow.Launcher
|
|||
}
|
||||
else
|
||||
{
|
||||
StartProcess(uri.AbsoluteUri, arguments: string.Empty, useShellExecute: true);
|
||||
try
|
||||
{
|
||||
StartProcess(uri.AbsoluteUri, arguments: string.Empty, useShellExecute: true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LogException(ClassName, $"Failed to open: {uri.AbsoluteUri}", e);
|
||||
ShowMsgError(GetTranslation("errorTitle"), e.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -478,7 +492,7 @@ namespace Flow.Launcher
|
|||
OpenUri(appUri);
|
||||
}
|
||||
|
||||
public void ToggleGameMode()
|
||||
public void ToggleGameMode()
|
||||
{
|
||||
_mainVM.ToggleGameMode();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -204,6 +204,11 @@
|
|||
"resolved": "1.11.42",
|
||||
"contentHash": "LDc1bEfF14EY2DZzak4xvzWvbpNXK3vi1u0KQbBpLUN4+cx/VrvXhgCAMSJhSU5vz0oMfW9JZIR20vj/PkDHPA=="
|
||||
},
|
||||
"ini-parser": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.5.2",
|
||||
"contentHash": "hp3gKmC/14+6eKLgv7Jd1Z7OV86lO+tNfOXr/stQbwmRhdQuXVSvrRAuAe7G5+lwhkov0XkqZ8/bn1PYWMx6eg=="
|
||||
},
|
||||
"InputSimulator": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.0.4",
|
||||
|
|
@ -863,7 +868,8 @@
|
|||
"NLog.OutputDebugString": "[6.0.4, )",
|
||||
"SharpVectors.Wpf": "[1.8.5, )",
|
||||
"System.Drawing.Common": "[7.0.0, )",
|
||||
"ToolGood.Words.Pinyin": "[3.1.0.3, )"
|
||||
"ToolGood.Words.Pinyin": "[3.1.0.3, )",
|
||||
"ini-parser": "[2.5.2, )"
|
||||
}
|
||||
},
|
||||
"flow.launcher.plugin": {
|
||||
|
|
|
|||
|
|
@ -106,8 +106,8 @@
|
|||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
|
||||
<PackageReference Include="Flow.Launcher.Localization" Version="0.0.6" />
|
||||
<PackageReference Include="Microsoft.Data.Sqlite" Version="9.0.9" />
|
||||
<PackageReference Include="Svg.Skia" Version="3.0.6" />
|
||||
<PackageReference Include="SkiaSharp" Version="3.119.0" />
|
||||
<PackageReference Include="Svg.Skia" Version="3.2.1" />
|
||||
<PackageReference Include="SkiaSharp" Version="3.119.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
Loading…
Reference in a new issue