From 7cc4a16aa7727c64b61fdea1a66c8082e3cb4ed5 Mon Sep 17 00:00:00 2001
From: Copilot <198982749+Copilot@users.noreply.github.com>
Date: Tue, 31 Mar 2026 20:25:03 -0500
Subject: [PATCH] Add setting to select network speed units in Command Palette
(#46320)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
## Summary of the Pull Request
Adds a unit selection setting to the Performance Monitor extension in
Command Palette that allows users to choose how network transmission
speed is displayed. The setting offers three options: bits per second
(Kbps/Mbps/Gbps, the default), bytes per second (KB/s/MB/s/GB/s), and
binary bytes per second using IEC prefixes (KiB/s/MiB/s/GiB/s).
## PR Checklist
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx
## Detailed Description of the Pull Request / Additional comments
The following files were changed:
- **`NetworkSpeedUnit.cs`** (new): Enum defining the three supported
unit modes — `BitsPerSecond`, `BytesPerSecond`, and
`BinaryBytesPerSecond`.
- **`SettingsManager.cs`** (new): A `JsonSettingsManager` subclass for
the Performance Monitor extension. Defines a `ChoiceSetSetting` for
`NetworkSpeedUnit` (default: `BitsPerSecond`), stored under the
`performanceMonitor` namespace in the shared CmdPal `settings.json`.
- **`PerformanceWidgetsPage.cs`**:
- `PerformanceWidgetsPage` constructor now accepts `SettingsManager` and
passes it to `SystemNetworkUsageWidgetPage`.
- `SystemNetworkUsageWidgetPage` stores the settings manager and calls
`SpeedToString()`, which dispatches via a switch expression to
`FormatAsBitsPerSecString()` (e.g. `12.5 Mbps`),
`FormatAsBytesPerSecString()` (e.g. `1.6 MB/s`), or
`FormatAsBinaryBytesPerSecString()` (e.g. `1.5 MiB/s`) based on the
selected unit.
- **`PerformanceMonitorCommandsProvider.cs`**: Holds the
`SettingsManager`, passes it to both the list page and dock band via
`SetEnabledState()`, exposes `Settings` on the provider, and adds the
settings page to the command's `MoreCommands`. The crash-recovery
hardening from main (`ProviderCrashSentinel`,
`TryReactivateImmediately`, `SetDisabledState`, thread-safe locking) is
fully preserved and integrated with the settings manager.
- **`Resources.resw`**: Updated `Network_Speed_Unit_Setting_Title` and
`Network_Speed_Unit_Setting_Description` to neutral language; added
three choice label strings (`Network_Speed_Unit_BitsPerSec`,
`Network_Speed_Unit_BytesPerSec`,
`Network_Speed_Unit_BinaryBytesPerSec`). Also includes the
disabled-state strings merged from main.
## Validation Steps Performed
- Manually verified that the setting appears in the Performance Monitor
extension's settings page (accessible via the ⋯ context menu on the
Performance Monitor command item).
- Verified that network speed values display in Kbps/Mbps/Gbps by
default, switch to KB/s/MB/s/GB/s when the bytes option is selected, and
switch to KiB/s/MiB/s/GiB/s when the binary bytes option is selected.
- Setting persists across Command Palette restarts via the shared CmdPal
settings file.
- Verified that the crash-recovery re-enable flow correctly restores
pages with the settings manager wired up.
Original prompt
>
> ----
>
> *This section details on the original issue you should resolve*
>
> [Command Palette] Allows network transmission speed units
to be switched between bits per second and bytes per
second
> ### Description of the new feature / enhancement
>
> Add a setting that allows network monitoring in the Command Palette
Dock to be displayed in bytes per second.
>
> ### Scenario when this would be used?
>
> In everyday usage, byte units are more commonly used.
>
> ### Supporting information
>
> _No response_
>
> ## Comments on the Issue (you are @copilot in this section)
>
>
> @niels9001
> @copilot Can you add a setting for this?
>
>
- Fixes microsoft/PowerToys#46271
---
✨ Let Copilot coding agent [set things up for
you](https://github.com/microsoft/PowerToys/issues/new?title=✨+Set+up+Copilot+instructions&body=Configure%20instructions%20for%20this%20repository%20as%20documented%20in%20%5BBest%20practices%20for%20Copilot%20coding%20agent%20in%20your%20repository%5D%28https://gh.io/copilot-coding-agent-tips%29%2E%0A%0A%3COnboard%20this%20repo%3E&assignees=copilot)
— coding agent works faster and does higher quality work when set up for
your repo.
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: niels9001 <9866362+niels9001@users.noreply.github.com>
---
.../NetworkSpeedUnit.cs | 20 ++++
.../PerformanceMonitorCommandsProvider.cs | 13 ++-
.../PerformanceWidgetsPage.cs | 97 +++++++++++++++++--
.../SettingsManager.cs | 50 ++++++++++
.../Strings/en-US/Resources.resw | 15 +++
5 files changed, 186 insertions(+), 9 deletions(-)
create mode 100644 src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/NetworkSpeedUnit.cs
create mode 100644 src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/SettingsManager.cs
diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/NetworkSpeedUnit.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/NetworkSpeedUnit.cs
new file mode 100644
index 0000000000..0578bb1d88
--- /dev/null
+++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/NetworkSpeedUnit.cs
@@ -0,0 +1,20 @@
+// 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.
+
+namespace Microsoft.CmdPal.Ext.PerformanceMonitor;
+
+///
+/// Controls the unit used to display network transmission speed.
+///
+internal enum NetworkSpeedUnit
+{
+ /// Bits per second (Kbps, Mbps, Gbps) — SI decimal prefixes.
+ BitsPerSecond,
+
+ /// Bytes per second (KB/s, MB/s, GB/s) — SI decimal prefixes.
+ BytesPerSecond,
+
+ /// Bytes per second (KiB/s, MiB/s, GiB/s) — IEC binary prefixes.
+ BinaryBytesPerSecond,
+}
diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/PerformanceMonitorCommandsProvider.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/PerformanceMonitorCommandsProvider.cs
index 3f00a99395..f80d84ae70 100644
--- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/PerformanceMonitorCommandsProvider.cs
+++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/PerformanceMonitorCommandsProvider.cs
@@ -21,6 +21,7 @@ public partial class PerformanceMonitorCommandsProvider : CommandProvider
internal static ProviderCrashSentinel CrashSentinel { get; } = new(ProviderIdValue);
private readonly Lock _stateLock = new();
+ private readonly SettingsManager _settingsManager = new();
private ICommandItem[] _commands = [];
private ICommandItem _band = new CommandItem();
private PerformanceWidgetsPage? _mainPage;
@@ -33,6 +34,8 @@ public partial class PerformanceMonitorCommandsProvider : CommandProvider
Id = ProviderIdValue;
Icon = Icons.PerformanceMonitorIcon;
+ Settings = _settingsManager.Settings;
+
if (softDisabled)
{
SetDisabledState();
@@ -121,12 +124,16 @@ public partial class PerformanceMonitorCommandsProvider : CommandProvider
{
DisposeActivePages();
- _mainPage = new PerformanceWidgetsPage(false);
- _bandPage = new PerformanceWidgetsPage(true);
+ _mainPage = new PerformanceWidgetsPage(_settingsManager, false);
+ _bandPage = new PerformanceWidgetsPage(_settingsManager, true);
_band = new CommandItem(_bandPage) { Title = DisplayName };
_commands =
[
- new CommandItem(_mainPage) { Title = DisplayName },
+ new CommandItem(_mainPage)
+ {
+ Title = DisplayName,
+ MoreCommands = [new CommandContextItem(_settingsManager.Settings.SettingsPage)],
+ },
];
_softDisabled = false;
}
diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/PerformanceWidgetsPage.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/PerformanceWidgetsPage.cs
index f82e45bc57..f898079ca2 100644
--- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/PerformanceWidgetsPage.cs
+++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/PerformanceWidgetsPage.cs
@@ -43,7 +43,7 @@ internal sealed partial class PerformanceWidgetsPage : OnLoadStaticListPage, IDi
private readonly SystemMemoryUsageWidgetPage _memoryPage = new();
private readonly ListItem _memoryItem;
- private readonly SystemNetworkUsageWidgetPage _networkPage = new();
+ private readonly SystemNetworkUsageWidgetPage _networkPage;
private readonly ListItem _networkItem;
private readonly SystemGPUUsageWidgetPage _gpuPage = new();
@@ -55,9 +55,10 @@ internal sealed partial class PerformanceWidgetsPage : OnLoadStaticListPage, IDi
private string _networkUpSpeed = string.Empty;
private string _networkDownSpeed = string.Empty;
- public PerformanceWidgetsPage(bool isBandPage = false)
+ public PerformanceWidgetsPage(SettingsManager settingsManager, bool isBandPage = false)
{
_isBandPage = isBandPage;
+ _networkPage = new SystemNetworkUsageWidgetPage(settingsManager);
_cpuItem = new ListItem(_cpuPage)
{
Title = _cpuPage.GetItemTitle(isBandPage),
@@ -532,10 +533,12 @@ internal sealed partial class SystemNetworkUsageWidgetPage : WidgetPage, IDispos
public override IconInfo Icon => Icons.NetworkIcon;
private readonly DataManager _dataManager;
+ private readonly SettingsManager _settingsManager;
private int _networkIndex;
- public SystemNetworkUsageWidgetPage()
+ public SystemNetworkUsageWidgetPage(SettingsManager settingsManager)
{
+ _settingsManager = settingsManager;
_dataManager = new(DataType.Network, () => UpdateWidget());
Commands = [
new CommandContextItem(new PrevNetworkCommand(this) { Name = Resources.GetResource("Previous_Network_Title") }),
@@ -561,8 +564,8 @@ internal sealed partial class SystemNetworkUsageWidgetPage : WidgetPage, IDispos
var networkStats = currentData.GetNetworkUsage(_networkIndex);
ContentData["networkUsage"] = FloatToPercentString(networkStats.Usage);
- ContentData["netSent"] = BytesToBitsPerSecString(networkStats.Sent);
- ContentData["netReceived"] = BytesToBitsPerSecString(networkStats.Received);
+ ContentData["netSent"] = SpeedToString(networkStats.Sent);
+ ContentData["netReceived"] = SpeedToString(networkStats.Received);
ContentData["networkName"] = netName;
ContentData["netGraphUrl"] = currentData.CreateNetImageUrl(_networkIndex);
ContentData["chartHeight"] = ChartHelper.ChartHeight + "px";
@@ -627,7 +630,17 @@ internal sealed partial class SystemNetworkUsageWidgetPage : WidgetPage, IDispos
}
}
- private string BytesToBitsPerSecString(float value)
+ private string SpeedToString(float bytesPerSec)
+ {
+ return _settingsManager.NetworkSpeedUnit switch
+ {
+ NetworkSpeedUnit.BytesPerSecond => FormatAsBytesPerSecString(bytesPerSec),
+ NetworkSpeedUnit.BinaryBytesPerSecond => FormatAsBinaryBytesPerSecString(bytesPerSec),
+ _ => FormatAsBitsPerSecString(bytesPerSec),
+ };
+ }
+
+ private static string FormatAsBitsPerSecString(float value)
{
// Bytes to bits
value *= 8;
@@ -666,6 +679,78 @@ internal sealed partial class SystemNetworkUsageWidgetPage : WidgetPage, IDispos
return string.Format(CultureInfo.InvariantCulture, "{0:0} Gbps", value);
}
+ private static string FormatAsBytesPerSecString(float value)
+ {
+ // Bytes to KB
+ value /= 1024;
+ if (value < 1024)
+ {
+ if (value < 100)
+ {
+ return string.Format(CultureInfo.InvariantCulture, "{0:0.0} KB/s", value);
+ }
+
+ return string.Format(CultureInfo.InvariantCulture, "{0:0} KB/s", value);
+ }
+
+ // KB to MB
+ value /= 1024;
+ if (value < 1024)
+ {
+ if (value < 100)
+ {
+ return string.Format(CultureInfo.InvariantCulture, "{0:0.0} MB/s", value);
+ }
+
+ return string.Format(CultureInfo.InvariantCulture, "{0:0} MB/s", value);
+ }
+
+ // MB to GB
+ value /= 1024;
+ if (value < 100)
+ {
+ return string.Format(CultureInfo.InvariantCulture, "{0:0.0} GB/s", value);
+ }
+
+ return string.Format(CultureInfo.InvariantCulture, "{0:0} GB/s", value);
+ }
+
+ private static string FormatAsBinaryBytesPerSecString(float value)
+ {
+ // Bytes to KiB
+ value /= 1024;
+ if (value < 1024)
+ {
+ if (value < 100)
+ {
+ return string.Format(CultureInfo.InvariantCulture, "{0:0.0} KiB/s", value);
+ }
+
+ return string.Format(CultureInfo.InvariantCulture, "{0:0} KiB/s", value);
+ }
+
+ // KiB to MiB
+ value /= 1024;
+ if (value < 1024)
+ {
+ if (value < 100)
+ {
+ return string.Format(CultureInfo.InvariantCulture, "{0:0.0} MiB/s", value);
+ }
+
+ return string.Format(CultureInfo.InvariantCulture, "{0:0} MiB/s", value);
+ }
+
+ // MiB to GiB
+ value /= 1024;
+ if (value < 100)
+ {
+ return string.Format(CultureInfo.InvariantCulture, "{0:0.0} GiB/s", value);
+ }
+
+ return string.Format(CultureInfo.InvariantCulture, "{0:0} GiB/s", value);
+ }
+
internal override void PushActivate()
{
base.PushActivate();
diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/SettingsManager.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/SettingsManager.cs
new file mode 100644
index 0000000000..2c32ddb9f4
--- /dev/null
+++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/SettingsManager.cs
@@ -0,0 +1,50 @@
+// 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.
+
+using System;
+using System.IO;
+using CoreWidgetProvider.Helpers;
+using Microsoft.CommandPalette.Extensions.Toolkit;
+
+namespace Microsoft.CmdPal.Ext.PerformanceMonitor;
+
+internal sealed class SettingsManager : JsonSettingsManager
+{
+ private const string Namespace = "performanceMonitor";
+
+ private static string Namespaced(string propertyName) => $"{Namespace}.{propertyName}";
+
+ private readonly ChoiceSetSetting _networkSpeedUnit = new(
+ Namespaced(nameof(NetworkSpeedUnit)),
+ Resources.GetResource("Network_Speed_Unit_Setting_Title"),
+ Resources.GetResource("Network_Speed_Unit_Setting_Description"),
+ [
+ new ChoiceSetSetting.Choice(Resources.GetResource("Network_Speed_Unit_BitsPerSec"), NetworkSpeedUnit.BitsPerSecond.ToString("G")),
+ new ChoiceSetSetting.Choice(Resources.GetResource("Network_Speed_Unit_BytesPerSec"), NetworkSpeedUnit.BytesPerSecond.ToString("G")),
+ new ChoiceSetSetting.Choice(Resources.GetResource("Network_Speed_Unit_BinaryBytesPerSec"), NetworkSpeedUnit.BinaryBytesPerSecond.ToString("G")),
+ ]);
+
+ public NetworkSpeedUnit NetworkSpeedUnit =>
+ Enum.TryParse(_networkSpeedUnit.Value, out var unit)
+ ? unit
+ : NetworkSpeedUnit.BitsPerSecond;
+
+ private static string SettingsJsonPath()
+ {
+ var directory = Utilities.BaseSettingsPath("Microsoft.CmdPal");
+ Directory.CreateDirectory(directory);
+ return Path.Combine(directory, "settings.json");
+ }
+
+ public SettingsManager()
+ {
+ FilePath = SettingsJsonPath();
+
+ Settings.Add(_networkSpeedUnit);
+
+ LoadSettings();
+
+ Settings.SettingsChanged += (_, _) => SaveSettings();
+ }
+}
diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/Strings/en-US/Resources.resw b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/Strings/en-US/Resources.resw
index 1d49265baf..92d5c7be1d 100644
--- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/Strings/en-US/Resources.resw
+++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PerformanceMonitor/Strings/en-US/Resources.resw
@@ -276,4 +276,19 @@
Receive ↓
+
+ Network speed unit
+
+
+ Choose the unit used to display network transmission speed
+
+
+ Bits per second (Kbps, Mbps, Gbps)
+
+
+ Bytes per second (KB/s, MB/s, GB/s)
+
+
+ Binary bytes per second (KiB/s, MiB/s, GiB/s)
+