Skip to content

Commit 0c51c41

Browse files
authored
Merge branch 'dev' into just-fix-url-small-issues
2 parents 73cc5a9 + 10fcbb9 commit 0c51c41

160 files changed

Lines changed: 1581 additions & 518 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Flow.Launcher.Core/Plugin/PluginConfig.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using Flow.Launcher.Plugin;
77
using System.Text.Json;
88
using Flow.Launcher.Infrastructure.UserSettings;
9+
using Flow.Launcher.Plugin.SharedCommands;
910

1011
namespace Flow.Launcher.Core.Plugin
1112
{
@@ -30,7 +31,18 @@ public static List<PluginMetadata> Parse(string[] pluginDirectories)
3031
{
3132
try
3233
{
33-
Directory.Delete(directory, true);
34+
var fullyDeleted = FilesFolders.TryDeleteDirectoryRobust(directory, maxRetries: 3, retryDelayMs: 200);
35+
if (!fullyDeleted)
36+
{
37+
PublicApi.Instance.LogWarn(ClassName, $"Directory <{directory}> was not fully deleted.");
38+
39+
// Directory was not fully deleted, recreate the marker file so deletion will be retried on next startup
40+
var markerFilePath = Path.Combine(directory, DataLocation.PluginDeleteFile);
41+
if (!File.Exists(markerFilePath))
42+
{
43+
File.WriteAllText(markerFilePath, string.Empty);
44+
}
45+
}
3446
}
3547
catch (Exception e)
3648
{

Flow.Launcher.Core/Plugin/PluginManager.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -931,6 +931,18 @@ internal static bool InstallPlugin(UserPlugin plugin, string zipFilePath, bool c
931931

932932
FilesFolders.CopyAll(pluginFolderPath, newPluginPath, (s) => PublicApi.Instance.ShowMsgBox(s));
933933

934+
// Check if marker file exists and delete it
935+
try
936+
{
937+
var markerFilePath = Path.Combine(newPluginPath, DataLocation.PluginDeleteFile);
938+
if (File.Exists(markerFilePath))
939+
File.Delete(markerFilePath);
940+
}
941+
catch (Exception e)
942+
{
943+
PublicApi.Instance.LogException(ClassName, $"Failed to delete plugin marker file in {newPluginPath}", e);
944+
}
945+
934946
try
935947
{
936948
if (Directory.Exists(tempFolderPluginPath))

Flow.Launcher.Infrastructure/NativeMethods.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,4 +91,6 @@ PBT_APMRESUMEAUTOMATIC
9191
PBT_APMRESUMESUSPEND
9292
PowerRegisterSuspendResumeNotification
9393
PowerUnregisterSuspendResumeNotification
94-
DeviceNotifyCallbackRoutine
94+
DeviceNotifyCallbackRoutine
95+
96+
MonitorFromWindow

Flow.Launcher.Infrastructure/UserSettings/Settings.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,7 @@ public bool HideNotifyIcon
481481
}
482482
public bool LeaveCmdOpen { get; set; }
483483
public bool HideWhenDeactivated { get; set; } = true;
484+
public bool ShowTaskbarWhenInvoked { get; set; } = false;
484485

485486
private bool _showAtTopmost = false;
486487
public bool ShowAtTopmost

Flow.Launcher.Infrastructure/Win32Helper.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1016,5 +1016,32 @@ protected override bool ReleaseHandle()
10161016
}
10171017

10181018
#endregion
1019+
1020+
#region Taskbar
1021+
1022+
public static unsafe void ShowTaskbar()
1023+
{
1024+
// Find the taskbar window
1025+
var taskbarHwnd = PInvoke.FindWindowEx(HWND.Null, HWND.Null, "Shell_TrayWnd", null);
1026+
if (taskbarHwnd == HWND.Null) return;
1027+
1028+
// Magic from https://github.com/Oliviaophia/SmartTaskbar
1029+
const uint TrayBarFlag = 0x05D1;
1030+
var mon = PInvoke.MonitorFromWindow(taskbarHwnd, Windows.Win32.Graphics.Gdi.MONITOR_FROM_FLAGS.MONITOR_DEFAULTTONEAREST);
1031+
PInvoke.PostMessage(taskbarHwnd, TrayBarFlag, new WPARAM(1), new LPARAM((nint)mon.Value));
1032+
}
1033+
1034+
public static void HideTaskbar()
1035+
{
1036+
// Find the taskbar window
1037+
var taskbarHwnd = PInvoke.FindWindowEx(HWND.Null, HWND.Null, "Shell_TrayWnd", null);
1038+
if (taskbarHwnd == HWND.Null) return;
1039+
1040+
// Magic from https://github.com/Oliviaophia/SmartTaskbar
1041+
const uint TrayBarFlag = 0x05D1;
1042+
PInvoke.PostMessage(taskbarHwnd, TrayBarFlag, new WPARAM(0), IntPtr.Zero);
1043+
}
1044+
1045+
#endregion
10191046
}
10201047
}

Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@
1515
</PropertyGroup>
1616

1717
<PropertyGroup>
18-
<Version>5.1.0</Version>
19-
<PackageVersion>5.1.0</PackageVersion>
20-
<AssemblyVersion>5.1.0</AssemblyVersion>
21-
<FileVersion>5.1.0</FileVersion>
18+
<Version>5.2.0</Version>
19+
<PackageVersion>5.2.0</PackageVersion>
20+
<AssemblyVersion>5.2.0</AssemblyVersion>
21+
<FileVersion>5.2.0</FileVersion>
2222
<PackageId>Flow.Launcher.Plugin</PackageId>
2323
<Authors>Flow-Launcher</Authors>
2424
<PackageLicenseExpression>MIT</PackageLicenseExpression>
@@ -72,9 +72,9 @@
7272
<PrivateAssets>all</PrivateAssets>
7373
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
7474
</PackageReference>
75-
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All" />
75+
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="10.0.103" PrivateAssets="All" />
7676
<PackageReference Include="JetBrains.Annotations" Version="2025.2.2" />
77-
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.3.205">
77+
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.3.269">
7878
<PrivateAssets>all</PrivateAssets>
7979
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
8080
</PackageReference>

Flow.Launcher.Plugin/Result.cs

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44
using System.Threading.Tasks;
55
using System.Windows.Controls;
66
using System.Windows.Media;
7+
using System.Text.Json.Serialization;
78

89
namespace Flow.Launcher.Plugin
910
{
1011
/// <summary>
11-
/// Describes a result of a <see cref="Query"/> executed by a plugin
12+
/// Describes a result of a <see cref="Query"/> executed by a plugin.
13+
/// This or its child classes is serializable.
1214
/// </summary>
1315
public class Result
1416
{
@@ -21,6 +23,8 @@ public class Result
2123

2224
private string _icoPath;
2325

26+
private string _icoPathAbsolute;
27+
2428
private string _copyText = string.Empty;
2529

2630
private string _badgeIcoPath;
@@ -64,15 +68,27 @@ public string CopyText
6468
public string AutoCompleteText { get; set; }
6569

6670
/// <summary>
67-
/// The image to be displayed for the result.
71+
/// Path or URI to the icon image for this result.
72+
/// Updates <see cref="IcoPathAbsolute"/> appropriately when set.
6873
/// </summary>
69-
/// <value>Can be a local file path or a URL.</value>
70-
/// <remarks>GlyphInfo is prioritized if not null</remarks>
74+
/// <remarks>
75+
/// Preferred usage: provide a path relative to the plugin directory (for example: "Images\icon.png").
76+
/// Because <see cref="IcoPath"/> is serialized, using relative paths keeps the icon reference portable
77+
/// when Flow is moved.
78+
///
79+
/// Accepted formats:
80+
/// - Relative file paths (resolved against <see cref="PluginDirectory"/> into <see cref="IcoPathAbsolute"/>)
81+
/// - Absolute file paths (left as-is)
82+
/// - HTTP/HTTPS URLs (left as-is)
83+
/// - Data URIs (left as-is)
84+
/// </remarks>
7185
public string IcoPath
7286
{
7387
get => _icoPath;
7488
set
7589
{
90+
_icoPath = value;
91+
7692
// As a standard this property will handle prepping and converting to absolute local path for icon image processing
7793
if (!string.IsNullOrEmpty(value)
7894
&& !string.IsNullOrEmpty(PluginDirectory)
@@ -81,15 +97,23 @@ public string IcoPath
8197
&& !value.StartsWith("https://", StringComparison.OrdinalIgnoreCase)
8298
&& !value.StartsWith("data:image", StringComparison.OrdinalIgnoreCase))
8399
{
84-
_icoPath = Path.Combine(PluginDirectory, value);
100+
_icoPathAbsolute = Path.Combine(PluginDirectory, value);
85101
}
86102
else
87103
{
88-
_icoPath = value;
104+
_icoPathAbsolute = value;
89105
}
90106
}
91107
}
92108

109+
/// <summary>
110+
/// Absolute path or URI which is used to load and display the result icon for Flow.
111+
/// This is populated by the <see cref="IcoPath"/> setter.
112+
/// If a relative path was provided to <see cref="IcoPath"/>, this property will contain the resolved
113+
/// absolute local path after combining with <see cref="PluginDirectory"/>.
114+
/// </summary>
115+
public string IcoPathAbsolute => _icoPathAbsolute;
116+
93117
/// <summary>
94118
/// The image to be displayed for the badge of the result.
95119
/// </summary>
@@ -131,17 +155,34 @@ public string BadgeIcoPath
131155
/// <summary>
132156
/// Delegate to load an icon for this result.
133157
/// </summary>
158+
[JsonIgnore]
134159
public IconDelegate Icon = null;
135160

136161
/// <summary>
137162
/// Delegate to load an icon for the badge of this result.
138163
/// </summary>
164+
[JsonIgnore]
139165
public IconDelegate BadgeIcon = null;
140166

167+
private GlyphInfo _glyph;
168+
141169
/// <summary>
142170
/// Information for Glyph Icon (Prioritized than IcoPath/Icon if user enable Glyph Icons)
143171
/// </summary>
144-
public GlyphInfo Glyph { get; init; }
172+
public GlyphInfo Glyph
173+
{
174+
get => _glyph;
175+
init => _glyph = value;
176+
}
177+
178+
/// <summary>
179+
/// Set the Glyph Icon after initialization
180+
/// </summary>
181+
/// <param name="glyph"></param>
182+
public void SetGlyph(GlyphInfo glyph)
183+
{
184+
_glyph = glyph;
185+
}
145186

146187
/// <summary>
147188
/// An action to take in the form of a function call when the result has been selected.
@@ -151,6 +192,7 @@ public string BadgeIcoPath
151192
/// Its result determines what happens to Flow Launcher's query form:
152193
/// when true, the form will be hidden; when false, it will stay in focus.
153194
/// </remarks>
195+
[JsonIgnore]
154196
public Func<ActionContext, bool> Action { get; set; }
155197

156198
/// <summary>
@@ -161,6 +203,7 @@ public string BadgeIcoPath
161203
/// Its result determines what happens to Flow Launcher's query form:
162204
/// when true, the form will be hidden; when false, it will stay in focus.
163205
/// </remarks>
206+
[JsonIgnore]
164207
public Func<ActionContext, ValueTask<bool>> AsyncAction { get; set; }
165208

166209
/// <summary>
@@ -203,11 +246,13 @@ public string PluginDirectory
203246
/// <example>
204247
/// As external information for ContextMenu
205248
/// </example>
249+
[JsonIgnore]
206250
public object ContextData { get; set; }
207251

208252
/// <summary>
209253
/// Plugin ID that generated this result
210254
/// </summary>
255+
[JsonInclude]
211256
public string PluginID { get; internal set; }
212257

213258
/// <summary>
@@ -223,6 +268,7 @@ public string PluginDirectory
223268
/// <summary>
224269
/// Customized Preview Panel
225270
/// </summary>
271+
[JsonIgnore]
226272
public Lazy<UserControl> PreviewPanel { get; set; }
227273

228274
/// <summary>
@@ -352,6 +398,7 @@ public record PreviewInfo
352398
/// <summary>
353399
/// Delegate to get the preview panel's image
354400
/// </summary>
401+
[JsonIgnore]
355402
public IconDelegate PreviewDelegate { get; set; } = null;
356403

357404
/// <summary>

0 commit comments

Comments
 (0)