diff --git a/.github/actions/spell-check/allow/code.txt b/.github/actions/spell-check/allow/code.txt index fee0314208..47b300cb87 100644 --- a/.github/actions/spell-check/allow/code.txt +++ b/.github/actions/spell-check/allow/code.txt @@ -325,6 +325,14 @@ REGSTR # Misc Win32 APIs and PInvokes INVOKEIDLIST MEMORYSTATUSEX +ABE +HTCAPTION +POSCHANGED +QUERYPOS +SETAUTOHIDEBAR +WINDOWPOS +WINEVENTPROC +WORKERW # PowerRename metadata pattern abbreviations (used in tests and regex patterns) DDDD @@ -349,3 +357,6 @@ nostdin # Performance counter keys engtype Nonpaged + +# XAML +Untargeted \ No newline at end of file diff --git a/src/modules/cmdpal/CommandPalette.slnf b/src/modules/cmdpal/CommandPalette.slnf index decc56060f..e21c1c3c38 100644 --- a/src/modules/cmdpal/CommandPalette.slnf +++ b/src/modules/cmdpal/CommandPalette.slnf @@ -37,6 +37,7 @@ "src\\modules\\cmdpal\\ext\\Microsoft.CmdPal.Ext.Calc\\Microsoft.CmdPal.Ext.Calc.csproj", "src\\modules\\cmdpal\\ext\\Microsoft.CmdPal.Ext.ClipboardHistory\\Microsoft.CmdPal.Ext.ClipboardHistory.csproj", "src\\modules\\cmdpal\\ext\\Microsoft.CmdPal.Ext.Indexer\\Microsoft.CmdPal.Ext.Indexer.csproj", + "src\\modules\\cmdpal\\ext\\Microsoft.CmdPal.Ext.PerformanceMonitor\\Microsoft.CmdPal.Ext.PerformanceMonitor.csproj", "src\\modules\\cmdpal\\ext\\Microsoft.CmdPal.Ext.Registry\\Microsoft.CmdPal.Ext.Registry.csproj", "src\\modules\\cmdpal\\ext\\Microsoft.CmdPal.Ext.RemoteDesktop\\Microsoft.CmdPal.Ext.RemoteDesktop.csproj", "src\\modules\\cmdpal\\ext\\Microsoft.CmdPal.Ext.Shell\\Microsoft.CmdPal.Ext.Shell.csproj", diff --git a/src/modules/cmdpal/Core/Microsoft.CmdPal.Core.ViewModels/NullPageViewModel.cs b/src/modules/cmdpal/Core/Microsoft.CmdPal.Core.ViewModels/NullPageViewModel.cs index 504eef6af1..73e063b8ff 100644 --- a/src/modules/cmdpal/Core/Microsoft.CmdPal.Core.ViewModels/NullPageViewModel.cs +++ b/src/modules/cmdpal/Core/Microsoft.CmdPal.Core.ViewModels/NullPageViewModel.cs @@ -4,5 +4,11 @@ namespace Microsoft.CmdPal.Core.ViewModels; -internal sealed partial class NullPageViewModel(TaskScheduler scheduler, AppExtensionHost extensionHost) - : PageViewModel(null, scheduler, extensionHost); +internal sealed partial class NullPageViewModel : PageViewModel +{ + internal NullPageViewModel(TaskScheduler scheduler, AppExtensionHost extensionHost) + : base(null, scheduler, extensionHost) + { + HasBackButton = false; + } +} diff --git a/src/modules/cmdpal/Core/Microsoft.CmdPal.Core.ViewModels/ShellViewModel.cs b/src/modules/cmdpal/Core/Microsoft.CmdPal.Core.ViewModels/ShellViewModel.cs index ac0c62822b..46bbbf4482 100644 --- a/src/modules/cmdpal/Core/Microsoft.CmdPal.Core.ViewModels/ShellViewModel.cs +++ b/src/modules/cmdpal/Core/Microsoft.CmdPal.Core.ViewModels/ShellViewModel.cs @@ -98,7 +98,6 @@ public partial class ShellViewModel : ObservableObject, _appHostService = appHostService; NullPage = new NullPageViewModel(_scheduler, appHostService.GetDefaultHost()); - NullPage.HasBackButton = false; _currentPage = new LoadingPageViewModel(null, _scheduler, appHostService.GetDefaultHost()); // Register to receive messages @@ -278,9 +277,9 @@ public partial class ShellViewModel : ObservableObject, // Telemetry: Track extension page navigation for session metrics if (host is not null) { - string extensionId = host.GetExtensionDisplayName() ?? "builtin"; - string commandId = command?.Id ?? "unknown"; - string commandName = command?.Name ?? "unknown"; + var extensionId = host.GetExtensionDisplayName() ?? "builtin"; + var commandId = command?.Id ?? "unknown"; + var commandName = command?.Name ?? "unknown"; WeakReferenceMessenger.Default.Send( new(extensionId, commandId, commandName, true, 0)); } @@ -361,10 +360,10 @@ public partial class ShellViewModel : ObservableObject, // Telemetry: Track command execution time and success var stopwatch = System.Diagnostics.Stopwatch.StartNew(); var command = message.Command.Unsafe; - string extensionId = host?.GetExtensionDisplayName() ?? "builtin"; - string commandId = command?.Id ?? "unknown"; - string commandName = command?.Name ?? "unknown"; - bool success = false; + var extensionId = host?.GetExtensionDisplayName() ?? "builtin"; + var commandId = command?.Id ?? "unknown"; + var commandName = command?.Name ?? "unknown"; + var success = false; try { diff --git a/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/Dock/DockBandViewModel.cs b/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/Dock/DockBandViewModel.cs index f88c661894..0d4fbc7f16 100644 --- a/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/Dock/DockBandViewModel.cs +++ b/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/Dock/DockBandViewModel.cs @@ -151,12 +151,16 @@ public sealed partial class DockBandViewModel : ExtensionObjectViewModel newViewModels.Add(newItemVm); } + List removed = new(); DoOnUiThread(() => { - ListHelpers.InPlaceUpdateList(Items, newViewModels, out var removed); + ListHelpers.InPlaceUpdateList(Items, newViewModels, out removed); }); - // TODO! dispose removed VMs + foreach (var removedItem in removed) + { + removedItem.SafeCleanup(); + } } public override void InitializeProperties() @@ -186,6 +190,22 @@ public sealed partial class DockBandViewModel : ExtensionObjectViewModel InitializeFromList(p); } } + + protected override void UnsafeCleanup() + { + base.UnsafeCleanup(); + + var command = _rootItem.Command; + if (command.Model.Unsafe is IListPage list) + { + list.ItemsChanged -= HandleItemsChanged; + } + + foreach (var item in Items) + { + item.SafeCleanup(); + } + } } public partial class DockItemViewModel : CommandItemViewModel 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 e1643fc59e..ef20f70b47 100644 --- a/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/Dock/DockViewModel.cs +++ b/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/Dock/DockViewModel.cs @@ -58,6 +58,12 @@ public sealed partial class DockViewModel : IDisposable, SetupBands(_settings.StartBands, StartItems); SetupBands(_settings.CenterBands, CenterItems); SetupBands(_settings.EndBands, EndItems); + + // Initialize properties on BG thread + Task.Run(() => + { + InitializeAllBands(); + }); } private void SetupBands( @@ -77,6 +83,9 @@ public sealed partial class DockViewModel : IDisposable, if (topLevelCommand is not null) { + // note: CreateBandItem doesn't actually initialize the band, it + // just creates the VM. Callers need to make sure to call + // InitializeProperties() on a BG thread elsewhere var bandVm = CreateBandItem(band, topLevelCommand.ItemViewModel); newBands.Add(bandVm); } @@ -96,6 +105,7 @@ public sealed partial class DockViewModel : IDisposable, public void Dispose() { + WeakReferenceMessenger.Default.Unregister(this); } public void Receive(CommandsReloadedMessage message) @@ -515,6 +525,11 @@ public sealed partial class DockViewModel : IDisposable, // Snapshot the new band so it can be removed on discard bandVm.SnapshotShowLabels(); + Task.Run(() => + { + bandVm.SafeInitializePropertiesSynchronous(); + }); + Logger.LogDebug($"Added band {bandId} to {targetSide} (not saved yet)"); } @@ -597,6 +612,24 @@ public sealed partial class DockViewModel : IDisposable, }; } } + + private void InitializeAllBands() + { + foreach (var band in StartItems) + { + band.SafeInitializePropertiesSynchronous(); + } + + foreach (var band in CenterItems) + { + band.SafeInitializePropertiesSynchronous(); + } + + foreach (var band in EndItems) + { + band.SafeInitializePropertiesSynchronous(); + } + } } #pragma warning restore SA1402 // File may only contain a single type diff --git a/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/Properties/Resources.resx b/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/Properties/Resources.resx index 31b2dd2dd8..d670e48a6b 100644 --- a/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/Properties/Resources.resx +++ b/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/Properties/Resources.resx @@ -291,5 +291,5 @@ Dock settings Command name for opening dock settings - + \ No newline at end of file diff --git a/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/Settings/DockSettings.cs b/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/Settings/DockSettings.cs index 1c36b16ff1..8d19250471 100644 --- a/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/Settings/DockSettings.cs +++ b/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/Settings/DockSettings.cs @@ -21,7 +21,7 @@ public class DockSettings public DockSize DockIconsSize { get; set; } = DockSize.Small; - // Theme settings + // public DockBackdrop Backdrop { get; set; } = DockBackdrop.Acrylic; public UserTheme Theme { get; set; } = UserTheme.Default; @@ -42,7 +42,7 @@ public class DockSettings public string? BackgroundImagePath { get; set; } - // /Theme settings + // public List PinnedCommands { get; set; } = []; public List StartBands { get; set; } = []; @@ -64,7 +64,7 @@ public class DockSettings StartBands.Add(new DockBandSettings { Id = "com.microsoft.cmdpal.winget", ShowLabels = false }); EndBands.Add(new DockBandSettings { Id = "com.microsoft.cmdpal.performanceWidget" }); - EndBands.Add(new DockBandSettings { Id = "com.microsoft.cmdpal.timedate.dockband" }); + EndBands.Add(new DockBandSettings { Id = "com.microsoft.cmdpal.timedate.dockBand" }); } } diff --git a/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/TopLevelCommandManager.cs b/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/TopLevelCommandManager.cs index 7cc0774d64..7fc7bdd734 100644 --- a/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/TopLevelCommandManager.cs +++ b/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/TopLevelCommandManager.cs @@ -32,6 +32,7 @@ public partial class TopLevelCommandManager : ObservableObject, private readonly List _builtInCommands = []; private readonly List _extensionCommandProviders = []; private readonly Lock _commandProvidersLock = new(); + private readonly Lock _dockBandsLock = new(); private readonly SupersedingAsyncGate _reloadCommandsGate; TaskScheduler IPageContext.Scheduler => _taskScheduler; @@ -94,7 +95,10 @@ public partial class TopLevelCommandManager : ObservableObject, TopLevelCommands.Add(c); } } + } + lock (_dockBandsLock) + { if (objects.DockBands is IEnumerable bands) { foreach (var c in bands) @@ -203,7 +207,10 @@ public partial class TopLevelCommandManager : ObservableObject, clone.InsertRange(startIndex, newItems); ListHelpers.InPlaceUpdateList(TopLevelCommands, clone); + } + lock (_dockBandsLock) + { // same idea for DockBands List dockClone = [.. DockBands]; var dockStartIndex = FindIndexForFirstProviderItem(dockClone, sender.ProviderId); @@ -256,6 +263,10 @@ public partial class TopLevelCommandManager : ObservableObject, lock (TopLevelCommands) { TopLevelCommands.Clear(); + } + + lock (_dockBandsLock) + { DockBands.Clear(); } @@ -333,14 +344,14 @@ public partial class TopLevelCommandManager : ObservableObject, var commandSets = (await Task.WhenAll(loadTasks)).Where(results => results is not null).Select(r => r!).ToList(); - lock (TopLevelCommands) + foreach (var providerObjects in commandSets) { - foreach (var providerObjects in commandSets) - { - var commandsCount = providerObjects.Commands?.Count() ?? 0; - var bandsCount = providerObjects.DockBands?.Count() ?? 0; - Logger.LogDebug($"(some provider) Loaded {commandsCount} commands and {bandsCount} bands"); + var commandsCount = providerObjects.Commands?.Count() ?? 0; + var bandsCount = providerObjects.DockBands?.Count() ?? 0; + Logger.LogDebug($"(some provider) Loaded {commandsCount} commands and {bandsCount} bands"); + lock (TopLevelCommands) + { if (providerObjects.Commands is IEnumerable commands) { foreach (var c in commands) @@ -348,7 +359,10 @@ public partial class TopLevelCommandManager : ObservableObject, TopLevelCommands.Add(c); } } + } + lock (_dockBandsLock) + { if (providerObjects.DockBands is IEnumerable bands) { foreach (var c in bands) @@ -408,6 +422,7 @@ public partial class TopLevelCommandManager : ObservableObject, { // Then find all the top-level commands that belonged to that extension List commandsToRemove = []; + List bandsToRemove = []; lock (TopLevelCommands) { foreach (var extension in extensions) @@ -420,6 +435,15 @@ public partial class TopLevelCommandManager : ObservableObject, commandsToRemove.Add(command); } } + + foreach (var band in DockBands) + { + var host = band.ExtensionHost; + if (host?.Extension == extension) + { + bandsToRemove.Add(band); + } + } } } @@ -439,6 +463,17 @@ public partial class TopLevelCommandManager : ObservableObject, } } } + + lock (_dockBandsLock) + { + if (bandsToRemove.Count != 0) + { + foreach (var deleted in bandsToRemove) + { + DockBands.Remove(deleted); + } + } + } }, CancellationToken.None, TaskCreationOptions.None, @@ -464,8 +499,7 @@ public partial class TopLevelCommandManager : ObservableObject, public TopLevelViewModel? LookupDockBand(string id) { - // TODO! bad that we're using TopLevelCommands as the object to lock, even for bands - lock (TopLevelCommands) + lock (_dockBandsLock) { foreach (var command in DockBands) { @@ -499,7 +533,7 @@ public partial class TopLevelCommandManager : ObservableObject, internal void PinDockBand(TopLevelViewModel bandVm) { - lock (DockBands) + lock (_dockBandsLock) { foreach (var existing in DockBands) { diff --git a/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/TopLevelViewModel.cs b/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/TopLevelViewModel.cs index b28eb88825..01fc146023 100644 --- a/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/TopLevelViewModel.cs +++ b/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/TopLevelViewModel.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation +// Copyright (c) Microsoft Corporation // The Microsoft Corporation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. @@ -494,8 +494,9 @@ public sealed partial class TopLevelViewModel : ObservableObject, IListItem, IEx contextItems.Add(new Separator()); var inStartBands = _settings.DockSettings.StartBands.Any(band => band.Id == this.Id); + var inCenterBands = _settings.DockSettings.CenterBands.Any(band => band.Id == this.Id); var inEndBands = _settings.DockSettings.EndBands.Any(band => band.Id == this.Id); - var alreadyPinned = (inStartBands || inEndBands) && + var alreadyPinned = (inStartBands || inCenterBands || inEndBands) && _settings.DockSettings.PinnedCommands.Contains(this.Id); var pinCommand = new PinToDockCommand( @@ -608,9 +609,9 @@ public sealed partial class TopLevelViewModel : ObservableObject, IListItem, IEx ShowLabels = true, }); - // Create a new band VM from our current TLVM. This will allow us to - // update the bands in the CommandProviderWrapper and the TLCM, - // without forcing a whole reload + // Create a new band VM from our current TopLevelViewModel. This + // will allow us to update the bands in the CommandProviderWrapper + // and the TopLevelCommandManager, without forcing a whole reload var bandVm = _topLevelViewModel.CloneAsBand(); _topLevelCommandManager.PinDockBand(bandVm); @@ -621,6 +622,7 @@ public sealed partial class TopLevelViewModel : ObservableObject, IListItem, IEx { _settings.DockSettings.PinnedCommands.Remove(_topLevelViewModel.Id); _settings.DockSettings.StartBands.RemoveAll(band => band.Id == _topLevelViewModel.Id); + _settings.DockSettings.CenterBands.RemoveAll(band => band.Id == _topLevelViewModel.Id); _settings.DockSettings.EndBands.RemoveAll(band => band.Id == _topLevelViewModel.Id); _topLevelViewModel.Save(); diff --git a/src/modules/cmdpal/Microsoft.CmdPal.UI/Dock/DockSettingsToViews.cs b/src/modules/cmdpal/Microsoft.CmdPal.UI/Dock/DockSettingsToViews.cs index c027d66dcc..e8e0e0310e 100644 --- a/src/modules/cmdpal/Microsoft.CmdPal.UI/Dock/DockSettingsToViews.cs +++ b/src/modules/cmdpal/Microsoft.CmdPal.UI/Dock/DockSettingsToViews.cs @@ -48,7 +48,7 @@ internal static class DockSettingsToViews return backdrop switch { DockBackdrop.Transparent => new TransparentTintBackdrop(), - DockBackdrop.Acrylic => null, // new DesktopAcrylicBackdrop(), + DockBackdrop.Acrylic => null, _ => throw new NotImplementedException(), }; } @@ -65,4 +65,3 @@ internal static class DockSettingsToViews }; } } -#pragma warning restore SA1402 // File may only contain a single type diff --git a/src/modules/cmdpal/Microsoft.CmdPal.UI/Dock/DockWindow.xaml.cs b/src/modules/cmdpal/Microsoft.CmdPal.UI/Dock/DockWindow.xaml.cs index f655f3ad09..9d03f2eb69 100644 --- a/src/modules/cmdpal/Microsoft.CmdPal.UI/Dock/DockWindow.xaml.cs +++ b/src/modules/cmdpal/Microsoft.CmdPal.UI/Dock/DockWindow.xaml.cs @@ -108,7 +108,7 @@ public sealed partial class DockWindow : WindowEx, // TaskbarCreated is the message that's broadcast when explorer.exe // restarts. We need to know when that happens to be able to bring our - // appbar back + // app bar back // And this apparently happens on lock screens / hibernates, too WM_TASKBAR_RESTART = PInvoke.RegisterWindowMessage("TaskbarCreated"); @@ -259,7 +259,7 @@ public sealed partial class DockWindow : WindowEx, uCallbackMessage = _callbackMessageId, }; - // Register this window as an appbar + // Register this window as an app bar PInvoke.SHAppBarMessage(PInvoke.ABM_NEW, ref _appBarData); // Stash the last size we created the bar at, so we know when to hot- @@ -294,12 +294,12 @@ public sealed partial class DockWindow : WindowEx, PInvoke.SHAppBarMessage(PInvoke.ABM_QUERYPOS, ref _appBarData); PInvoke.SHAppBarMessage(PInvoke.ABM_SETPOS, ref _appBarData); - // TODO: investigate ABS_AUTOHIDE and autohide bars. + // TODO: investigate ABS_AUTOHIDE and auto hide bars. // I think it's something like this, but I don't totally know - // // _appBarData.lParam = ABS_ALWAYSONTOP; - // _appBarData.lParam = (LPARAM)(int)PInvoke.ABS_AUTOHIDE; - // PInvoke.SHAppBarMessage(ABM_SETSTATE, ref _appBarData); - // PInvoke.SHAppBarMessage(PInvoke.ABM_SETAUTOHIDEBAR, ref _appBarData); + // _appBarData.lParam = ABS_ALWAYSONTOP; + // _appBarData.lParam = (LPARAM)(int)PInvoke.ABS_AUTOHIDE; + // PInvoke.SHAppBarMessage(ABM_SETSTATE, ref _appBarData); + // PInvoke.SHAppBarMessage(PInvoke.ABM_SETAUTOHIDEBAR, ref _appBarData); // Account for system borders when moving the window // Adjust position to account for window frame/border @@ -630,7 +630,7 @@ public sealed partial class DockWindow : WindowEx, _themeService.ThemeChanged -= ThemeService_ThemeChanged; DisposeAcrylic(); - // Remove our appbar registration + // Remove our app bar registration DestroyAppBar(_hwnd); // Unhook the window procedure diff --git a/src/modules/cmdpal/Microsoft.CmdPal.UI/Settings/DockSettingsPage.xaml b/src/modules/cmdpal/Microsoft.CmdPal.UI/Settings/DockSettingsPage.xaml index 540b95bec4..2833d27ee1 100644 --- a/src/modules/cmdpal/Microsoft.CmdPal.UI/Settings/DockSettingsPage.xaml +++ b/src/modules/cmdpal/Microsoft.CmdPal.UI/Settings/DockSettingsPage.xaml @@ -1,4 +1,4 @@ - + @@ -57,18 +56,17 @@ x:Name="DockPositionComboBox" MinWidth="120" SelectedIndex="{x:Bind SelectedSideIndex, Mode=TwoWay}"> - - - - + + + + diff --git a/src/modules/cmdpal/Microsoft.CmdPal.UI/Strings/en-us/Resources.resw b/src/modules/cmdpal/Microsoft.CmdPal.UI/Strings/en-us/Resources.resw index 6c5c81f743..49c0167eee 100644 --- a/src/modules/cmdpal/Microsoft.CmdPal.UI/Strings/en-us/Resources.resw +++ b/src/modules/cmdpal/Microsoft.CmdPal.UI/Strings/en-us/Resources.resw @@ -888,4 +888,28 @@ Right-click to remove the key combination, thereby deactivating the shortcut. Assign shortcut + + Dock position and appearance + + + Choose where the dock appears on your screen + + + Left + + + Top + + + Right + + + Bottom + + + Show labels + + + Choose whether to show labels for dock items by default + \ No newline at end of file diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/Microsoft.CmdPal.Ext.PerformanceMonitor.csproj b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/Microsoft.CmdPal.Ext.PerformanceMonitor.csproj index 0e6823c805..8c17700066 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/Microsoft.CmdPal.Ext.PerformanceMonitor.csproj +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/Microsoft.CmdPal.Ext.PerformanceMonitor.csproj @@ -1,7 +1,7 @@ - - - + + + Microsoft.CmdPal.Ext.PerformanceMonitor $(SolutionDir)$(Platform)\$(Configuration)\WinUI3Apps\CmdPal @@ -9,7 +9,7 @@ false Microsoft.CmdPal.Ext.PerformanceMonitor.pri - enable + enable preview diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.TimeDate/Properties/Resources.Designer.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.TimeDate/Properties/Resources.Designer.cs index 994f0f805a..76ff7a3b64 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.TimeDate/Properties/Resources.Designer.cs +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.TimeDate/Properties/Resources.Designer.cs @@ -941,5 +941,23 @@ namespace Microsoft.CmdPal.Ext.TimeDate { return ResourceManager.GetString("Microsoft_plugin_timedate_Year", resourceCulture); } } + + /// + /// Looks up a localized string similar to Copy date. + /// + public static string timedate_copy_date_command_name { + get { + return ResourceManager.GetString("timedate_copy_date_command_name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Copy time. + /// + public static string timedate_copy_time_command_name { + get { + return ResourceManager.GetString("timedate_copy_time_command_name", resourceCulture); + } + } } } diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.TimeDate/Properties/Resources.resx b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.TimeDate/Properties/Resources.resx index 0235f68ee7..c42f25ca66 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.TimeDate/Properties/Resources.resx +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.TimeDate/Properties/Resources.resx @@ -436,4 +436,12 @@ Clock Title for the time and date dock band + + Copy time + Name of a command to copy the current time to the clipboard + + + Copy date + Name of a command to copy the current date to the clipboard + \ No newline at end of file diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.TimeDate/TimeDateCommandsProvider.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.TimeDate/TimeDateCommandsProvider.cs index 41f24b8ba0..e2012559b8 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.TimeDate/TimeDateCommandsProvider.cs +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.TimeDate/TimeDateCommandsProvider.cs @@ -56,7 +56,7 @@ public sealed partial class TimeDateCommandsProvider : CommandProvider { var wrappedBand = new WrappedDockItem( [_bandItem], - "com.microsoft.cmdpal.timedate.dockband", + "com.microsoft.cmdpal.timedate.dockBand", Resources.Microsoft_plugin_timedate_dock_band_title); return new ICommandItem[] { wrappedBand }; @@ -66,14 +66,15 @@ public sealed partial class TimeDateCommandsProvider : CommandProvider internal sealed partial class NowDockBand : ListItem { + private static readonly TimeSpan UpdateInterval = TimeSpan.FromSeconds(60); private CopyTextCommand _copyTimeCommand; private CopyTextCommand _copyDateCommand; public NowDockBand() { - Command = new NoOpCommand() { Id = "com.microsoft.cmdpal.timedate.dockband" }; - _copyTimeCommand = new CopyTextCommand(string.Empty) { Name = "Copy Time" }; - _copyDateCommand = new CopyTextCommand(string.Empty) { Name = "Copy Date" }; + Command = new NoOpCommand() { Id = "com.microsoft.cmdpal.timedate.dockBand" }; + _copyTimeCommand = new CopyTextCommand(string.Empty) { Name = Resources.timedate_copy_time_command_name }; + _copyDateCommand = new CopyTextCommand(string.Empty) { Name = Resources.timedate_copy_date_command_name }; MoreCommands = [ new CommandContextItem(_copyTimeCommand), new CommandContextItem(_copyDateCommand) @@ -81,11 +82,11 @@ internal sealed partial class NowDockBand : ListItem UpdateText(); // Create a timer to update the time every minute - System.Timers.Timer timer = new(60000); // 60000 ms = 1 minute + System.Timers.Timer timer = new(UpdateInterval.TotalMilliseconds); // but we want it to tick on the minute, so calculate the initial delay var now = DateTime.Now; - timer.Interval = 60000 - ((now.Second * 1000) + now.Millisecond); + timer.Interval = UpdateInterval.TotalMilliseconds - ((now.Second * 1000) + now.Millisecond); // then after the first tick, set it to 60 seconds timer.Elapsed += Timer_ElapsedFirst; @@ -97,7 +98,7 @@ internal sealed partial class NowDockBand : ListItem // After the first tick, set the interval to 60 seconds if (sender is System.Timers.Timer timer) { - timer.Interval = 60000; + timer.Interval = UpdateInterval.TotalMilliseconds; timer.Elapsed -= Timer_ElapsedFirst; timer.Elapsed += Timer_Elapsed; diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.WindowWalker/NativeMethods.txt b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.WindowWalker/NativeMethods.txt deleted file mode 100644 index e679e2c7cd..0000000000 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.WindowWalker/NativeMethods.txt +++ /dev/null @@ -1,14 +0,0 @@ - -GetCurrentThreadId -SetWinEventHook -SetWindowsHookEx -UnhookWindowsHookEx -CallNextHookEx -EVENT_OBJECT_CREATE -EVENT_OBJECT_NAMECHANGE -EVENT_OBJECT_SHOW -EVENT_OBJECT_DESTROY -EVENT_OBJECT_HIDE -WINEVENT_OUTOFCONTEXT -WINEVENT_SKIPOWNPROCESS -OBJECT_IDENTIFIER \ No newline at end of file