diff --git a/Flow.Launcher.Infrastructure/Image/ImageLoader.cs b/Flow.Launcher.Infrastructure/Image/ImageLoader.cs index a49385a02..86df01a30 100644 --- a/Flow.Launcher.Infrastructure/Image/ImageLoader.cs +++ b/Flow.Launcher.Infrastructure/Image/ImageLoader.cs @@ -171,8 +171,8 @@ namespace Flow.Launcher.Infrastructure.Image } catch (System.Exception e2) { - Log.Exception(ClassName, $"|ImageLoader.Load|Failed to get thumbnail for {path} on first try", e); - Log.Exception(ClassName, $"|ImageLoader.Load|Failed to get thumbnail for {path} on second try", e2); + Log.Exception(ClassName, $"Failed to get thumbnail for {path} on first try", e); + Log.Exception(ClassName, $"Failed to get thumbnail for {path} on second try", e2); ImageSource image = ImageCache[Constant.MissingImgIcon, false]; ImageCache[path, false] = image; diff --git a/Flow.Launcher.Infrastructure/Image/ThumbnailReader.cs b/Flow.Launcher.Infrastructure/Image/ThumbnailReader.cs index b98ea50fe..4ce0df026 100644 --- a/Flow.Launcher.Infrastructure/Image/ThumbnailReader.cs +++ b/Flow.Launcher.Infrastructure/Image/ThumbnailReader.cs @@ -12,7 +12,7 @@ using Windows.Win32.Graphics.Gdi; namespace Flow.Launcher.Infrastructure.Image { /// - /// Subclass of + /// Subclass of /// [Flags] public enum ThumbnailOptions @@ -31,7 +31,9 @@ namespace Flow.Launcher.Infrastructure.Image private static readonly Guid GUID_IShellItem = typeof(IShellItem).GUID; - private static readonly HRESULT S_ExtractionFailed = (HRESULT)0x8004B200; + private static readonly HRESULT S_EXTRACTIONFAILED = (HRESULT)0x8004B200; + + private static readonly HRESULT S_PATHNOTFOUND = (HRESULT)0x8004B205; public static BitmapSource GetThumbnail(string fileName, int width, int height, ThumbnailOptions options) { @@ -79,9 +81,10 @@ namespace Flow.Launcher.Infrastructure.Image { imageFactory.GetImage(size, (SIIGBF)options, &hBitmap); } - catch (COMException ex) when (ex.HResult == S_ExtractionFailed && options == ThumbnailOptions.ThumbnailOnly) + catch (COMException ex) when (options == ThumbnailOptions.ThumbnailOnly && + (ex.HResult == S_PATHNOTFOUND || ex.HResult == S_EXTRACTIONFAILED)) { - // Fallback to IconOnly if ThumbnailOnly fails + // Fallback to IconOnly if extraction fails or files cannot be found imageFactory.GetImage(size, (SIIGBF)ThumbnailOptions.IconOnly, &hBitmap); } catch (FileNotFoundException) when (options == ThumbnailOptions.ThumbnailOnly) @@ -89,6 +92,11 @@ namespace Flow.Launcher.Infrastructure.Image // Fallback to IconOnly if files cannot be found imageFactory.GetImage(size, (SIIGBF)ThumbnailOptions.IconOnly, &hBitmap); } + catch (System.Exception ex) + { + // Handle other exceptions + throw new InvalidOperationException("Failed to get thumbnail", ex); + } } finally { diff --git a/Flow.Launcher.Infrastructure/Win32Helper.cs b/Flow.Launcher.Infrastructure/Win32Helper.cs index 6be024389..798501ae3 100644 --- a/Flow.Launcher.Infrastructure/Win32Helper.cs +++ b/Flow.Launcher.Infrastructure/Win32Helper.cs @@ -365,21 +365,10 @@ namespace Flow.Launcher.Infrastructure // No installed English layout found if (enHKL == HKL.Null) return; - // When application is exiting, the Application.Current will be null - if (Application.Current == null) return; - - // Get the FL main window - var hwnd = GetWindowHandle(Application.Current.MainWindow, true); + // Get the foreground window + var hwnd = PInvoke.GetForegroundWindow(); if (hwnd == HWND.Null) return; - // Check if the FL main window is the current foreground window - if (!IsForegroundWindow(hwnd)) - { - var result = PInvoke.SetForegroundWindow(hwnd); - // If we cannot set the foreground window, we can use the foreground window and switch the layout - if (!result) hwnd = PInvoke.GetForegroundWindow(); - } - // Get the current foreground window thread ID var threadId = PInvoke.GetWindowThreadProcessId(hwnd); if (threadId == 0) throw new Win32Exception(Marshal.GetLastWin32Error()); diff --git a/Flow.Launcher.Plugin/Result.cs b/Flow.Launcher.Plugin/Result.cs index f561fcb1d..f0fcd48ff 100644 --- a/Flow.Launcher.Plugin/Result.cs +++ b/Flow.Launcher.Plugin/Result.cs @@ -128,12 +128,12 @@ namespace Flow.Launcher.Plugin /// /// Delegate to load an icon for this result. /// - public IconDelegate Icon { get; set; } + public IconDelegate Icon = null; /// /// Delegate to load an icon for the badge of this result. /// - public IconDelegate BadgeIcon { get; set; } + public IconDelegate BadgeIcon = null; /// /// Information for Glyph Icon (Prioritized than IcoPath/Icon if user enable Glyph Icons) diff --git a/Flow.Launcher/HotkeyControl.xaml.cs b/Flow.Launcher/HotkeyControl.xaml.cs index 8762a934b..262727127 100644 --- a/Flow.Launcher/HotkeyControl.xaml.cs +++ b/Flow.Launcher/HotkeyControl.xaml.cs @@ -1,6 +1,4 @@ -#nullable enable - -using System.Collections.ObjectModel; +using System.Collections.ObjectModel; using System.Threading.Tasks; using System.Windows; using System.Windows.Input; @@ -9,6 +7,8 @@ using Flow.Launcher.Helper; using Flow.Launcher.Infrastructure.Hotkey; using Flow.Launcher.Infrastructure.UserSettings; +#nullable enable + namespace Flow.Launcher { public partial class HotkeyControl @@ -242,7 +242,11 @@ namespace Flow.Launcher HotKeyMapper.RemoveHotkey(Hotkey); } - var dialog = new HotkeyControlDialog(Hotkey, DefaultHotkey, WindowTitle); + var dialog = new HotkeyControlDialog(Hotkey, DefaultHotkey, WindowTitle) + { + Owner = Window.GetWindow(this) + }; + await dialog.ShowAsync(); switch (dialog.ResultType) { diff --git a/Flow.Launcher/Msg.xaml.cs b/Flow.Launcher/Msg.xaml.cs index 110235cb5..923c3692f 100644 --- a/Flow.Launcher/Msg.xaml.cs +++ b/Flow.Launcher/Msg.xaml.cs @@ -59,6 +59,7 @@ namespace Flow.Launcher Close(); } + [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD100:Avoid async void methods", Justification = "")] public async void Show(string title, string subTitle, string iconPath) { tbTitle.Text = title; diff --git a/Flow.Launcher/ReportWindow.xaml.cs b/Flow.Launcher/ReportWindow.xaml.cs index 0ab785a17..24801cf52 100644 --- a/Flow.Launcher/ReportWindow.xaml.cs +++ b/Flow.Launcher/ReportWindow.xaml.cs @@ -15,8 +15,6 @@ namespace Flow.Launcher { internal partial class ReportWindow { - private static readonly string ClassName = nameof(ReportWindow); - public ReportWindow(Exception exception) { InitializeComponent(); diff --git a/Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginsViewModel.cs b/Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginsViewModel.cs index b89e970e9..de7cf15c3 100644 --- a/Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginsViewModel.cs +++ b/Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginsViewModel.cs @@ -5,7 +5,6 @@ using System.Windows.Controls; using System.Windows; using CommunityToolkit.Mvvm.Input; using Flow.Launcher.Core.Plugin; -using Flow.Launcher.Infrastructure; using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; using Flow.Launcher.ViewModel; @@ -112,10 +111,11 @@ public partial class SettingsPanePluginsViewModel : BaseModel .ToList(); [RelayCommand] - private async Task OpenHelperAsync() + private async Task OpenHelperAsync(Button button) { var helpDialog = new ContentDialog() { + Owner = Window.GetWindow(button), Content = new StackPanel { Children = @@ -146,7 +146,6 @@ public partial class SettingsPanePluginsViewModel : BaseModel } } }, - PrimaryButtonText = (string)Application.Current.Resources["commonOK"], CornerRadius = new CornerRadius(8), Style = (Style)Application.Current.Resources["ContentDialog"] diff --git a/Flow.Launcher/SettingPages/Views/SettingsPanePlugins.xaml b/Flow.Launcher/SettingPages/Views/SettingsPanePlugins.xaml index f9f708314..f3d630306 100644 --- a/Flow.Launcher/SettingPages/Views/SettingsPanePlugins.xaml +++ b/Flow.Launcher/SettingPages/Views/SettingsPanePlugins.xaml @@ -57,6 +57,7 @@ Height="34" Margin="0 0 20 0" Command="{Binding OpenHelperCommand}" + CommandParameter="{Binding RelativeSource={RelativeSource Self}}" Content="" FontFamily="{DynamicResource SymbolThemeFontFamily}" FontSize="14" /> diff --git a/Flow.Launcher/SettingPages/Views/SettingsPaneTheme.xaml.cs b/Flow.Launcher/SettingPages/Views/SettingsPaneTheme.xaml.cs index 22de4fcc0..f4c103ade 100644 --- a/Flow.Launcher/SettingPages/Views/SettingsPaneTheme.xaml.cs +++ b/Flow.Launcher/SettingPages/Views/SettingsPaneTheme.xaml.cs @@ -1,8 +1,8 @@ -using System.Windows.Navigation; +using System.Windows.Navigation; using CommunityToolkit.Mvvm.DependencyInjection; using Flow.Launcher.SettingPages.ViewModels; -using Page = ModernWpf.Controls.Page; using Flow.Launcher.Infrastructure.UserSettings; +using Page = ModernWpf.Controls.Page; namespace Flow.Launcher.SettingPages.Views; diff --git a/Flow.Launcher/ViewModel/RelayCommand.cs b/Flow.Launcher/ViewModel/RelayCommand.cs deleted file mode 100644 index e8d4af8b5..000000000 --- a/Flow.Launcher/ViewModel/RelayCommand.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using System.Windows.Input; - -namespace Flow.Launcher.ViewModel -{ - public class RelayCommand : ICommand - { - private readonly Action _action; - - public RelayCommand(Action action) - { - _action = action; - } - - public virtual bool CanExecute(object parameter) - { - return true; - } - -#pragma warning disable CS0067 // the event is never used - public event EventHandler CanExecuteChanged; -#pragma warning restore CS0067 - - public virtual void Execute(object parameter) - { - _action?.Invoke(parameter); - } - } -} diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj b/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj index 549217027..98164f489 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj @@ -45,6 +45,7 @@ + diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Helper/ShellContextMenu.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Helper/ShellContextMenu.cs index abb76580d..58b4e86f9 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Helper/ShellContextMenu.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Helper/ShellContextMenu.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Text; using System.Runtime.InteropServices; using System.Drawing; @@ -341,7 +341,7 @@ namespace Peter return null; } - IShellFolder oParentFolder = GetParentFolder(arrFI[0].Parent.FullName); + IShellFolder oParentFolder = GetParentFolder(arrFI[0].Parent!.FullName); if (null == oParentFolder) { return null; @@ -1535,7 +1535,7 @@ namespace Peter m_hookType, m_filterFunc, IntPtr.Zero, - (int)AppDomain.GetCurrentThreadId()); + Environment.CurrentManagedThreadId); } // ************************************************************************ diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Helper/SortOptionTranslationHelper.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Helper/SortOptionTranslationHelper.cs index 0a3a2ae43..72f58f5b6 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Helper/SortOptionTranslationHelper.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Helper/SortOptionTranslationHelper.cs @@ -16,7 +16,7 @@ public static class SortOptionTranslationHelper ArgumentNullException.ThrowIfNull(API); var enumName = Enum.GetName(sortOption); - var splited = enumName.Split('_'); + var splited = enumName!.Split('_'); var name = string.Join('_', splited[..^1]); var direction = splited[^1]; diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/EnvironmentVariables.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/EnvironmentVariables.cs index e526fb85a..6c4e6a3ed 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/EnvironmentVariables.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/EnvironmentVariables.cs @@ -47,7 +47,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search foreach (DictionaryEntry special in Environment.GetEnvironmentVariables()) { - var path = special.Value.ToString(); + var path = special.Value!.ToString(); // we add a trailing slash to the path to make sure drive paths become valid absolute paths. // for example, if %systemdrive% is C: we turn it to C:\ path = path.EnsureTrailingSlash(); @@ -61,7 +61,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search { // Variables are returned with a mixture of all upper/lower case. // Call ToUpper() to make the results look consistent - _envStringPaths.Add(special.Key.ToString().ToUpper(), path); + _envStringPaths.Add(special.Key.ToString()!.ToUpper(), path); } } } diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/ActionKeywordModel.cs b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/ActionKeywordModel.cs index 2f614ead8..d4cd1348e 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/ActionKeywordModel.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/ActionKeywordModel.cs @@ -1,13 +1,15 @@ using System.ComponentModel; using System.Runtime.CompilerServices; +#nullable enable + namespace Flow.Launcher.Plugin.Explorer.Views { public class ActionKeywordModel : INotifyPropertyChanged { - private static Settings _settings; + private static Settings _settings = null!; - public event PropertyChangedEventHandler PropertyChanged; + public event PropertyChangedEventHandler? PropertyChanged; public static void Init(Settings settings) { @@ -54,4 +56,4 @@ namespace Flow.Launcher.Plugin.Explorer.Views } } } -} \ No newline at end of file +} diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/RelayCommand.cs b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/RelayCommand.cs deleted file mode 100644 index ff704b679..000000000 --- a/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/RelayCommand.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using System.Windows.Input; - -namespace Flow.Launcher.Plugin.Explorer.ViewModels -{ - internal class RelayCommand : ICommand - { - private Action _action; - - public RelayCommand(Action action) - { - _action = action; - } - - public virtual bool CanExecute(object parameter) - { - return true; - } - - public event EventHandler CanExecuteChanged; - - public virtual void Execute(object parameter) - { - _action?.Invoke(parameter); - } - } -} diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs index 407300924..cf9ebd33f 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs @@ -1,9 +1,4 @@ #nullable enable -using Flow.Launcher.Plugin.Explorer.Search; -using Flow.Launcher.Plugin.Explorer.Search.Everything; -using Flow.Launcher.Plugin.Explorer.Search.Everything.Exceptions; -using Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks; -using Flow.Launcher.Plugin.Explorer.Views; using System; using System.Collections.Generic; using System.Diagnostics; @@ -13,11 +8,16 @@ using System.IO; using System.Linq; using System.Windows; using System.Windows.Forms; -using System.Windows.Input; +using CommunityToolkit.Mvvm.Input; +using Flow.Launcher.Plugin.Explorer.Search; +using Flow.Launcher.Plugin.Explorer.Search.Everything; +using Flow.Launcher.Plugin.Explorer.Search.Everything.Exceptions; +using Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks; +using Flow.Launcher.Plugin.Explorer.Views; namespace Flow.Launcher.Plugin.Explorer.ViewModels { - public class SettingsViewModel : BaseModel + public partial class SettingsViewModel : BaseModel { public Settings Settings { get; set; } @@ -36,7 +36,6 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels InitializeActionKeywordModels(); } - public void Save() { Context.API.SaveSettingJsonStorage(); @@ -48,7 +47,6 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels private EnumBindingModel _selectedContentSearchEngine; private EnumBindingModel _selectedPathEnumerationEngine; - public EnumBindingModel SelectedIndexSearchEngine { get => _selectedIndexSearchEngine; @@ -261,8 +259,7 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels public ActionKeywordModel? SelectedActionKeyword { get; set; } - public ICommand EditActionKeywordCommand => new RelayCommand(EditActionKeyword); - + [RelayCommand] private void EditActionKeyword(object obj) { if (SelectedActionKeyword is not { } actionKeyword) @@ -307,12 +304,6 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels public AccessLink? SelectedQuickAccessLink { get; set; } public AccessLink? SelectedIndexSearchExcludedPath { get; set; } - - - public ICommand RemoveLinkCommand => new RelayCommand(RemoveLink); - public ICommand EditLinkCommand => new RelayCommand(EditLink); - public ICommand AddLinkCommand => new RelayCommand(AddLink); - public void AppendLink(string containerName, AccessLink link) { var container = containerName switch @@ -324,6 +315,7 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels container.Add(link); } + [RelayCommand] private void EditLink(object commandParameter) { var (selectedLink, collection) = commandParameter switch @@ -360,7 +352,7 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels Context.API.ShowMsgBox(warning); } - + [RelayCommand] private void AddLink(object commandParameter) { var container = commandParameter switch @@ -385,6 +377,7 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels container.Add(newAccessLink); } + [RelayCommand] private void RemoveLink(object obj) { if (obj is not string container) return; @@ -435,7 +428,6 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels return path; } - internal static void OpenWindowsIndexingOptions() { var psi = new ProcessStartInfo @@ -448,39 +440,35 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels Process.Start(psi); } - private ICommand? _openFileEditorPathCommand; - - public ICommand OpenFileEditorPath => _openFileEditorPathCommand ??= new RelayCommand(_ => + [RelayCommand] + private void OpenFileEditorPath() { var path = PromptUserSelectPath(ResultType.File, Settings.EditorPath != null ? Path.GetDirectoryName(Settings.EditorPath) : null); if (path is null) return; FileEditorPath = path; - }); + } - private ICommand? _openFolderEditorPathCommand; - - public ICommand OpenFolderEditorPath => _openFolderEditorPathCommand ??= new RelayCommand(_ => + [RelayCommand] + private void OpenFolderEditorPath() { var path = PromptUserSelectPath(ResultType.File, Settings.FolderEditorPath != null ? Path.GetDirectoryName(Settings.FolderEditorPath) : null); if (path is null) return; FolderEditorPath = path; - }); + } - private ICommand? _openShellPathCommand; - - public ICommand OpenShellPath => _openShellPathCommand ??= new RelayCommand(_ => + [RelayCommand] + private void OpenShellPath() { var path = PromptUserSelectPath(ResultType.File, Settings.EditorPath != null ? Path.GetDirectoryName(Settings.EditorPath) : null); if (path is null) return; ShellPath = path; - }); - + } public string FileEditorPath { @@ -537,7 +525,6 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels } } - #region Everything FastSortWarning public Visibility FastSortWarningVisibility @@ -593,7 +580,5 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels } #endregion - - } } diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Views/ActionKeywordSetting.xaml.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Views/ActionKeywordSetting.xaml.cs index 73c35b1c8..000b2558d 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Views/ActionKeywordSetting.xaml.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Views/ActionKeywordSetting.xaml.cs @@ -85,6 +85,7 @@ namespace Flow.Launcher.Plugin.Explorer.Views DialogResult = false; Close(); } + private void TxtCurrentActionKeyword_OnKeyDown(object sender, KeyEventArgs e) { if (e.Key == Key.Enter) @@ -94,11 +95,13 @@ namespace Flow.Launcher.Plugin.Explorer.Views e.Handled = true; } } + public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } + private bool SetField(ref T field, T value, [CallerMemberName] string propertyName = null) { if (EqualityComparer.Default.Equals(field, value)) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml index 6ca7be84d..e5999da41 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml @@ -245,7 +245,7 @@ Margin="{StaticResource SettingPanelItemLeftMargin}" HorizontalAlignment="Left" VerticalAlignment="Center" - Command="{Binding OpenFileEditorPath}" + Command="{Binding OpenFileEditorPathCommand}" Content="{DynamicResource select}" /> @@ -272,7 +272,7 @@ Margin="{StaticResource SettingPanelItemLeftMargin}" HorizontalAlignment="Left" VerticalAlignment="Center" - Command="{Binding OpenFolderEditorPath}" + Command="{Binding OpenFolderEditorPathCommand}" Content="{DynamicResource select}" /> @@ -299,7 +299,7 @@ Margin="{StaticResource SettingPanelItemLeftMargin}" HorizontalAlignment="Left" VerticalAlignment="Center" - Command="{Binding OpenShellPath}" + Command="{Binding OpenShellPathCommand}" Content="{DynamicResource select}" /> diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml.cs index b7f5efc3c..9203ece9a 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml.cs @@ -1,11 +1,10 @@ -using Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks; -using Flow.Launcher.Plugin.Explorer.ViewModels; -using System.Collections.Generic; -using System.ComponentModel; +using System.ComponentModel; using System.IO; using System.Linq; using System.Windows; using System.Windows.Controls; +using Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks; +using Flow.Launcher.Plugin.Explorer.ViewModels; using DataFormats = System.Windows.DataFormats; using DragDropEffects = System.Windows.DragDropEffects; using DragEventArgs = System.Windows.DragEventArgs; @@ -19,9 +18,6 @@ namespace Flow.Launcher.Plugin.Explorer.Views { private readonly SettingsViewModel viewModel; - private List actionKeywordsListView; - - public ExplorerSettings(SettingsViewModel viewModel) { DataContext = viewModel; @@ -39,8 +35,6 @@ namespace Flow.Launcher.Plugin.Explorer.Views lbxExcludedPaths.Items.SortDescriptions.Add(new SortDescription("Path", ListSortDirection.Ascending)); } - - private void AccessLinkDragDrop(string containerName, DragEventArgs e) { var files = (string[])e.Data.GetData(DataFormats.FileDrop); diff --git a/Plugins/Flow.Launcher.Plugin.ProcessKiller/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.ProcessKiller/Languages/en.xaml index ea6e54fef..ddabd31f8 100644 --- a/Plugins/Flow.Launcher.Plugin.ProcessKiller/Languages/en.xaml +++ b/Plugins/Flow.Launcher.Plugin.ProcessKiller/Languages/en.xaml @@ -10,6 +10,7 @@ kill {0} processes kill all instances + Show title for processes with visible windows Put processes with visible windows on the top \ No newline at end of file diff --git a/Plugins/Flow.Launcher.Plugin.ProcessKiller/Main.cs b/Plugins/Flow.Launcher.Plugin.ProcessKiller/Main.cs index 4f5d1becd..8f5ba4bd2 100644 --- a/Plugins/Flow.Launcher.Plugin.ProcessKiller/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.ProcessKiller/Main.cs @@ -81,7 +81,10 @@ namespace Flow.Launcher.Plugin.ProcessKiller // Filter processes based on search term var searchTerm = query.Search; var processlist = new List(); - var processWindowTitle = ProcessHelper.GetProcessesWithNonEmptyWindowTitle(); + var processWindowTitle = + Settings.ShowWindowTitle || Settings.PutVisibleWindowProcessesTop ? + ProcessHelper.GetProcessesWithNonEmptyWindowTitle() : + new Dictionary(); if (string.IsNullOrWhiteSpace(searchTerm)) { foreach (var p in allPocessList) @@ -91,12 +94,22 @@ namespace Flow.Launcher.Plugin.ProcessKiller if (processWindowTitle.TryGetValue(p.Id, out var windowTitle)) { // Add score to prioritize processes with visible windows - // And use window title for those processes - processlist.Add(new ProcessResult(p, Settings.PutVisibleWindowProcessesTop ? 200 : 0, windowTitle, null, progressNameIdTitle)); + // Use window title for those processes if enabled + processlist.Add(new ProcessResult( + p, + Settings.PutVisibleWindowProcessesTop ? 200 : 0, + Settings.ShowWindowTitle ? windowTitle : progressNameIdTitle, + null, + progressNameIdTitle)); } else { - processlist.Add(new ProcessResult(p, 0, progressNameIdTitle, null, progressNameIdTitle)); + processlist.Add(new ProcessResult( + p, + 0, + progressNameIdTitle, + null, + progressNameIdTitle)); } } } @@ -115,13 +128,17 @@ namespace Flow.Launcher.Plugin.ProcessKiller if (score > 0) { // Add score to prioritize processes with visible windows - // And use window title for those processes + // Use window title for those processes if (Settings.PutVisibleWindowProcessesTop) { score += 200; } - processlist.Add(new ProcessResult(p, score, windowTitle, - score == windowTitleMatch.Score ? windowTitleMatch : null, progressNameIdTitle)); + processlist.Add(new ProcessResult( + p, + score, + Settings.ShowWindowTitle ? windowTitle : progressNameIdTitle, + score == windowTitleMatch.Score ? windowTitleMatch : null, + progressNameIdTitle)); } } else @@ -130,7 +147,12 @@ namespace Flow.Launcher.Plugin.ProcessKiller var score = processNameIdMatch.Score; if (score > 0) { - processlist.Add(new ProcessResult(p, score, progressNameIdTitle, processNameIdMatch, progressNameIdTitle)); + processlist.Add(new ProcessResult( + p, + score, + progressNameIdTitle, + processNameIdMatch, + progressNameIdTitle)); } } } diff --git a/Plugins/Flow.Launcher.Plugin.ProcessKiller/ProcessHelper.cs b/Plugins/Flow.Launcher.Plugin.ProcessKiller/ProcessHelper.cs index d7f44ccce..386782905 100644 --- a/Plugins/Flow.Launcher.Plugin.ProcessKiller/ProcessHelper.cs +++ b/Plugins/Flow.Launcher.Plugin.ProcessKiller/ProcessHelper.cs @@ -1,9 +1,11 @@ -using Microsoft.Win32.SafeHandles; -using System; +using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; +using System.Threading.Tasks; +using Microsoft.Win32.SafeHandles; using Windows.Win32; using Windows.Win32.Foundation; using Windows.Win32.System.Threading; @@ -72,8 +74,21 @@ namespace Flow.Launcher.Plugin.ProcessKiller /// public static unsafe Dictionary GetProcessesWithNonEmptyWindowTitle() { - var processDict = new Dictionary(); + // Collect all window handles + var windowHandles = new List(); PInvoke.EnumWindows((hWnd, _) => + { + if (PInvoke.IsWindowVisible(hWnd)) + { + windowHandles.Add(hWnd); + } + return true; + }, IntPtr.Zero); + + // Concurrently process each window handle + var processDict = new ConcurrentDictionary(); + var processedProcessIds = new ConcurrentDictionary(); + Parallel.ForEach(windowHandles, hWnd => { var windowTitle = GetWindowTitle(hWnd); if (!string.IsNullOrWhiteSpace(windowTitle) && PInvoke.IsWindowVisible(hWnd)) @@ -82,20 +97,26 @@ namespace Flow.Launcher.Plugin.ProcessKiller var result = PInvoke.GetWindowThreadProcessId(hWnd, &processId); if (result == 0u || processId == 0u) { - return false; + return; } - var process = Process.GetProcessById((int)processId); - if (!processDict.ContainsKey((int)processId)) + // Ensure each process ID is processed only once + if (processedProcessIds.TryAdd((int)processId, 0)) { - processDict.Add((int)processId, windowTitle); + try + { + var process = Process.GetProcessById((int)processId); + processDict.TryAdd((int)processId, windowTitle); + } + catch + { + // Handle exceptions (e.g., process exited) + } } } + }); - return true; - }, IntPtr.Zero); - - return processDict; + return new Dictionary(processDict); } private static unsafe string GetWindowTitle(HWND hwnd) diff --git a/Plugins/Flow.Launcher.Plugin.ProcessKiller/Settings.cs b/Plugins/Flow.Launcher.Plugin.ProcessKiller/Settings.cs index 916bc6a39..57cd2ab86 100644 --- a/Plugins/Flow.Launcher.Plugin.ProcessKiller/Settings.cs +++ b/Plugins/Flow.Launcher.Plugin.ProcessKiller/Settings.cs @@ -2,6 +2,8 @@ { public class Settings { + public bool ShowWindowTitle { get; set; } = true; + public bool PutVisibleWindowProcessesTop { get; set; } = false; } } diff --git a/Plugins/Flow.Launcher.Plugin.ProcessKiller/ViewModels/SettingsViewModel.cs b/Plugins/Flow.Launcher.Plugin.ProcessKiller/ViewModels/SettingsViewModel.cs index bacf1ba08..0728d9c0f 100644 --- a/Plugins/Flow.Launcher.Plugin.ProcessKiller/ViewModels/SettingsViewModel.cs +++ b/Plugins/Flow.Launcher.Plugin.ProcessKiller/ViewModels/SettingsViewModel.cs @@ -9,6 +9,12 @@ Settings = settings; } + public bool ShowWindowTitle + { + get => Settings.ShowWindowTitle; + set => Settings.ShowWindowTitle = value; + } + public bool PutVisibleWindowProcessesTop { get => Settings.PutVisibleWindowProcessesTop; diff --git a/Plugins/Flow.Launcher.Plugin.ProcessKiller/Views/SettingsControl.xaml b/Plugins/Flow.Launcher.Plugin.ProcessKiller/Views/SettingsControl.xaml index d15d6c3e0..b969be4e8 100644 --- a/Plugins/Flow.Launcher.Plugin.ProcessKiller/Views/SettingsControl.xaml +++ b/Plugins/Flow.Launcher.Plugin.ProcessKiller/Views/SettingsControl.xaml @@ -12,10 +12,16 @@ + + diff --git a/Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml.cs b/Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml.cs index c42bd4f30..deb110698 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml.cs @@ -146,6 +146,7 @@ namespace Flow.Launcher.Plugin.Program.Views programSourceView.Items.Refresh(); } + [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD100:Avoid async void methods", Justification = "")] private async void ReIndexing() { ViewRefresh(); @@ -183,6 +184,7 @@ namespace Flow.Launcher.Plugin.Program.Views EditProgramSource(selectedProgramSource); } + [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD100:Avoid async void methods", Justification = "")] private async void EditProgramSource(ProgramSource selectedProgramSource) { if (selectedProgramSource == null) @@ -277,6 +279,7 @@ namespace Flow.Launcher.Plugin.Program.Views } } + [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD100:Avoid async void methods", Justification = "")] private async void btnLoadAllProgramSource_OnClick(object sender, RoutedEventArgs e) { await ProgramSettingDisplay.DisplayAllProgramsAsync(); @@ -284,6 +287,7 @@ namespace Flow.Launcher.Plugin.Program.Views ViewRefresh(); } + [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD100:Avoid async void methods", Justification = "")] private async void btnProgramSourceStatus_OnClick(object sender, RoutedEventArgs e) { var selectedItems = programSourceView diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs index 043eb7a19..39bf49654 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs @@ -362,6 +362,7 @@ namespace Flow.Launcher.Plugin.Sys Glyph = new GlyphInfo (FontFamily:"/Resources/#Segoe Fluent Icons", Glyph:"\xe89f"), Action = c => { + _context.API.HideMainWindow(); Application.Current.MainWindow.Close(); return true; } diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SearchSourceSetting.xaml.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SearchSourceSetting.xaml.cs index 58577dbc1..b44f130e4 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/SearchSourceSetting.xaml.cs +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SearchSourceSetting.xaml.cs @@ -28,6 +28,7 @@ namespace Flow.Launcher.Plugin.WebSearch Initialize(sources, context, Action.Add); } + [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD100:Avoid async void methods", Justification = "")] private async void Initialize(IList sources, PluginInitContext context, Action action) { InitializeComponent(); @@ -124,6 +125,7 @@ namespace Flow.Launcher.Plugin.WebSearch } } + [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD100:Avoid async void methods", Justification = "")] private async void OnSelectIconClick(object sender, RoutedEventArgs e) { const string filter = "Image files (*.jpg, *.jpeg, *.gif, *.png, *.bmp) |*.jpg; *.jpeg; *.gif; *.png; *.bmp"; diff --git a/README.md b/README.md index cbb553bd1..d8ecfa671 100644 --- a/README.md +++ b/README.md @@ -351,6 +351,7 @@ Or download the [early access version](https://github.com/Flow-Launcher/Prerelea

+