From 76f7dd3b09f7ae42eac2f310ffa84dc7541a108c Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Mon, 27 Oct 2025 10:57:09 -0500 Subject: [PATCH] don't flicker the windows so much bub --- .../Dock/DockViewModel.cs | 10 ----- .../Components/Window.cs | 25 ++++++++++-- .../Helpers/SettingsManager.cs | 9 +++++ .../Pages/WindowWalkerListPage.cs | 38 ++++++++++++++++--- .../Properties/Resources.Designer.cs | 20 +++++++++- .../Properties/Resources.resx | 6 +++ .../WindowWalkerCommandsProvider.cs | 19 +--------- .../WindowWalkerListItem.cs | 25 +++++++++--- 8 files changed, 108 insertions(+), 44 deletions(-) diff --git a/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/Dock/DockViewModel.cs b/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/Dock/DockViewModel.cs index e84509c306..d0622b4cec 100644 --- a/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/Dock/DockViewModel.cs +++ b/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/Dock/DockViewModel.cs @@ -46,16 +46,6 @@ public sealed partial class DockViewModel : IDisposable, SetupBands(); } - // private static string[] _startCommands = [ - // "com.microsoft.cmdpal.windowwalker.dockband", - // ]; - - // private static string[] _endCommands = [ - // "com.crloewen.performanceMonitor.dockband", - // "com.microsoft.cmdpal.clipboardHistory.Band", - // "com.zadjii.virtualDesktops.band", - // "com.microsoft.cmdpal.timedate.dockband", - // ]; private void SetupBands() { Logger.LogDebug($"Setting up dock bands"); diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.WindowWalker/Components/Window.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.WindowWalker/Components/Window.cs index c071d55e80..95c8a9b9b0 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.WindowWalker/Components/Window.cs +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.WindowWalker/Components/Window.cs @@ -51,7 +51,7 @@ internal sealed class Window var sizeOfTitle = NativeMethods.GetWindowTextLength(hwnd); if (sizeOfTitle++ > 0) { - StringBuilder titleBuffer = new StringBuilder(sizeOfTitle); + var titleBuffer = new StringBuilder(sizeOfTitle); var numCharactersWritten = NativeMethods.GetWindowText(hwnd, titleBuffer, sizeOfTitle); if (numCharactersWritten == 0) { @@ -260,7 +260,7 @@ internal sealed class Window /// The state (minimized, maximized, etc..) of the window internal WindowSizeState GetWindowSizeState() { - NativeMethods.GetWindowPlacement(Hwnd, out WINDOWPLACEMENT placement); + NativeMethods.GetWindowPlacement(Hwnd, out var placement); switch (placement.ShowCmd) { @@ -332,7 +332,7 @@ internal sealed class Window /// Class name private static string GetWindowClassName(IntPtr hwnd) { - StringBuilder windowClassName = new StringBuilder(300); + var windowClassName = new StringBuilder(300); var numCharactersWritten = NativeMethods.GetClassName(hwnd, windowClassName, windowClassName.MaxCapacity); if (numCharactersWritten == 0) @@ -384,7 +384,7 @@ internal sealed class Window { new Task(() => { - EnumWindowsProc callbackptr = new EnumWindowsProc((IntPtr hwnd, IntPtr lParam) => + var callbackptr = new EnumWindowsProc((IntPtr hwnd, IntPtr lParam) => { // Every uwp app main window has at least three child windows. Only the one we are interested in has a class starting with "Windows.UI.Core." and is assigned to the real app process. // (The other ones have a class name that begins with the string "ApplicationFrame".) @@ -410,4 +410,21 @@ internal sealed class Window return _handlesToProcessCache[hWindow]; } } + + public override bool Equals(object? obj) + { + if (obj is Window other) + { + return this.hwnd == other.hwnd && + this.Title == other.Title && + this.Visible == other.Visible; + } + + return base.Equals(obj); + } + + public override int GetHashCode() + { + return base.GetHashCode(); + } } diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.WindowWalker/Helpers/SettingsManager.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.WindowWalker/Helpers/SettingsManager.cs index ce0f57b975..bb1624d8aa 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.WindowWalker/Helpers/SettingsManager.cs +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.WindowWalker/Helpers/SettingsManager.cs @@ -76,6 +76,12 @@ public class SettingsManager : JsonSettingsManager, ISettingsInterface Resources.windowwalker_SettingUseWindowIcon_Description, true); + private readonly ToggleSetting _showTitlesOnDock = new( + Namespaced(nameof(ShowTitlesOnDock)), + Resources.windowwalker_SettingShowTitlesOnDock, + Resources.windowwalker_SettingShowTitlesOnDock_Description, + true); + public bool ResultsFromVisibleDesktopOnly { get => _resultsFromVisibleDesktopOnly.Value; set => _resultsFromVisibleDesktopOnly.Value = value; } public bool SubtitleShowPid => _subtitleShowPid.Value; @@ -98,6 +104,8 @@ public class SettingsManager : JsonSettingsManager, ISettingsInterface public bool ShowSubtitles { get; set; } = true; + public bool ShowTitlesOnDock { get => _showTitlesOnDock.Value; set => _showTitlesOnDock.Value = value; } + internal static string SettingsJsonPath() { var directory = Utilities.BaseSettingsPath("Microsoft.CmdPal"); @@ -121,6 +129,7 @@ public class SettingsManager : JsonSettingsManager, ISettingsInterface Settings.Add(_hideExplorerSettingInfo); Settings.Add(_inMruOrder); Settings.Add(_useWindowIcon); + Settings.Add(_showTitlesOnDock); // Load settings from file upon initialization LoadSettings(); diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.WindowWalker/Pages/WindowWalkerListPage.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.WindowWalker/Pages/WindowWalkerListPage.cs index 416ae70380..201caf0ee7 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.WindowWalker/Pages/WindowWalkerListPage.cs +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.WindowWalker/Pages/WindowWalkerListPage.cs @@ -9,14 +9,17 @@ using Microsoft.CmdPal.Ext.WindowWalker.Helpers; using Microsoft.CmdPal.Ext.WindowWalker.Properties; using Microsoft.CommandPalette.Extensions; using Microsoft.CommandPalette.Extensions.Toolkit; +using Microsoft.UI.Dispatching; namespace Microsoft.CmdPal.Ext.WindowWalker.Pages; internal sealed partial class WindowWalkerListPage : DynamicListPage, IDisposable { + private readonly List _results = new(); private readonly SettingsManager _settingsManager; private readonly SearchController _searchController; private System.Threading.CancellationTokenSource _cancellationTokenSource = new(); + private DispatcherQueue _updateWindowsQueue = DispatcherQueueController.CreateOnDedicatedThread().DispatcherQueue; private bool _disposed; @@ -36,12 +39,20 @@ internal sealed partial class WindowWalkerListPage : DynamicListPage, IDisposabl Title = Resources.window_walker_top_level_command_title, Subtitle = Resources.windowwalker_NoResultsMessage, }; + + Query(string.Empty); } - public override void UpdateSearchText(string oldSearch, string newSearch) => - RaiseItemsChanged(0); + public override void UpdateSearchText(string oldSearch, string newSearch) + { + _updateWindowsQueue.TryEnqueue(() => + { + Query(newSearch); + }); + } - public List Query(string query) + // public List Query(string query) + public void Query(string query) { ArgumentNullException.ThrowIfNull(query); @@ -54,10 +65,24 @@ internal sealed partial class WindowWalkerListPage : DynamicListPage, IDisposabl _searchController.UpdateSearchText(query); var searchControllerResults = _searchController.SearchMatches; - return ResultHelper.GetResultList(searchControllerResults, !string.IsNullOrEmpty(query), _settingsManager); + var newListItems = ResultHelper.GetResultList(searchControllerResults, !string.IsNullOrEmpty(query), _settingsManager); + var oldCount = _results.Count; + var newCount = newListItems.Count; + ListHelpers.InPlaceUpdateList(_results, newListItems, out var removedItems); + if (newCount == oldCount && removedItems.Count == 0) + { + // do nothing - windows didn't change + } + else + { + RaiseItemsChanged(_results.Count); + } } - public override IListItem[] GetItems() => Query(SearchText).ToArray(); + public override IListItem[] GetItems() + { + return _results.ToArray(); + } public void Dispose() { @@ -79,6 +104,7 @@ internal sealed partial class WindowWalkerListPage : DynamicListPage, IDisposabl internal void RaiseItemsChanged() { - base.RaiseItemsChanged(); + // base.RaiseItemsChanged(); + Query(SearchText); } } diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.WindowWalker/Properties/Resources.Designer.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.WindowWalker/Properties/Resources.Designer.cs index 1a8c5106d4..19fd700c20 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.WindowWalker/Properties/Resources.Designer.cs +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.WindowWalker/Properties/Resources.Designer.cs @@ -19,7 +19,7 @@ namespace Microsoft.CmdPal.Ext.WindowWalker.Properties { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "18.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class Resources { @@ -375,6 +375,24 @@ namespace Microsoft.CmdPal.Ext.WindowWalker.Properties { } } + /// + /// Looks up a localized string similar to Dock: Show window titles. + /// + public static string windowwalker_SettingShowTitlesOnDock { + get { + return ResourceManager.GetString("windowwalker_SettingShowTitlesOnDock", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Show the window titles on windows in the dock. + /// + public static string windowwalker_SettingShowTitlesOnDock_Description { + get { + return ResourceManager.GetString("windowwalker_SettingShowTitlesOnDock_Description", resourceCulture); + } + } + /// /// Looks up a localized string similar to This information is only shown in subtitle and tool tip, if you have at least two desktops.. /// diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.WindowWalker/Properties/Resources.resx b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.WindowWalker/Properties/Resources.resx index 3d61936a1d..c38e138d61 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.WindowWalker/Properties/Resources.resx +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.WindowWalker/Properties/Resources.resx @@ -241,4 +241,10 @@ Show the actual window icon instead of the process icon + + Dock: Show window titles + + + Show the window titles on windows in the dock + \ No newline at end of file diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.WindowWalker/WindowWalkerCommandsProvider.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.WindowWalker/WindowWalkerCommandsProvider.cs index dd6fd93d02..9ad0a5eea1 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.WindowWalker/WindowWalkerCommandsProvider.cs +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.WindowWalker/WindowWalkerCommandsProvider.cs @@ -41,24 +41,6 @@ public partial class WindowWalkerCommandsProvider : CommandProvider, IExtendedAt ], }; _bandItem = new WindowsDockBand(); - - // var testSettings = new SettingsManager(); - // testSettings.HideExplorerSettingInfo = true; - // testSettings.InMruOrder = false; - // testSettings.ResultsFromVisibleDesktopOnly = true; - // testSettings.UseWindowIcon = true; - // testSettings.ShowSubtitles = false; - // var testPage = new WindowWalkerListPage(testSettings); - // testPage.Id = "com.microsoft.cmdpal.windowwalker.dockband"; - - // _bandItem = new CommandItem(testPage) - // { - // Title = Resources.window_walker_top_level_command_title, - // Subtitle = Resources.windowwalker_name, - // MoreCommands = [ - // new CommandContextItem(Settings.SettingsPage), - // ], - // }; } public override ICommandItem[] TopLevelCommands() => [_windowWalkerPageItem]; @@ -91,6 +73,7 @@ internal sealed partial class WindowsDockBand : CommandItem testSettings.ResultsFromVisibleDesktopOnly = true; testSettings.UseWindowIcon = true; testSettings.ShowSubtitles = false; + testSettings.ShowTitlesOnDock = SettingsManager.Instance.ShowTitlesOnDock; var testPage = new WindowWalkerListPage(testSettings); testPage.Id = "com.microsoft.cmdpal.windowwalker.dockband"; _page = testPage; diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.WindowWalker/WindowWalkerListItem.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.WindowWalker/WindowWalkerListItem.cs index 72e648387e..e99231692e 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.WindowWalker/WindowWalkerListItem.cs +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.WindowWalker/WindowWalkerListItem.cs @@ -2,11 +2,6 @@ // The Microsoft Corporation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Microsoft.CmdPal.Ext.WindowWalker.Commands; using Microsoft.CmdPal.Ext.WindowWalker.Components; using Microsoft.CommandPalette.Extensions.Toolkit; @@ -24,4 +19,24 @@ internal sealed partial class WindowWalkerListItem : ListItem { _window = window; } + + public override bool Equals(object? obj) + { + if (obj is WindowWalkerListItem other) + { + if (this._window is null) + { + return other._window is null; + } + + return this._window.Equals(other._window); + } + + return base.Equals(obj); + } + + public override int GetHashCode() + { + return base.GetHashCode(); + } }