Skip to content

Fix copy to clipboard STA thread issue & Support retry for copy & Async build-in shortcut model & Improve query update logic & Fix build shortcuts text replace issue & Fix startup window hide issue #3314

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

Open
wants to merge 82 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 64 commits
Commits
Show all changes
82 commits
Select commit Hold shift + click to select a range
9f8e829
Delete CopyToClipboard function in JsonRPC api
Jack251970 Mar 6, 2025
d7a29e5
Revert "Delete CopyToClipboard function in JsonRPC api"
Jack251970 Mar 6, 2025
e5ad777
Fix copy to clipboard STA thread issue
Jack251970 Mar 6, 2025
04f6d14
Merge branch 'dev' into delete_clipboard_jsonrpc
Jack251970 Mar 20, 2025
17ecebf
Merge branch 'dev' into delete_clipboard_jsonrpc
Jack251970 Mar 20, 2025
b034f0d
Update Flow.Launcher.Infrastructure/Win32Helper.cs
Jack251970 Mar 20, 2025
c98c419
Update Flow.Launcher.Infrastructure/Win32Helper.cs
Jack251970 Mar 20, 2025
338c8e2
Merge branch 'dev' into delete_clipboard_jsonrpc
Jack251970 Mar 26, 2025
ff2cb96
Merge branch 'dev' into delete_clipboard_jsonrpc
Jack251970 Mar 27, 2025
817d247
Merge branch 'dev' into delete_clipboard_jsonrpc
Jack251970 Mar 30, 2025
e0a651c
Add async buildin shortcut model
Jack251970 Mar 30, 2025
a49c465
Add async buildin shortcuts in mainvm
Jack251970 Mar 30, 2025
9897213
Improve log
Jack251970 Mar 30, 2025
123802b
Merge branch 'dev' into delete_clipboard_jsonrpc
Jack251970 Apr 4, 2025
246b1fb
Improve code comments
Jack251970 Apr 5, 2025
3b30209
Merge branch 'dev' into delete_clipboard_jsonrpc
Jack251970 Apr 9, 2025
c1602b0
Merge branch 'dev' into delete_clipboard_jsonrpc
Jack251970 Apr 12, 2025
8168d8a
Merge branch 'dev' into delete_clipboard_jsonrpc
Jack251970 Apr 13, 2025
3fc69ab
Fix typos
Jack251970 Apr 13, 2025
0314a9f
Add SetText back
Jack251970 Apr 13, 2025
ff9f1e1
Merge branch 'dev' into delete_clipboard_jsonrpc
Jack251970 Apr 14, 2025
8db8d5c
Add dispatcher back
Jack251970 Apr 14, 2025
f742460
Add code comments
Jack251970 Apr 14, 2025
ae7cea1
Fix COMException
Jack251970 Apr 14, 2025
3be057d
Revert "Fix COMException"
Jack251970 Apr 14, 2025
2f27fa6
Do not open report window for task scheduler exception
Jack251970 Apr 14, 2025
1b412da
Improve error reporting
Jack251970 Apr 15, 2025
370be2a
Use JoinableTaskFactory instead
Jack251970 Apr 15, 2025
0c592b1
Fix typos
Jack251970 Apr 15, 2025
d08deab
Code quality
Jack251970 Apr 15, 2025
e55f79e
Improve code comments & code quality
Jack251970 Apr 15, 2025
0eeaaea
Merge branch 'dev' into delete_clipboard_jsonrpc
Jack251970 Apr 15, 2025
bd1da94
Merge branch 'dev' into delete_clipboard_jsonrpc
Jack251970 Apr 16, 2025
882b7dc
Check ui thread access when calling ui thread
Jack251970 Apr 16, 2025
ba5a76a
Improve performance
Jack251970 Apr 16, 2025
632dbeb
Check ui thread access when calling ui thread
Jack251970 Apr 16, 2025
8f23870
Back to original style for fixing task issues
Jack251970 Apr 16, 2025
9dc9cde
Check token
Jack251970 Apr 16, 2025
5990820
Set update source null
Jack251970 Apr 16, 2025
72c2d7f
Wait update source cancellation before next update source
Jack251970 Apr 16, 2025
9242f8e
Valid plugin after
Jack251970 Apr 16, 2025
0e70519
Adjust ident
Jack251970 Apr 16, 2025
290750a
Dispose update slim
Jack251970 Apr 16, 2025
a780719
Improve code comments
Jack251970 Apr 16, 2025
00c496f
Revert "Set update source null"
Jack251970 Apr 16, 2025
5002449
Use gloabl token & remove useless check
Jack251970 Apr 16, 2025
396cd69
Do not dispose update source
Jack251970 Apr 16, 2025
893ec48
Remove unused check
Jack251970 Apr 16, 2025
a22306a
Use Query check instead of bool check
Jack251970 Apr 16, 2025
8e15e7f
Change variable name
Jack251970 Apr 16, 2025
67ed7a1
Do not use dispatcher
Jack251970 Apr 17, 2025
14cdf8a
Add cancel token check
Jack251970 Apr 17, 2025
be0c1ad
Switch to ThreadPool thread to keep UI responsive when waiting update…
Jack251970 Apr 17, 2025
43826cb
Add cancel token
Jack251970 Apr 17, 2025
5441fc4
Fix log message issue
Jack251970 Apr 17, 2025
20b5c47
Fix progress bar issue when cancelling query with empty
Jack251970 Apr 17, 2025
9eb7c9c
Wait last query to be canceled and then do resetting actions
Jack251970 Apr 17, 2025
b9e04ff
Improve code comments
Jack251970 Apr 17, 2025
236abc8
Add test codes
Jack251970 Apr 17, 2025
96bb07d
Use dispatcher for performance
Jack251970 Apr 17, 2025
56a3551
Fix performance issue
Jack251970 Apr 17, 2025
4ca8c60
Add test codes
Jack251970 Apr 17, 2025
ab95342
Improve test codes
Jack251970 Apr 17, 2025
186cd2c
Remove useless switch
Jack251970 Apr 17, 2025
4aa9a34
Fix test codes
Jack251970 Apr 17, 2025
e9a0868
Add running query check
Jack251970 Apr 17, 2025
854e61d
Add test codes
Jack251970 Apr 17, 2025
7961615
Improve test codes
Jack251970 Apr 17, 2025
e5b5ec5
Improve test codes
Jack251970 Apr 17, 2025
30a840a
Improve test codes
Jack251970 Apr 17, 2025
b918d00
Improve display performance
Jack251970 Apr 17, 2025
adde491
Suppress warning
Jack251970 Apr 18, 2025
6859232
Merge branch 'dev' into delete_clipboard_jsonrpc
Jack251970 Apr 18, 2025
c78a558
Merge branch 'dev' into delete_clipboard_jsonrpc
Jack251970 Apr 19, 2025
c0b792c
Set running query null after update lock and update cancellation
Jack251970 Apr 20, 2025
7669bba
Inline update source
Jack251970 Apr 22, 2025
ccfc6fd
Merge branch 'dev' into delete_clipboard_jsonrpc
Jack251970 Apr 22, 2025
282f486
Fix query input check issue
Jack251970 Apr 22, 2025
a143cb4
Improve code comments
Jack251970 Apr 22, 2025
1ffbbca
Remove _updateToken
Jack251970 Apr 22, 2025
836d09e
Ignore main window show when exiting
Jack251970 Apr 23, 2025
6bb638b
Fix window blink issue
Jack251970 Apr 23, 2025
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
20 changes: 10 additions & 10 deletions Flow.Launcher.Core/Resource/Theme.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public Theme(IPublicAPI publicAPI, Settings settings)
{
_api.LogError(ClassName, "Current theme resource not found. Initializing with default theme.");
_oldTheme = Constant.DefaultTheme;
};
}
}

#endregion
Expand Down Expand Up @@ -126,7 +126,7 @@ public void UpdateFonts()
// Load a ResourceDictionary for the specified theme.
var themeName = _settings.Theme;
var dict = GetThemeResourceDictionary(themeName);

// Apply font settings to the theme resource.
ApplyFontSettings(dict);
UpdateResourceDictionary(dict);
Expand All @@ -152,11 +152,11 @@ private void ApplyFontSettings(ResourceDictionary dict)
var fontStyle = FontHelper.GetFontStyleFromInvariantStringOrNormal(_settings.QueryBoxFontStyle);
var fontWeight = FontHelper.GetFontWeightFromInvariantStringOrNormal(_settings.QueryBoxFontWeight);
var fontStretch = FontHelper.GetFontStretchFromInvariantStringOrNormal(_settings.QueryBoxFontStretch);

SetFontProperties(queryBoxStyle, fontFamily, fontStyle, fontWeight, fontStretch, true);
SetFontProperties(querySuggestionBoxStyle, fontFamily, fontStyle, fontWeight, fontStretch, false);
}

if (dict["ItemTitleStyle"] is Style resultItemStyle &&
dict["ItemTitleSelectedStyle"] is Style resultItemSelectedStyle &&
dict["ItemHotkeyStyle"] is Style resultHotkeyItemStyle &&
Expand All @@ -172,7 +172,7 @@ private void ApplyFontSettings(ResourceDictionary dict)
SetFontProperties(resultHotkeyItemStyle, fontFamily, fontStyle, fontWeight, fontStretch, false);
SetFontProperties(resultHotkeyItemSelectedStyle, fontFamily, fontStyle, fontWeight, fontStretch, false);
}

if (dict["ItemSubTitleStyle"] is Style resultSubItemStyle &&
dict["ItemSubTitleSelectedStyle"] is Style resultSubItemSelectedStyle)
{
Expand All @@ -197,7 +197,7 @@ private static void SetFontProperties(Style style, FontFamily fontFamily, FontSt
// First, find the setters to remove and store them in a list
var settersToRemove = style.Setters
.OfType<Setter>()
.Where(setter =>
.Where(setter =>
setter.Property == Control.FontFamilyProperty ||
setter.Property == Control.FontStyleProperty ||
setter.Property == Control.FontWeightProperty ||
Expand Down Expand Up @@ -227,18 +227,18 @@ private static void SetFontProperties(Style style, FontFamily fontFamily, FontSt
{
var settersToRemove = style.Setters
.OfType<Setter>()
.Where(setter =>
.Where(setter =>
setter.Property == TextBlock.FontFamilyProperty ||
setter.Property == TextBlock.FontStyleProperty ||
setter.Property == TextBlock.FontWeightProperty ||
setter.Property == TextBlock.FontStretchProperty)
.ToList();

foreach (var setter in settersToRemove)
{
style.Setters.Remove(setter);
}

style.Setters.Add(new Setter(TextBlock.FontFamilyProperty, fontFamily));
style.Setters.Add(new Setter(TextBlock.FontStyleProperty, fontStyle));
style.Setters.Add(new Setter(TextBlock.FontWeightProperty, fontWeight));
Expand Down Expand Up @@ -421,7 +421,7 @@ public bool ChangeTheme(string theme = null)

// Retrieve theme resource – always use the resource with font settings applied.
var resourceDict = GetResourceDictionary(theme);

UpdateResourceDictionary(resourceDict);

_settings.Theme = theme;
Expand Down
5 changes: 4 additions & 1 deletion Flow.Launcher.Infrastructure/NativeMethods.txt
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ MONITORINFOEXW
WM_ENTERSIZEMOVE
WM_EXITSIZEMOVE

OleInitialize
OleUninitialize

GetKeyboardLayout
GetWindowThreadProcessId
ActivateKeyboardLayout
Expand All @@ -53,4 +56,4 @@ INPUTLANGCHANGE_FORWARD
LOCALE_TRANSIENT_KEYBOARD1
LOCALE_TRANSIENT_KEYBOARD2
LOCALE_TRANSIENT_KEYBOARD3
LOCALE_TRANSIENT_KEYBOARD4
LOCALE_TRANSIENT_KEYBOARD4
67 changes: 54 additions & 13 deletions Flow.Launcher.Infrastructure/UserSettings/CustomShortcutModel.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
using System;
using System.Text.Json.Serialization;
using System.Threading.Tasks;

namespace Flow.Launcher.Infrastructure.UserSettings
{
#region Base

public abstract class ShortcutBaseModel
{
public string Key { get; set; }

[JsonIgnore]
public Func<string> Expand { get; set; } = () => { return ""; };

public override bool Equals(object obj)
{
return obj is ShortcutBaseModel other &&
Expand All @@ -22,16 +22,14 @@ public override int GetHashCode()
}
}

public class CustomShortcutModel : ShortcutBaseModel
public class BaseCustomShortcutModel : ShortcutBaseModel
{
public string Value { get; set; }

[JsonConstructorAttribute]
public CustomShortcutModel(string key, string value)
public BaseCustomShortcutModel(string key, string value)
{
Key = key;
Value = value;
Expand = () => { return Value; };
}

public void Deconstruct(out string key, out string value)
Expand All @@ -40,26 +38,69 @@ public void Deconstruct(out string key, out string value)
value = Value;
}

public static implicit operator (string Key, string Value)(CustomShortcutModel shortcut)
public static implicit operator (string Key, string Value)(BaseCustomShortcutModel shortcut)
{
return (shortcut.Key, shortcut.Value);
}

public static implicit operator CustomShortcutModel((string Key, string Value) shortcut)
public static implicit operator BaseCustomShortcutModel((string Key, string Value) shortcut)
{
return new CustomShortcutModel(shortcut.Key, shortcut.Value);
return new BaseCustomShortcutModel(shortcut.Key, shortcut.Value);
}
}

public class BuiltinShortcutModel : ShortcutBaseModel
public class BaseBuiltinShortcutModel : ShortcutBaseModel
{
public string Description { get; set; }

public BuiltinShortcutModel(string key, string description, Func<string> expand)
public BaseBuiltinShortcutModel(string key, string description)
{
Key = key;
Description = description;
Expand = expand ?? (() => { return ""; });
}
}

#endregion

#region Custom Shortcut

public class CustomShortcutModel : BaseCustomShortcutModel
{
[JsonIgnore]
public Func<string> Expand { get; set; } = () => { return string.Empty; };

[JsonConstructor]
public CustomShortcutModel(string key, string value) : base(key, value)
{
Expand = () => { return Value; };
}
}

#endregion

#region Builtin Shortcut

public class BuiltinShortcutModel : BaseBuiltinShortcutModel
{
[JsonIgnore]
public Func<string> Expand { get; set; } = () => { return string.Empty; };

public BuiltinShortcutModel(string key, string description, Func<string> expand) : base(key, description)
{
Expand = expand ?? (() => { return string.Empty; });
}
}

public class AsyncBuiltinShortcutModel : BaseBuiltinShortcutModel
{
[JsonIgnore]
public Func<Task<string>> ExpandAsync { get; set; } = () => { return Task.FromResult(string.Empty); };

public AsyncBuiltinShortcutModel(string key, string description, Func<Task<string>> expandAsync) : base(key, description)
{
ExpandAsync = expandAsync ?? (() => { return Task.FromResult(string.Empty); });
}
}

#endregion
}
4 changes: 2 additions & 2 deletions Flow.Launcher.Infrastructure/UserSettings/Settings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -297,9 +297,9 @@ public bool KeepMaxResults
public ObservableCollection<CustomShortcutModel> CustomShortcuts { get; set; } = new ObservableCollection<CustomShortcutModel>();

[JsonIgnore]
public ObservableCollection<BuiltinShortcutModel> BuiltinShortcuts { get; set; } = new()
public ObservableCollection<BaseBuiltinShortcutModel> BuiltinShortcuts { get; set; } = new()
{
new BuiltinShortcutModel("{clipboard}", "shortcut_clipboard_description", Clipboard.GetText),
new AsyncBuiltinShortcutModel("{clipboard}", "shortcut_clipboard_description", () => Win32Helper.StartSTATaskAsync(Clipboard.GetText)),
new BuiltinShortcutModel("{active_explorer_path}", "shortcut_active_explorer_path", FileExplorerHelper.GetActiveExplorerPath)
};

Expand Down
74 changes: 74 additions & 0 deletions Flow.Launcher.Infrastructure/Win32Helper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
using System.Diagnostics;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;
Expand Down Expand Up @@ -333,6 +335,78 @@ internal static HWND GetWindowHandle(Window window, bool ensure = false)

#endregion

#region STA Thread

/*
Inspired by https://github.com/files-community/Files code on STA Thread handling.
*/

public static Task StartSTATaskAsync(Action action)
{
var taskCompletionSource = new TaskCompletionSource();
Thread thread = new(() =>
{
PInvoke.OleInitialize();

try
{
action();
taskCompletionSource.SetResult();
}
catch (System.Exception ex)
{
taskCompletionSource.SetException(ex);
}
finally
{
PInvoke.OleUninitialize();
}
})
{
IsBackground = true,
Priority = ThreadPriority.Normal
};

thread.SetApartmentState(ApartmentState.STA);
thread.Start();

return taskCompletionSource.Task;
}

public static Task<T> StartSTATaskAsync<T>(Func<T> func)
{
var taskCompletionSource = new TaskCompletionSource<T>();

Thread thread = new(() =>
{
PInvoke.OleInitialize();

try
{
taskCompletionSource.SetResult(func());
}
catch (System.Exception ex)
{
taskCompletionSource.SetException(ex);
}
finally
{
PInvoke.OleUninitialize();
}
})
{
IsBackground = true,
Priority = ThreadPriority.Normal
};

thread.SetApartmentState(ApartmentState.STA);
thread.Start();

return taskCompletionSource.Task;
}

#endregion

#region Keyboard Layout

private const string UserProfileRegistryPath = @"Control Panel\International\User Profile";
Expand Down
12 changes: 6 additions & 6 deletions Flow.Launcher/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
using Flow.Launcher.ViewModel;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.VisualStudio.Threading;

namespace Flow.Launcher
{
Expand All @@ -29,6 +30,7 @@ public partial class App : IDisposable, ISingleInstanceApp
#region Public Properties

public static IPublicAPI API { get; private set; }
public static JoinableTaskFactory JTF { get; } = new JoinableTaskFactory(new JoinableTaskContext());

#endregion

Expand Down Expand Up @@ -149,7 +151,7 @@ await API.StopwatchLogInfoAsync(ClassName, "Startup cost", async () =>
Ioc.Default.GetRequiredService<Portable>().PreStartCleanUpAfterPortabilityUpdate();

API.LogInfo(ClassName, "Begin Flow Launcher startup ----------------------------------------------------");
API.LogInfo(ClassName, "Runtime info:{ErrorReporting.RuntimeInfo()}");
API.LogInfo(ClassName, $"Runtime info:{ErrorReporting.RuntimeInfo()}");

RegisterAppDomainExceptions();
RegisterDispatcherUnhandledException();
Expand All @@ -176,8 +178,6 @@ await API.StopwatchLogInfoAsync(ClassName, "Startup cost", async () =>

_mainWindow = new MainWindow();

API.LogInfo(ClassName, "Dependencies Info:{ErrorReporting.DependenciesInfo()}");

Current.MainWindow = _mainWindow;
Current.MainWindow.Title = Constant.FlowLauncher;

Expand Down Expand Up @@ -225,6 +225,7 @@ private void AutoStartup()
}
}

[Conditional("RELEASE")]
private void AutoUpdates()
{
_ = Task.Run(async () =>
Expand Down Expand Up @@ -282,13 +283,12 @@ private void RegisterDispatcherUnhandledException()
[Conditional("RELEASE")]
private static void RegisterAppDomainExceptions()
{
AppDomain.CurrentDomain.UnhandledException += ErrorReporting.UnhandledExceptionHandle;
AppDomain.CurrentDomain.UnhandledException += ErrorReporting.UnhandledException;
}

/// <summary>
/// let exception throw as normal is better for Debug
/// let exception throw as normal for Debug and Release
/// </summary>
[Conditional("RELEASE")]
private static void RegisterTaskSchedulerUnhandledException()
{
TaskScheduler.UnobservedTaskException += ErrorReporting.TaskSchedulerUnobservedTaskException;
Expand Down
Loading
Loading