Skip to content

Add support for Efficiency Mode (EcoQoS) in WindowExtensions#252

Open
ProfMinecraftDev wants to merge 2 commits intodotMorten:mainfrom
ProfMinecraftDev:feature/efficiency-mode
Open

Add support for Efficiency Mode (EcoQoS) in WindowExtensions#252
ProfMinecraftDev wants to merge 2 commits intodotMorten:mainfrom
ProfMinecraftDev:feature/efficiency-mode

Conversation

@ProfMinecraftDev
Copy link

Add support for Efficiency Mode (EcoQoS) in WindowExtensions

Summary

This Pull Request introduces Efficiency Mode support for WinUI 3 windows. It allows applications to transition into a low-resource state (EcoQoS) when hidden or minimized, and return to high-performance mode when restored.

Technical Background

Windows 11 introduced EcoQoS (Economic Quality of Service) to help developers reduce the power consumption of background processes. By leveraging SetProcessInformation, we can signal the Windows Scheduler to:

  1. Prioritize E-cores (Efficiency cores) over P-cores.
  2. Throttle CPU clock speeds to minimize thermal footprint.
  3. Lower Scheduling Priority to Idle to prevent interference with foreground tasks.

Changes

🛠️ New Utility: EfficiencyModeUtilities

A static helper class that encapsulates the native Win32 calls. It handles OS version checks to apply the best available power saving method:

  • Windows 11 (22000+): Full EcoQoS support.
  • Windows 10 (16299+): Execution speed throttling and priority adjustment.

🧩 Enum: QualityOfServiceLevel

A documented enum to define power states: Default, Eco, Low, and High.

🪟 Extension Methods: WindowExtensions

Updated the standard visibility methods to include power management:

  • Show(bool disableEfficiencyMode = true): Restores performance when the window is active.
  • Hide(bool enableEfficiencyMode = true): Automatically throttles the process when the UI is hidden.

Code Example

// The window will now automatically enter Efficiency Mode when hidden
myWindow.Hide(); 

// And return to normal performance when shown
myWindow.Show();

The EfficiencyModeUtilities class is incorporated to manage the efficient mode of processes in Windows, allowing the QoS level and priority to be adjusted through native APIs. The Show and Hide methods of WindowExtensions now allow you to turn Efficiency Mode on or off when showing or hiding the window. The QualityOfServiceLevel enum is added and references are updated in NativeMethods.txt. Code readability and style are also improved.
@dotMorten
Copy link
Owner

dotMorten commented Feb 21, 2026

Thanks for this but for me to review it could you fix the PR so it doesn’t have all the unrelated changes? It’s probably some indenting / line break changes you inadvertently added and there’s also a bunch of unrelated syntax changes I’m not sure why you changed

@ProfMinecraftDev
Copy link
Author

My apologies, Morten! My editor's auto-formatter seems to have gone rogue on the indentation and line breaks. I'll clean up the history right away and force-push a clean version containing only the Efficiency Mode changes. Thanks for the heads-up!

Refactored extension methods in WindowExtensions.cs
to use lambda expressions, reducing lines and improving the
readability. Adjusted local variables with var, removed
unnecessary control blocks and using were reorganized.
The functionality remains intact, but the code is more
concise and easy to maintain.
@ProfMinecraftDev
Copy link
Author

Done! I've cleaned up the PR. It now only contains the relevant changes for the Efficiency Mode implementation, with no accidental formatting changes. Ready for review!

@dotMorten
Copy link
Owner

Thank you!
First of all I think this would have a very unintentional consequence on existing apps suddenly going into a different mode so this probably shouldn’t just happen on hide/show (and there are more variants than just that btw).
It should instead probably just be a separate API that a user can call to turn on and off.
However with the feature like that, this API doesn’t quite feel right to be in WinUIEx since there’s really not any WinUI/WinAppSDK specific stuff left.
I’ll think about it some more but my initial gut feeling is it’s outside the scope of WinUIEx.

I do appreciate the work you’ve done here and willingness to share it. I’ll simmer on it and let you know.

@ProfMinecraftDev
Copy link
Author

I completely understand your concern about unintentional side effects. You're right, forcing EcoQoS on every Hide/Show might be too aggressive for a general-purpose library.

How about we keep the EfficiencyModeUtilities as an opt-in helper? That way, WinUIEx users get a 'shippable' way to implement Efficiency Mode without us touching the default behavior of Show() and Hide(). Even if it's pure Win32, having it integrated into the WinUIEx ecosystem makes it much more accessible for WinAppSDK developers who are already using your extensions to manage their windows.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds process-level Efficiency Mode (EcoQoS / power throttling) support to WinUIEx, and hooks it into WindowExtensions visibility helpers so apps can reduce resource usage when windows are hidden.

Changes:

  • Introduces EfficiencyModeUtilities and QualityOfServiceLevel for setting process QoS + priority.
  • Updates WindowExtensions.Show/Hide to toggle Efficiency Mode by default when hiding/showing.
  • Extends CsWin32 NativeMethods list with additional process throttling / priority APIs and constants.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 13 comments.

File Description
src/WinUIEx/WindowExtensions.cs Adds optional parameters to Show/Hide and toggles process Efficiency Mode during window visibility changes.
src/WinUIEx/EfficiencyModeUtilities.cs New helper + enum for setting process power throttling and priority class.
src/WinUIEx/NativeMethods.txt Adds required CsWin32 symbols for SetProcessInformation and priority APIs.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

break;

default:
throw new NotImplementedException();
Copy link

Copilot AI Feb 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default switch branch throws NotImplementedException. For invalid enum values (or unsupported levels) an ArgumentOutOfRangeException is more appropriate and produces clearer error messages for callers.

Suggested change
throw new NotImplementedException();
throw new ArgumentOutOfRangeException(nameof(level), level, "Unsupported QualityOfServiceLevel value.");

Copilot uses AI. Check for mistakes.
Comment on lines +9 to +13
/// <summary>
/// WinUI Window Extension Methods
/// </summary>
public static partial class WindowExtensions
{
Copy link

Copilot AI Feb 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file’s indentation was changed to tabs, but the rest of the WinUIEx codebase uses 4-space indentation (e.g., HwndExtensions.cs). Mixing tabs/spaces makes diffs noisy and breaks formatting consistency; please revert to spaces for this file.

Copilot uses AI. Check for mistakes.
Comment on lines +230 to +246
public static bool Show(this Microsoft.UI.Xaml.Window window, bool disableEfficiencyMode = true)
{
EfficiencyModeUtilities.SetEfficiencyMode(!disableEfficiencyMode);
return HwndExtensions.ShowWindow(GetWindowHandle(window));
}

/// <summary>
/// Hides the window and activates another window.
/// </summary>
/// <param name="window">The window to hide.</param>
/// <param name="enableEfficiencyMode">Whether to enable Efficiency Mode when hiding the window.</param>
/// <returns><c>true</c> if the window was previously visible; otherwise, <c>false</c>.</returns>
public static bool Hide(this Microsoft.UI.Xaml.Window window, bool enableEfficiencyMode = true)
{
EfficiencyModeUtilities.SetEfficiencyMode(enableEfficiencyMode);
return HwndExtensions.HideWindow(GetWindowHandle(window));
}
Copy link

Copilot AI Feb 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EfficiencyModeUtilities.SetEfficiencyMode(...) changes process-wide scheduling/priority, but it’s being triggered from per-window Hide/Show. In multi-window apps, hiding one window will throttle the entire process even if other windows remain visible. Consider tracking visible window count (only enable when all windows are hidden/minimized) or moving this behavior behind an explicit opt-in API that isn’t coupled to WindowExtensions.Hide/Show by default.

Copilot uses AI. Check for mistakes.
Comment on lines +256 to +263
/// <summary>
/// Minimizes the specified window and activates the next top-level window in the Z order.
/// </summary>
/// <remarks>The presenter must be an overlapped presenter.</remarks>
/// <exception cref="NotSupportedException">Throw if the AppWindow Presenter isn't an overlapped presenter.</exception>
/// <param name="window">Window</param>
public static void Minimize(this Microsoft.UI.Xaml.Window window) => UpdateOverlappedPresenter(window, (c) => c.Minimize());

Copy link

Copilot AI Feb 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR description mentions entering Efficiency Mode when the window is minimized as well, but Minimize() doesn’t toggle Efficiency Mode (only Hide/Show do). Either update the implementation to cover minimize/restore, or adjust the PR description/docs so behavior matches.

Copilot uses AI. Check for mistakes.
Comment on lines +14 to +16
public static class EfficiencyModeUtilities
{
private static bool EnsureNonZero(this Windows.Win32.Foundation.BOOL value)
Copy link

Copilot AI Feb 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This new file uses tabs for indentation, while most of the repository’s .cs files use 4-space indentation. Please convert tabs to spaces to keep formatting consistent and avoid noisy diffs in future edits.

Copilot uses AI. Check for mistakes.
Comment on lines +224 to +246
/// <summary>
/// Activates the window and displays it in its current size and position.
/// </summary>
/// <param name="window">The window to show.</param>
/// <param name="disableEfficiencyMode">Whether to disable Efficiency Mode when showing the window.</param>
/// <returns><c>true</c> if the window was previously visible; otherwise, <c>false</c>.</returns>
public static bool Show(this Microsoft.UI.Xaml.Window window, bool disableEfficiencyMode = true)
{
EfficiencyModeUtilities.SetEfficiencyMode(!disableEfficiencyMode);
return HwndExtensions.ShowWindow(GetWindowHandle(window));
}

/// <summary>
/// Hides the window and activates another window.
/// </summary>
/// <param name="window">The window to hide.</param>
/// <param name="enableEfficiencyMode">Whether to enable Efficiency Mode when hiding the window.</param>
/// <returns><c>true</c> if the window was previously visible; otherwise, <c>false</c>.</returns>
public static bool Hide(this Microsoft.UI.Xaml.Window window, bool enableEfficiencyMode = true)
{
EfficiencyModeUtilities.SetEfficiencyMode(enableEfficiencyMode);
return HwndExtensions.HideWindow(GetWindowHandle(window));
}
Copy link

Copilot AI Feb 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New behavior in Show/Hide (toggling process QoS/priority) isn’t covered by tests. There are existing WindowExtensions tests (WindowExtensionTests.cs); please add coverage that at least exercises Hide/Show with both parameter values and asserts it doesn’t throw / regress visibility behavior.

Copilot uses AI. Check for mistakes.
Comment on lines +78 to +81
_ = PInvoke.SetPriorityClass(
hProcess: PInvoke.GetCurrentProcess(),
dwPriorityClass: flags).EnsureNonZero();
}
Copy link

Copilot AI Feb 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly, the return value from SetPriorityClass(...) is discarded. If this fails (e.g., due to permissions/policy), the process priority won’t change but the API reports no error. Consider throwing or returning a boolean result to indicate success.

Copilot uses AI. Check for mistakes.
powerThrottling.StateMask = 0;
break;

case QualityOfServiceLevel.Eco when Environment.OSVersion.Version >= new Version(11, 0):
Copy link

Copilot AI Feb 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Windows 11 still reports Environment.OSVersion.Version.Major == 10 (10.0.22000+), so comparing against new Version(11, 0) will never match. As a result, QualityOfServiceLevel.Eco will throw even on Windows 11. Use a build-based check (e.g., 10.0.22000+) or OperatingSystem.IsWindowsVersionAtLeast(10, 0, 22000) instead.

Suggested change
case QualityOfServiceLevel.Eco when Environment.OSVersion.Version >= new Version(11, 0):
case QualityOfServiceLevel.Eco when OperatingSystem.IsWindowsVersionAtLeast(10, 0, 22000):

Copilot uses AI. Check for mistakes.
Comment on lines +91 to +92
QualityOfServiceLevel ecoLevel = Environment.OSVersion.Version >= new Version(11, 0) ? QualityOfServiceLevel.Eco : QualityOfServiceLevel.Low;

Copy link

Copilot AI Feb 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This Windows 11 detection uses Environment.OSVersion.Version >= new Version(11, 0), which won’t be true on Windows 11 (it reports 10.0.22000+). This will cause ecoLevel to always be Low. Use a build/version-at-least check for 10.0.22000 instead.

Copilot uses AI. Check for mistakes.
@ProfMinecraftDev
Copy link
Author

@copilot open a new pull request to apply changes based on the comments in this thread

1 similar comment
@ProfMinecraftDev
Copy link
Author

@copilot open a new pull request to apply changes based on the comments in this thread

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants