diff --git a/Flow.Launcher.Plugin/Result.cs b/Flow.Launcher.Plugin/Result.cs
index f561fcb1dcf..f0fcd48ffc0 100644
--- a/Flow.Launcher.Plugin/Result.cs
+++ b/Flow.Launcher.Plugin/Result.cs
@@ -128,12 +128,12 @@ public string BadgeIcoPath
///
/// 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/Plugins/Flow.Launcher.Plugin.ProcessKiller/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.ProcessKiller/Languages/en.xaml
index ea6e54fef7a..ddabd31f8fd 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 4f5d1becdd9..8f5ba4bd237 100644
--- a/Plugins/Flow.Launcher.Plugin.ProcessKiller/Main.cs
+++ b/Plugins/Flow.Launcher.Plugin.ProcessKiller/Main.cs
@@ -81,7 +81,10 @@ private List CreateResultsFromQuery(Query query)
// 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 @@ private List CreateResultsFromQuery(Query query)
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 @@ private List CreateResultsFromQuery(Query query)
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 @@ private List CreateResultsFromQuery(Query query)
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 d7f44ccce51..3867829058f 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 @@ public List GetMatchingProcesses()
///
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 @@ public static unsafe Dictionary GetProcessesWithNonEmptyWindowTitle
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 916bc6a3979..57cd2ab8697 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 bacf1ba08c9..0728d9c0fb5 100644
--- a/Plugins/Flow.Launcher.Plugin.ProcessKiller/ViewModels/SettingsViewModel.cs
+++ b/Plugins/Flow.Launcher.Plugin.ProcessKiller/ViewModels/SettingsViewModel.cs
@@ -9,6 +9,12 @@ public SettingsViewModel(Settings settings)
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 d15d6c3e084..b969be4e877 100644
--- a/Plugins/Flow.Launcher.Plugin.ProcessKiller/Views/SettingsControl.xaml
+++ b/Plugins/Flow.Launcher.Plugin.ProcessKiller/Views/SettingsControl.xaml
@@ -12,10 +12,16 @@
+
+