From 1be3b6c087455d244518636951c943a0fb50603f Mon Sep 17 00:00:00 2001 From: Den Delimarsky Date: Thu, 25 Jul 2024 09:09:17 -0700 Subject: [PATCH] [Awake]Refactor and update version - `DAISY023_04102024` (#32378) Improves the following: - Consolidates different code paths for easier maintenance. - Removes the dependency on Windows Forms and creates the system tray icon and handling through native Win32 APIs (massive thank you to @BrianPeek for helping write the window creation logic and diagnosing threading issues). - Changing modes in Awake now triggers icon changes in the tray (#11996). Massive thank you to @niels9001 for creating the icons. Fixes the following: - When in the UI and you select `0` as hours and `0` as minutes in `TIMED` awake mode, the UI becomes non-responsive whenever you try to get back to timed after it rolls back to `PASSIVE`. (#33630) - Adds the option to keep track of Awake state through tray tooltip. (#12714) --------- Co-authored-by: Clint Rutkas Co-authored-by: Jaime Bernardo --- .github/actions/spell-check/expect.txt | 31 +- Directory.Build.props | 2 +- Directory.Packages.props | 2 +- NOTICE.md | 2 +- doc/planning/awake.md | 17 +- .../awake/Awake/Assets/Awake/disabled.ico | Bin 0 -> 97566 bytes .../awake/Awake/Assets/Awake/expirable.ico | Bin 0 -> 97566 bytes .../awake/Awake/Assets/Awake/indefinite.ico | Bin 0 -> 97566 bytes .../awake/Awake/Assets/Awake/normal.ico | Bin 0 -> 97566 bytes .../awake/Awake/Assets/Awake/scheduled.ico | Bin 0 -> 97566 bytes .../awake/Awake/Assets/Awake/timed.ico | Bin 0 -> 97566 bytes src/modules/awake/Awake/Awake.csproj | 26 +- src/modules/awake/Awake/Core/Constants.cs | 10 +- .../awake/Awake/Core/ExtensionMethods.cs | 1 - src/modules/awake/Awake/Core/Manager.cs | 274 +++++++----- src/modules/awake/Awake/Core/Models/MSG.cs | 18 + .../awake/Awake/Core/Models/MenuInfo.cs | 21 + .../awake/Awake/Core/Models/NOTIFYICONDATA.cs | 22 + src/modules/awake/Awake/Core/Models/POINT.cs | 15 + .../SingleThreadSynchronizationContext.cs | 62 +++ .../awake/Awake/Core/Models/TrayCommands.cs | 12 +- .../awake/Awake/Core/Models/TrayIconAction.cs | 13 + .../awake/Awake/Core/Models/WNDCLASSEX.cs | 26 ++ src/modules/awake/Awake/Core/Native/Bridge.cs | 64 ++- .../awake/Awake/Core/Native/Constants.cs | 34 +- src/modules/awake/Awake/Core/TrayHelper.cs | 393 +++++++++++++----- .../awake/Awake/Core/TrayMessageFilter.cs | 172 -------- src/modules/awake/Awake/Program.cs | 243 ++++------- .../Awake/Properties/Resources.Designer.cs | 126 +++++- .../awake/Awake/Properties/Resources.resx | 42 +- .../Settings.UI.Library/AwakeMode.cs | 14 + .../Settings.UI.Library/AwakeProperties.cs | 10 +- .../Settings.UI.Library/AwakeSettings.cs | 4 +- .../SettingsXAML/Views/AwakePage.xaml | 2 +- .../Settings.UI/ViewModels/AwakeViewModel.cs | 36 +- 35 files changed, 1054 insertions(+), 640 deletions(-) create mode 100644 src/modules/awake/Awake/Assets/Awake/disabled.ico create mode 100644 src/modules/awake/Awake/Assets/Awake/expirable.ico create mode 100644 src/modules/awake/Awake/Assets/Awake/indefinite.ico create mode 100644 src/modules/awake/Awake/Assets/Awake/normal.ico create mode 100644 src/modules/awake/Awake/Assets/Awake/scheduled.ico create mode 100644 src/modules/awake/Awake/Assets/Awake/timed.ico create mode 100644 src/modules/awake/Awake/Core/Models/MSG.cs create mode 100644 src/modules/awake/Awake/Core/Models/MenuInfo.cs create mode 100644 src/modules/awake/Awake/Core/Models/NOTIFYICONDATA.cs create mode 100644 src/modules/awake/Awake/Core/Models/POINT.cs create mode 100644 src/modules/awake/Awake/Core/Models/SingleThreadSynchronizationContext.cs create mode 100644 src/modules/awake/Awake/Core/Models/TrayIconAction.cs create mode 100644 src/modules/awake/Awake/Core/Models/WNDCLASSEX.cs delete mode 100644 src/modules/awake/Awake/Core/TrayMessageFilter.cs create mode 100644 src/settings-ui/Settings.UI.Library/AwakeMode.cs diff --git a/.github/actions/spell-check/expect.txt b/.github/actions/spell-check/expect.txt index 1299374146..0cfc383559 100644 --- a/.github/actions/spell-check/expect.txt +++ b/.github/actions/spell-check/expect.txt @@ -221,7 +221,6 @@ comdlg comexp cominterop commandline -COMMANDTITLE commctrl commdlg compmgmt @@ -430,8 +429,8 @@ ENDSESSION ENTERSIZEMOVE ENU EOAC -epu EPO +epu ERASEBKGND EREOF EResize @@ -486,7 +485,6 @@ FILEFLAGSMASK FILELOCKSMITH FILELOCKSMITHCONTEXTMENU FILELOCKSMITHEXT -FILELOCKSMITHLIB FILELOCKSMITHLIBINTEROP FILEMUSTEXIST FILEOP @@ -502,6 +500,7 @@ findfast FIXEDFILEINFO flac flyouts +FMask FOF FOFX FOLDERID @@ -523,7 +522,6 @@ GCLP gdi gdiplus GDISCALED -gdnbaselines GEmoji GETCLIENTAREAANIMATION GETDESKWALLPAPER @@ -543,7 +541,6 @@ gpedit gpo GPOCA gpp -GPT gpu GSM gtm @@ -703,7 +700,6 @@ INSTALLSTARTMENUSHORTCUT INSTALLSTATE Inste Intelli -interactable Interlop INTRESOURCE INVALIDARG @@ -732,7 +728,6 @@ IWeb IWIC iwr IYUV -JArray jfi jfif jgeosdfsdsgmkedfgdfgdfgbkmhcgcflmi @@ -764,7 +759,6 @@ KILLFOCUS killrunner kmph Knownfolders -ksh KSPROPERTY Kybd languagesjson @@ -800,7 +794,6 @@ LOADFROMFILE LOBYTE LOCALDISPLAY LOCALPACKAGE -localport LOCALSYSTEM LOCATIONCHANGE LOGFONT @@ -814,6 +807,7 @@ LOWORD lparam LPBITMAPINFOHEADER LPCITEMIDLIST +lpcmi LPCMINVOKECOMMANDINFO LPCREATESTRUCT LPCRECT @@ -838,6 +832,7 @@ lptpm LPTR LPTSTR LPW +lpwcx lpwndpl LReader LRESULT @@ -855,10 +850,10 @@ lwin LZero majortype makecab -MAKELANGID MAKEINTRESOURCE MAKEINTRESOURCEA MAKEINTRESOURCEW +MAKELANGID makepri manifestdependency MAPPEDTOSAMEKEY @@ -878,7 +873,6 @@ mdwn MEDIASUBTYPE mediatype mef -MENUBREAK MENUITEMINFO MENUITEMINFOW MERGECOPY @@ -1041,6 +1035,7 @@ NOSEARCH NOSENDCHANGING NOSIZE NOTIFICATIONSDLL +NOTIFYICONDATA NOTIFYICONDATAW NOTIMPL notlike @@ -1064,7 +1059,6 @@ numberbox nwc Objbase objidl -occurrence ocr Ocrsettings odbccp @@ -1078,7 +1072,6 @@ oldtheme oleaut OLECHAR onebranch -OOBEPT opencode OPENFILENAME opensource @@ -1102,7 +1095,6 @@ OVERLAPPEDWINDOW overlaywindow Oversampling OWNDC -OWNERDRAW Packagemanager PACL PAINTSTRUCT @@ -1116,7 +1108,6 @@ PARTIALCONFIRMATIONDIALOGTITLE PATCOPY pathcch PATHMUSTEXIST -Pathto PATINVERT PATPAINT PAUDIO @@ -1165,6 +1156,7 @@ ploca plocm pluginsmodel PMSIHANDLE +pnid Pnp Popups POPUPWINDOW @@ -1257,8 +1249,6 @@ QUERYENDSESSION QUERYOPEN QUEUESYNC QUNS -qwertyuiopasdfghjklzxcvbnm -qwrtyuiopsghjklzxvnm raf RAII RAlt @@ -1275,7 +1265,6 @@ RECTDESTINATION rectp RECTSOURCE recyclebin -redirectedfrom Redist redistributable reencode @@ -1357,8 +1346,6 @@ runas rundll rungameid RUNLEVEL -runsettings -runspace runtimeclass runtimeobject runtimepack @@ -1592,7 +1579,6 @@ TDevice telem telephon templatenamespace -testhost testprocess TEXCOORD TEXTEXTRACTOR @@ -1617,7 +1603,6 @@ tlb tlbimp TMPVAR TNP -toggleswitch Toolhelp toolkitconverters Toolset @@ -1647,9 +1632,11 @@ TYPESHORTCUT UAC UAL uap +UCallback udit uefi uesc +UFlags UHash UIA UIEx diff --git a/Directory.Build.props b/Directory.Build.props index 2226bab418..5cee923ad1 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -85,7 +85,7 @@ false - 202407100737 + 202407200737 diff --git a/NOTICE.md b/NOTICE.md index 51589b2302..4bfdb688e1 100644 --- a/NOTICE.md +++ b/NOTICE.md @@ -1359,7 +1359,7 @@ EXHIBIT A -Mozilla Public License. - System.IO.Abstractions 17.2.3 - System.IO.Abstractions.TestingHelpers 17.2.3 - System.Management 8.0.0 -- System.Reactive 6.0.0-preview.9 +- System.Reactive 6.0.1 - System.Runtime.Caching 8.0.0 - System.Security.Cryptography.ProtectedData 8.0.0 - System.ServiceProcess.ServiceController 8.0.0 diff --git a/doc/planning/awake.md b/doc/planning/awake.md index f7e579c4b4..cfbbbefac9 100644 --- a/doc/planning/awake.md +++ b/doc/planning/awake.md @@ -1,21 +1,34 @@ --- -last-update: 3-20-2022 +last-update: 7-16-2024 --- # PowerToys Awake Changelog ## Builds -The build ID can be found in `Program.cs` in the `BuildId` variable - it is a unique identifier for the current builds that allows better diagnostics (we can look up the build ID from the logs) and offers a way to triage Awake-specific issues faster independent of the PowerToys version. The build ID does not carry any significance beyond that within the PowerToys code base. +The build ID can be found in `Core\Constants.cs` in the `BuildId` variable - it is a unique identifier for the current builds that allows better diagnostics (we can look up the build ID from the logs) and offers a way to triage Awake-specific issues faster independent of the PowerToys version. The build ID does not carry any significance beyond that within the PowerToys code base. The build ID moniker is made up of two components - a reference to a [Halo](https://en.wikipedia.org/wiki/Halo_(franchise)) character, and the date when the work on the specific build started in the format of `MMDDYYYY`. | Build ID | Build Date | |:----------------------------------------------------------|:-----------------| +| [`DAISY023_04102024`](#DAISY023_04102024-april-10-2024) | April 10, 2024 | | [`ATRIOX_04132023`](#ATRIOX_04132023-april-13-2023) | April 13, 2023 | | [`LIBRARIAN_03202022`](#librarian_03202022-march-20-2022) | March 20, 2022 | | `ARBITER_01312022` | January 31, 2022 | +### `DAISY023_04102024` (April 10, 2024) + +>[!NOTE] +>See pull request: [Awake Update - `DAISY023_04102024`](https://github.com/microsoft/PowerToys/pull/32378) + +- [#33630](https://github.com/microsoft/PowerToys/issues/33630) When in the UI and you select `0` as hours and `0` as minutes in `TIMED` awake mode, the UI becomes non-responsive whenever you try to get back to timed after it rolls back to `PASSIVE`. +- [#12714](https://github.com/microsoft/PowerToys/issues/12714) Adds the option to keep track of Awake state through tray tooltip. +- [#11996](https://github.com/microsoft/PowerToys/issues/11996) Adds custom icons support for mode changes in Awake. +- Removes the dependency on `System.Windows.Forms` and instead uses native Windows APIs to create the tray icon. +- Removes redundant/unused code that impacted application performance. +- Updates dependent packages to their latest versions (`Microsoft.Windows.CsWinRT` and `System.Reactive`). + ### `ATRIOX_04132023` (April 13, 2023) - Moves from using `Task.Run` to spin up threads to actually using a blocking queue that properly sets thread parameters on the same thread. diff --git a/src/modules/awake/Awake/Assets/Awake/disabled.ico b/src/modules/awake/Awake/Assets/Awake/disabled.ico new file mode 100644 index 0000000000000000000000000000000000000000..3495684891dbfc13daaf3e1dd649e6e9d9a2a3fc GIT binary patch literal 97566 zcmeHw3!GKedGE#-uL+sT2uMJfTxbk24T&Z;#sq3pwZAr&N(pUalr*Nk6<^Hon3==O zFlPn^hNmE}0Yp#{@qurVL40B&=Fz;G2uT~-+uH`qZSSSGy7&G6zi)ket-a?UpqOZK z4y;*wpU2*7umAV`zsFj8?I`LIeIOb=x)SvX(Um7f(f6Y$8a`b2|M|Em`a;hr8Z^l5 z_lTn3?Gr_nmAZdA_WM;t_0DtfHdqvS}AL8$I|3w_XWdwh(`&XVA zMHhW6iV6kp506go)gyWY$I{~skM0_Y-~T>7k>g<>ziYX)hdbWzsI_+#{oV~d-0_A- zSDp|>kJR>vPRBLiFwrCwUKd{ltz#CJ6^)i-^$O0)pUL~^k77{{lOC#A!$VDuq?K%q`=q7F_iCe>A`hN^9Vea~ z;Zh6yKH8stQe@ZRLp0N_iKlICX+aP5teGsAB@OM6-^ll)n%ZK~b%Og9j~_+o%Nl;o zUs+M$M_ciI_qH^uc!hqySj)Hh(!cusnpzy^pdJYy;TP`swP>e(z{|kKj8SS2hmJk6;H(Du-}Tsf3B^mtw*`C27mFNFML*8Q=ErB zFa8s^@K65Y)M#l<5r5LRv5TIFT5)Fd5?^REJ}Yv+GKqY9mM)|)D5Wjq8<~}UDzLneX9%DCrL^@%+(*{n|Q&FNOiocXS#Za ztAFNdo(!*^M_SwO>^L*s@7;Oqyb;<_;74P$y=>=E_nZ8{|BiNMILcTQvojHFX6aW! z8vwh4EfoCYTln+qurp*Vw!^(dv-}(Ql)6;oKJBHnta^|4jE?OKDQgRnK&OpClzDp! zpOI5=+yZ_M-f%CR0~{&ZFYnZVWFzv5dtFfgpOAj|YrLralZ&z`B!c~(LUTeuFhB*I zT|XC^nZkY2p!+>O@2Q{b59If?4IMlfiyWWlmtP!gZ7K8wPZwLsDYc*>*5IXjveG}1 zXXJvUJ?@X|vSV4PoaX*QBj14by$;pg3$^Wvjz{T{6r@DZK9PKC!Pii3M4=_m7rxKW z`MsW9RPPcm%K0Fa(I_V8!+T(-_@thK1e?Yd9o-Aih~H`T!JbL9w?_j0WobZ9k3k{P63$Pe{65OLLE%2% zKVH6P$FZ6?SE39@F`Nt7F8wM1RD4nZzO48U8wLD1dOqu=_P8f7#Ibsz^WYi~BWN`E zf~pBPYo$Y5Cri(wWAU|v=-{5U==P3c#BURb$*}J&P)#cI_bQy<^a3XiI^1 zirq%JMobeSmXR9q4BxZgux39|7beL^z3>+=#3Jd7$6�@-=@O-E{30C|5?eTz^$m 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 literal 0 HcmV?d00001 diff --git a/src/modules/awake/Awake/Assets/Awake/indefinite.ico b/src/modules/awake/Awake/Assets/Awake/indefinite.ico new file mode 100644 index 0000000000000000000000000000000000000000..a988e8b581e2ab958cd374234165e03275188c74 GIT binary patch literal 97566 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 bNGbZN&qShxGm%#KA!lfkFYpJnr04xV<-(a@ literal 0 HcmV?d00001 diff --git a/src/modules/awake/Awake/Assets/Awake/scheduled.ico b/src/modules/awake/Awake/Assets/Awake/scheduled.ico new file mode 100644 index 0000000000000000000000000000000000000000..768f2038dfe39dbb4ebb4702c7981c0d3b36fbc1 GIT binary patch literal 97566 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 Fe+N94XGQ=3 literal 0 HcmV?d00001 diff --git a/src/modules/awake/Awake/Assets/Awake/timed.ico b/src/modules/awake/Awake/Assets/Awake/timed.ico new file mode 100644 index 0000000000000000000000000000000000000000..2cef35513f4306ae7a0455835edd36a23840bb70 GIT binary patch literal 97566 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 literal 0 HcmV?d00001 diff --git a/src/modules/awake/Awake/Awake.csproj b/src/modules/awake/Awake/Awake.csproj index 9f09482fdb..1ea7ab2b39 100644 --- a/src/modules/awake/Awake/Awake.csproj +++ b/src/modules/awake/Awake/Awake.csproj @@ -10,7 +10,7 @@ enable false false - true + False true PowerToys.Awake @@ -59,6 +59,12 @@ + + + + + + @@ -90,6 +96,24 @@ Always + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + diff --git a/src/modules/awake/Awake/Core/Constants.cs b/src/modules/awake/Awake/Core/Constants.cs index 267197b60e..80a75dc1ed 100644 --- a/src/modules/awake/Awake/Core/Constants.cs +++ b/src/modules/awake/Awake/Core/Constants.cs @@ -8,7 +8,15 @@ namespace Awake.Core { internal const string AppName = "Awake"; internal const string FullAppName = "PowerToys " + AppName; - internal const string TrayWindowId = "WindowsForms10.Window.0.app.0."; + internal const string TrayWindowId = "Awake.MessageWindow"; internal const string BuildRegistryLocation = @"SOFTWARE\Microsoft\Windows NT\CurrentVersion"; + + // PowerToys Awake build code name. Used for exact logging + // that does not map to PowerToys broad version schema to pinpoint + // internal issues easier. + // Format of the build ID is: CODENAME_MMDDYYYY, where MMDDYYYY + // is representative of the date when the last change was made before + // the pull request is issued. + internal const string BuildId = "DAISY023_04102024"; } } diff --git a/src/modules/awake/Awake/Core/ExtensionMethods.cs b/src/modules/awake/Awake/Core/ExtensionMethods.cs index d669791b3f..f86e9812fa 100644 --- a/src/modules/awake/Awake/Core/ExtensionMethods.cs +++ b/src/modules/awake/Awake/Core/ExtensionMethods.cs @@ -12,7 +12,6 @@ namespace Awake.Core public static void AddRange(this ICollection target, IEnumerable source) { ArgumentNullException.ThrowIfNull(target); - ArgumentNullException.ThrowIfNull(source); foreach (var element in source) diff --git a/src/modules/awake/Awake/Core/Manager.cs b/src/modules/awake/Awake/Core/Manager.cs index 2136ca4b71..473a4f2147 100644 --- a/src/modules/awake/Awake/Core/Manager.cs +++ b/src/modules/awake/Awake/Core/Manager.cs @@ -5,7 +5,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; +using System.Drawing; using System.Globalization; using System.IO; using System.Reactive.Linq; @@ -30,25 +30,29 @@ namespace Awake.Core /// public class Manager { - private static readonly CompositeFormat AwakeMinutes = System.Text.CompositeFormat.Parse(Properties.Resources.AWAKE_MINUTES); - private static readonly CompositeFormat AwakeHours = System.Text.CompositeFormat.Parse(Properties.Resources.AWAKE_HOURS); + private static bool _isUsingPowerToysConfig; - private static BlockingCollection _stateQueue; + internal static bool IsUsingPowerToysConfig { get => _isUsingPowerToysConfig; set => _isUsingPowerToysConfig = value; } + + private static readonly CompositeFormat AwakeMinutes = CompositeFormat.Parse(Resources.AWAKE_MINUTES); + private static readonly CompositeFormat AwakeHours = CompositeFormat.Parse(Resources.AWAKE_HOURS); + + private static readonly BlockingCollection _stateQueue; private static CancellationTokenSource _tokenSource; private static SettingsUtils? _moduleSettings; - private static SettingsUtils? ModuleSettings { get => _moduleSettings; set => _moduleSettings = value; } + internal static SettingsUtils? ModuleSettings { get => _moduleSettings; set => _moduleSettings = value; } static Manager() { _tokenSource = new CancellationTokenSource(); - _stateQueue = new BlockingCollection(); + _stateQueue = []; ModuleSettings = new SettingsUtils(); } - public static void StartMonitor() + internal static void StartMonitor() { Thread monitorThread = new(() => { @@ -70,7 +74,7 @@ namespace Awake.Core Bridge.SetConsoleCtrlHandler(handler, addHandler); } - public static void AllocateConsole() + internal static void AllocateConsole() { Bridge.AllocConsole(); @@ -103,17 +107,12 @@ namespace Awake.Core private static ExecutionState ComputeAwakeState(bool keepDisplayOn) { - if (keepDisplayOn) - { - return ExecutionState.ES_SYSTEM_REQUIRED | ExecutionState.ES_DISPLAY_REQUIRED | ExecutionState.ES_CONTINUOUS; - } - else - { - return ExecutionState.ES_SYSTEM_REQUIRED | ExecutionState.ES_CONTINUOUS; - } + return keepDisplayOn + ? ExecutionState.ES_SYSTEM_REQUIRED | ExecutionState.ES_DISPLAY_REQUIRED | ExecutionState.ES_CONTINUOUS + : ExecutionState.ES_SYSTEM_REQUIRED | ExecutionState.ES_CONTINUOUS; } - public static void CancelExistingThread() + internal static void CancelExistingThread() { Logger.LogInfo($"Attempting to ensure that the thread is properly cleaned up..."); @@ -128,81 +127,156 @@ namespace Awake.Core Logger.LogInfo("Instantiating of new token source and thread token completed."); } - public static void SetIndefiniteKeepAwake(bool keepDisplayOn = false) + internal static void SetIndefiniteKeepAwake(bool keepDisplayOn = false) { PowerToysTelemetry.Log.WriteEvent(new Telemetry.AwakeIndefinitelyKeepAwakeEvent()); CancelExistingThread(); _stateQueue.Add(ComputeAwakeState(keepDisplayOn)); + + TrayHelper.SetShellIcon(TrayHelper.HiddenWindowHandle, $"{Constants.FullAppName} [{Resources.AWAKE_TRAY_TEXT_INDEFINITE}]", new Icon(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assets/Awake/indefinite.ico")), TrayIconAction.Update); + + if (IsUsingPowerToysConfig) + { + try + { + var currentSettings = ModuleSettings!.GetSettings(Constants.AppName) ?? new AwakeSettings(); + var settingsChanged = currentSettings.Properties.Mode != AwakeMode.INDEFINITE || + currentSettings.Properties.KeepDisplayOn != keepDisplayOn; + + if (settingsChanged) + { + currentSettings.Properties.Mode = AwakeMode.INDEFINITE; + currentSettings.Properties.KeepDisplayOn = keepDisplayOn; + ModuleSettings!.SaveSettings(JsonSerializer.Serialize(currentSettings), Constants.AppName); + } + } + catch (Exception ex) + { + Logger.LogError($"Failed to handle indefinite keep awake command: {ex.Message}"); + } + } } - public static void SetNoKeepAwake() + internal static void SetExpirableKeepAwake(DateTimeOffset expireAt, bool keepDisplayOn = true) { - PowerToysTelemetry.Log.WriteEvent(new Telemetry.AwakeNoKeepAwakeEvent()); + Logger.LogInfo($"Expirable keep-awake. Expected expiration date/time: {expireAt} with display on setting set to {keepDisplayOn}."); - CancelExistingThread(); - } - - public static void SetExpirableKeepAwake(DateTimeOffset expireAt, bool keepDisplayOn = true) - { PowerToysTelemetry.Log.WriteEvent(new Telemetry.AwakeExpirableKeepAwakeEvent()); CancelExistingThread(); - if (expireAt > DateTime.Now && expireAt != null) + if (expireAt > DateTimeOffset.Now) { Logger.LogInfo($"Starting expirable log for {expireAt}"); _stateQueue.Add(ComputeAwakeState(keepDisplayOn)); - Observable.Timer(expireAt).Subscribe( + TrayHelper.SetShellIcon(TrayHelper.HiddenWindowHandle, $"{Constants.FullAppName} [{Resources.AWAKE_TRAY_TEXT_EXPIRATION}]", new Icon(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assets/Awake/expirable.ico")), TrayIconAction.Update); + + Observable.Timer(expireAt - DateTimeOffset.Now).Subscribe( _ => { Logger.LogInfo($"Completed expirable keep-awake."); CancelExistingThread(); - - SetPassiveKeepAwakeMode(Constants.AppName); + SetPassiveKeepAwake(); }, _tokenSource.Token); } else { - // The target date is not in the future. Logger.LogError("The specified target date and time is not in the future."); - Logger.LogError($"Current time: {DateTime.Now}\tTarget time: {expireAt}"); + Logger.LogError($"Current time: {DateTimeOffset.Now}\tTarget time: {expireAt}"); + } + + if (IsUsingPowerToysConfig) + { + try + { + var currentSettings = ModuleSettings!.GetSettings(Constants.AppName) ?? new AwakeSettings(); + var settingsChanged = currentSettings.Properties.Mode != AwakeMode.EXPIRABLE || + currentSettings.Properties.ExpirationDateTime != expireAt || + currentSettings.Properties.KeepDisplayOn != keepDisplayOn; + + if (settingsChanged) + { + currentSettings.Properties.Mode = AwakeMode.EXPIRABLE; + currentSettings.Properties.KeepDisplayOn = keepDisplayOn; + currentSettings.Properties.ExpirationDateTime = expireAt; + ModuleSettings!.SaveSettings(JsonSerializer.Serialize(currentSettings), Constants.AppName); + } + } + catch (Exception ex) + { + Logger.LogError($"Failed to handle indefinite keep awake command: {ex.Message}"); + } } } - public static void SetTimedKeepAwake(uint seconds, bool keepDisplayOn = true) + internal static void SetTimedKeepAwake(uint seconds, bool keepDisplayOn = true) { + Logger.LogInfo($"Timed keep-awake. Expected runtime: {seconds} seconds with display on setting set to {keepDisplayOn}."); + PowerToysTelemetry.Log.WriteEvent(new Telemetry.AwakeTimedKeepAwakeEvent()); CancelExistingThread(); Logger.LogInfo($"Timed keep awake started for {seconds} seconds."); - _stateQueue.Add(ComputeAwakeState(keepDisplayOn)); + TrayHelper.SetShellIcon(TrayHelper.HiddenWindowHandle, $"{Constants.FullAppName} [{Resources.AWAKE_TRAY_TEXT_TIMED}]", new Icon(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assets/Awake/timed.ico")), TrayIconAction.Update); + Observable.Timer(TimeSpan.FromSeconds(seconds)).Subscribe( _ => { Logger.LogInfo($"Completed timed thread."); CancelExistingThread(); - - SetPassiveKeepAwakeMode(Constants.AppName); + SetPassiveKeepAwake(); }, _tokenSource.Token); + + if (IsUsingPowerToysConfig) + { + try + { + var currentSettings = ModuleSettings!.GetSettings(Constants.AppName) ?? new AwakeSettings(); + var timeSpan = TimeSpan.FromSeconds(seconds); + var settingsChanged = currentSettings.Properties.Mode != AwakeMode.TIMED || + currentSettings.Properties.IntervalHours != (uint)timeSpan.Hours || + currentSettings.Properties.IntervalMinutes != (uint)timeSpan.Minutes; + + if (settingsChanged) + { + currentSettings.Properties.Mode = AwakeMode.TIMED; + currentSettings.Properties.IntervalHours = (uint)timeSpan.Hours; + currentSettings.Properties.IntervalMinutes = (uint)timeSpan.Minutes; + ModuleSettings!.SaveSettings(JsonSerializer.Serialize(currentSettings), Constants.AppName); + } + } + catch (Exception ex) + { + Logger.LogError($"Failed to handle timed keep awake command: {ex.Message}"); + } + } } + ///

+ /// Performs a clean exit from Awake. + /// + /// Exit code to exit with. + /// Exit signal tracking the state. + /// Determines whether to force exit and post a quitting message. internal static void CompleteExit(int exitCode, ManualResetEvent? exitSignal, bool force = false) { - SetNoKeepAwake(); + SetPassiveKeepAwake(updateSettings: false); - IntPtr windowHandle = GetHiddenWindow(); - - if (windowHandle != IntPtr.Zero) + if (TrayHelper.HiddenWindowHandle != IntPtr.Zero) { - Bridge.SendMessage(windowHandle, Native.Constants.WM_CLOSE, 0, 0); + // Delete the icon. + TrayHelper.SetShellIcon(TrayHelper.HiddenWindowHandle, string.Empty, null, TrayIconAction.Delete); + + // Close the message window that we used for the tray. + Bridge.SendMessage(TrayHelper.HiddenWindowHandle, Native.Constants.WM_CLOSE, 0, 0); } if (force) @@ -213,7 +287,7 @@ namespace Awake.Core try { exitSignal?.Set(); - Bridge.DestroyWindow(windowHandle); + Bridge.DestroyWindow(TrayHelper.HiddenWindowHandle); } catch (Exception ex) { @@ -221,7 +295,11 @@ namespace Awake.Core } } - public static string GetOperatingSystemBuild() + /// + /// Gets the operating system for logging purposes. + /// + /// Returns the string representing the current OS build. + internal static string GetOperatingSystemBuild() { try { @@ -245,83 +323,71 @@ namespace Awake.Core } } - [SuppressMessage("Performance", "CA1806:Do not ignore method results", Justification = "Function returns DWORD value that identifies the current thread, but we do not need it.")] - internal static IEnumerable EnumerateWindowsForProcess(int processId) + /// + /// Generates the default system tray options in situations where no custom options are provided. + /// + /// Returns a dictionary of default Awake timed interval options. + internal static Dictionary GetDefaultTrayOptions() { - var handles = new List(); - var hCurrentWnd = IntPtr.Zero; - - do - { - hCurrentWnd = Bridge.FindWindowEx(IntPtr.Zero, hCurrentWnd, null as string, null); - Bridge.GetWindowThreadProcessId(hCurrentWnd, out uint targetProcessId); - - if (targetProcessId == processId) - { - handles.Add(hCurrentWnd); - } - } - while (hCurrentWnd != IntPtr.Zero); - - return handles; - } - - [SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "In this context, the string is only converted to a hex value.")] - internal static IntPtr GetHiddenWindow() - { - IEnumerable windowHandles = EnumerateWindowsForProcess(Environment.ProcessId); - var domain = AppDomain.CurrentDomain.GetHashCode().ToString("x"); - string targetClass = $"{Constants.TrayWindowId}{domain}"; - - foreach (var handle in windowHandles) - { - StringBuilder className = new(256); - int classQueryResult = Bridge.GetClassName(handle, className, className.Capacity); - if (classQueryResult != 0 && className.ToString().StartsWith(targetClass, StringComparison.InvariantCultureIgnoreCase)) - { - return handle; - } - } - - return IntPtr.Zero; - } - - public static Dictionary GetDefaultTrayOptions() - { - Dictionary optionsList = new Dictionary + Dictionary optionsList = new() { { string.Format(CultureInfo.InvariantCulture, AwakeMinutes, 30), 1800 }, - { Resources.AWAKE_1_HOUR, 3600 }, + { string.Format(CultureInfo.InvariantCulture, AwakeHours, 1), 3600 }, { string.Format(CultureInfo.InvariantCulture, AwakeHours, 2), 7200 }, }; return optionsList; } - public static void SetPassiveKeepAwakeMode(string moduleName) + /// + /// Resets the computer to standard power settings. + /// + /// In certain cases, such as exits, we want to make sure that settings are not reset for the passive mode but rather retained based on previous execution. Default is to save settings, but otherwise it can be overridden. + internal static void SetPassiveKeepAwake(bool updateSettings = true) { - AwakeSettings currentSettings; + Logger.LogInfo($"Operating in passive mode (computer's standard power plan). No custom keep awake settings enabled."); - try - { - currentSettings = ModuleSettings!.GetSettings(moduleName); - } - catch (Exception ex) - { - string? errorString = $"Failed to reset Awake mode GetSettings: {ex.Message}"; - Logger.LogError(errorString); - currentSettings = new AwakeSettings(); - } + PowerToysTelemetry.Log.WriteEvent(new Telemetry.AwakeNoKeepAwakeEvent()); - currentSettings.Properties.Mode = AwakeMode.PASSIVE; + CancelExistingThread(); - try + TrayHelper.SetShellIcon(TrayHelper.HiddenWindowHandle, $"{Constants.FullAppName} [{Resources.AWAKE_TRAY_TEXT_OFF}]", new Icon(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assets/Awake/disabled.ico")), TrayIconAction.Update); + + if (IsUsingPowerToysConfig && updateSettings) { - ModuleSettings!.SaveSettings(JsonSerializer.Serialize(currentSettings), moduleName); + try + { + var currentSettings = ModuleSettings!.GetSettings(Constants.AppName) ?? new AwakeSettings(); + + if (currentSettings.Properties.Mode != AwakeMode.PASSIVE) + { + currentSettings.Properties.Mode = AwakeMode.PASSIVE; + ModuleSettings!.SaveSettings(JsonSerializer.Serialize(currentSettings), Constants.AppName); + } + } + catch (Exception ex) + { + Logger.LogError($"Failed to reset Awake mode: {ex.Message}"); + } } - catch (Exception ex) + } + + /// + /// Sets the display settings. + /// + internal static void SetDisplay() + { + if (IsUsingPowerToysConfig) { - string? errorString = $"Failed to reset Awake mode SaveSettings: {ex.Message}"; - Logger.LogError(errorString); + try + { + var currentSettings = ModuleSettings!.GetSettings(Constants.AppName) ?? new AwakeSettings(); + currentSettings.Properties.KeepDisplayOn = !currentSettings.Properties.KeepDisplayOn; + ModuleSettings!.SaveSettings(JsonSerializer.Serialize(currentSettings), Constants.AppName); + } + catch (Exception ex) + { + Logger.LogError($"Failed to handle display setting command: {ex.Message}"); + } } } } diff --git a/src/modules/awake/Awake/Core/Models/MSG.cs b/src/modules/awake/Awake/Core/Models/MSG.cs new file mode 100644 index 0000000000..88ab499688 --- /dev/null +++ b/src/modules/awake/Awake/Core/Models/MSG.cs @@ -0,0 +1,18 @@ +// 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; + +namespace Awake.Core.Models +{ + internal struct Msg + { + public IntPtr HWnd; + public uint Message; + public IntPtr WParam; + public IntPtr LParam; + public uint Time; + public Point Pt; + } +} diff --git a/src/modules/awake/Awake/Core/Models/MenuInfo.cs b/src/modules/awake/Awake/Core/Models/MenuInfo.cs new file mode 100644 index 0000000000..c47c559591 --- /dev/null +++ b/src/modules/awake/Awake/Core/Models/MenuInfo.cs @@ -0,0 +1,21 @@ +// 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.Runtime.InteropServices; + +namespace Awake.Core.Models +{ + [StructLayout(LayoutKind.Sequential)] + public struct MenuInfo + { + public uint CbSize; // Size of the structure, in bytes + public uint FMask; // Specifies which members of the structure are valid + public uint DwStyle; // Style of the menu + public uint CyMax; // Maximum height of the menu, in pixels + public IntPtr HbrBack; // Handle to the brush used for the menu's background + public uint DwContextHelpID; // Context help ID + public IntPtr DwMenuData; // Pointer to the menu's user data + } +} diff --git a/src/modules/awake/Awake/Core/Models/NOTIFYICONDATA.cs b/src/modules/awake/Awake/Core/Models/NOTIFYICONDATA.cs new file mode 100644 index 0000000000..919d203e9d --- /dev/null +++ b/src/modules/awake/Awake/Core/Models/NOTIFYICONDATA.cs @@ -0,0 +1,22 @@ +// 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.Runtime.InteropServices; + +namespace Awake.Core.Models +{ + [StructLayout(LayoutKind.Sequential)] + public struct NotifyIconData + { + public int CbSize; + public IntPtr HWnd; + public int UId; + public int UFlags; + public int UCallbackMessage; + public IntPtr HIcon; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] + public string SzTip; + } +} diff --git a/src/modules/awake/Awake/Core/Models/POINT.cs b/src/modules/awake/Awake/Core/Models/POINT.cs new file mode 100644 index 0000000000..ec3da1ce26 --- /dev/null +++ b/src/modules/awake/Awake/Core/Models/POINT.cs @@ -0,0 +1,15 @@ +// 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.Runtime.InteropServices; + +namespace Awake.Core.Models +{ + [StructLayout(LayoutKind.Sequential)] + public struct Point + { + public int X; + public int Y; + } +} diff --git a/src/modules/awake/Awake/Core/Models/SingleThreadSynchronizationContext.cs b/src/modules/awake/Awake/Core/Models/SingleThreadSynchronizationContext.cs new file mode 100644 index 0000000000..e2ef3f92c4 --- /dev/null +++ b/src/modules/awake/Awake/Core/Models/SingleThreadSynchronizationContext.cs @@ -0,0 +1,62 @@ +// 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.Collections.Generic; +using System.Threading; + +namespace Awake.Core.Models +{ + internal sealed class SingleThreadSynchronizationContext : SynchronizationContext + { + private readonly Queue> queue = + new(); + +#pragma warning disable CS8765 // Nullability of type of parameter doesn't match overridden member (possibly because of nullability attributes). + public override void Post(SendOrPostCallback d, object state) +#pragma warning restore CS8765 // Nullability of type of parameter doesn't match overridden member (possibly because of nullability attributes). + { + lock (queue) + { + queue.Enqueue(Tuple.Create(d, state)); + Monitor.Pulse(queue); + } + } + + public void BeginMessageLoop() + { + while (true) + { + Tuple work; + lock (queue) + { + while (queue.Count == 0) + { + Monitor.Wait(queue); + } + + work = queue.Dequeue(); + } + + if (work == null) + { + break; + } + + work.Item1(work.Item2); + } + } + + public void EndMessageLoop() + { + lock (queue) + { +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. + queue.Enqueue(null); // Signal the end of the message loop +#pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference type. + Monitor.Pulse(queue); + } + } + } +} diff --git a/src/modules/awake/Awake/Core/Models/TrayCommands.cs b/src/modules/awake/Awake/Core/Models/TrayCommands.cs index 7a266a93ea..b33873e51c 100644 --- a/src/modules/awake/Awake/Core/Models/TrayCommands.cs +++ b/src/modules/awake/Awake/Core/Models/TrayCommands.cs @@ -6,11 +6,11 @@ namespace Awake.Core.Models { internal enum TrayCommands : uint { - TC_DISPLAY_SETTING = Native.Constants.WM_USER + 1, - TC_MODE_PASSIVE = Native.Constants.WM_USER + 2, - TC_MODE_INDEFINITE = Native.Constants.WM_USER + 3, - TC_MODE_EXPIRABLE = Native.Constants.WM_USER + 4, - TC_EXIT = Native.Constants.WM_USER + 100, - TC_TIME = Native.Constants.WM_USER + 101, + TC_DISPLAY_SETTING = Native.Constants.WM_USER + 0x2, + TC_MODE_PASSIVE = Native.Constants.WM_USER + 0x3, + TC_MODE_INDEFINITE = Native.Constants.WM_USER + 0x4, + TC_MODE_EXPIRABLE = Native.Constants.WM_USER + 0x5, + TC_EXIT = Native.Constants.WM_USER + 0x64, + TC_TIME = Native.Constants.WM_USER + 0x65, } } diff --git a/src/modules/awake/Awake/Core/Models/TrayIconAction.cs b/src/modules/awake/Awake/Core/Models/TrayIconAction.cs new file mode 100644 index 0000000000..49faf233bd --- /dev/null +++ b/src/modules/awake/Awake/Core/Models/TrayIconAction.cs @@ -0,0 +1,13 @@ +// 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 Awake.Core.Models +{ + internal enum TrayIconAction + { + Add, + Update, + Delete, + } +} diff --git a/src/modules/awake/Awake/Core/Models/WNDCLASSEX.cs b/src/modules/awake/Awake/Core/Models/WNDCLASSEX.cs new file mode 100644 index 0000000000..f84cb53ee0 --- /dev/null +++ b/src/modules/awake/Awake/Core/Models/WNDCLASSEX.cs @@ -0,0 +1,26 @@ +// 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.Runtime.InteropServices; + +namespace Awake.Core.Models +{ + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + internal struct WndClassEx + { + public uint CbSize; + public uint Style; + public IntPtr LpfnWndProc; + public int CbClsExtra; + public int CbWndExtra; + public IntPtr HInstance; + public IntPtr HIcon; + public IntPtr HCursor; + public IntPtr HbrBackground; + public string LpszMenuName; + public string LpszClassName; + public IntPtr HIconSm; + } +} diff --git a/src/modules/awake/Awake/Core/Native/Bridge.cs b/src/modules/awake/Awake/Core/Native/Bridge.cs index 27eb5578d5..2fc2864dec 100644 --- a/src/modules/awake/Awake/Core/Native/Bridge.cs +++ b/src/modules/awake/Awake/Core/Native/Bridge.cs @@ -5,14 +5,14 @@ using System; using System.IO; using System.Runtime.InteropServices; -using System.Text; using Awake.Core.Models; namespace Awake.Core.Native { internal sealed class Bridge { - internal delegate bool EnumThreadDelegate(IntPtr hWnd, IntPtr lParam); + [UnmanagedFunctionPointer(CallingConvention.Winapi, SetLastError = true)] + internal delegate int WndProcDelegate(IntPtr hWnd, uint message, IntPtr wParam, IntPtr lParam); [DllImport("Powrprof.dll", SetLastError = true)] internal static extern bool GetPwrCapabilities(out SystemPowerCapabilities lpSystemPowerCapabilities); @@ -30,9 +30,6 @@ namespace Awake.Core.Native [DllImport("kernel32.dll", SetLastError = true)] internal static extern bool SetStdHandle(int nStdHandle, IntPtr hHandle); - [DllImport("kernel32.dll", SetLastError = true)] - internal static extern uint GetCurrentThreadId(); - [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] internal static extern IntPtr CreateFile( [MarshalAs(UnmanagedType.LPWStr)] string filename, @@ -50,25 +47,13 @@ namespace Awake.Core.Native internal static extern bool InsertMenu(IntPtr hMenu, uint uPosition, uint uFlags, uint uIDNewItem, string lpNewItem); [DllImport("user32.dll", SetLastError = true)] - internal static extern bool TrackPopupMenuEx(IntPtr hmenu, uint fuFlags, int x, int y, IntPtr hwnd, IntPtr lptpm); - - [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] - internal static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount); - - [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] - internal static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr hWndChildAfter, string? className, string? windowTitle); - - [DllImport("user32.dll", SetLastError = true)] - internal static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId); - - [DllImport("user32.dll", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool SetForegroundWindow(IntPtr hWnd); + public static extern bool TrackPopupMenuEx(IntPtr hMenu, uint uFlags, int x, int y, IntPtr hWnd, IntPtr lptpm); [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] internal static extern IntPtr SendMessage(IntPtr hWnd, uint msg, nuint wParam, nint lParam); [DllImport("user32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool DestroyMenu(IntPtr hMenu); [DllImport("user32.dll")] @@ -76,5 +61,46 @@ namespace Awake.Core.Native [DllImport("user32.dll")] internal static extern void PostQuitMessage(int nExitCode); + + [DllImport("shell32.dll")] + internal static extern bool Shell_NotifyIcon(int dwMessage, ref NotifyIconData pnid); + + [DllImport("user32.dll", SetLastError = true)] + internal static extern bool TranslateMessage(ref Msg lpMsg); + + [DllImport("user32.dll", SetLastError = true)] + internal static extern IntPtr DispatchMessage(ref Msg lpMsg); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + internal static extern IntPtr RegisterClassEx(ref WndClassEx lpwcx); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + internal static extern IntPtr CreateWindowEx(uint dwExStyle, string lpClassName, string lpWindowName, uint dwStyle, int x, int y, int nWidth, int nHeight, IntPtr hWndParent, IntPtr hMenu, IntPtr hInstance, IntPtr lpParam); + + [DllImport("user32.dll", SetLastError = true)] + internal static extern int DefWindowProc(IntPtr hWnd, uint message, IntPtr wParam, IntPtr lParam); + + [DllImport("user32.dll", SetLastError = true)] + internal static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); + + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool GetCursorPos(out Point lpPoint); + + [DllImport("user32.dll")] + internal static extern bool ScreenToClient(IntPtr hWnd, ref Point lpPoint); + + [DllImport("user32.dll")] + internal static extern bool GetMessage(out Msg lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax); + + [DllImport("user32.dll", SetLastError = true)] + internal static extern bool UpdateWindow(IntPtr hWnd); + + [DllImport("user32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool SetMenuInfo(IntPtr hMenu, ref MenuInfo lpcmi); + + [DllImport("user32.dll")] + internal static extern bool SetForegroundWindow(IntPtr hWnd); } } diff --git a/src/modules/awake/Awake/Core/Native/Constants.cs b/src/modules/awake/Awake/Core/Native/Constants.cs index 2c512864f6..ca24ef43bf 100644 --- a/src/modules/awake/Awake/Core/Native/Constants.cs +++ b/src/modules/awake/Awake/Core/Native/Constants.cs @@ -7,26 +7,46 @@ namespace Awake.Core.Native [System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1310:Field names should not contain underscore", Justification = "Win32 API convention.")] internal sealed class Constants { - internal const uint WM_COMMAND = 0x111; - internal const uint WM_USER = 0x400; - internal const uint WM_GETTEXT = 0x000D; + // Window Messages + internal const uint WM_COMMAND = 0x0111; + internal const uint WM_USER = 0x0400U; internal const uint WM_CLOSE = 0x0010; + internal const int WM_DESTROY = 0x0002; + internal const int WM_LBUTTONDOWN = 0x0201; + internal const int WM_RBUTTONDOWN = 0x0204; - // Popup menu constants. + // Menu Flags internal const uint MF_BYPOSITION = 1024; internal const uint MF_STRING = 0; - internal const uint MF_MENUBREAK = 0x00000040; internal const uint MF_SEPARATOR = 0x00000800; internal const uint MF_POPUP = 0x00000010; internal const uint MF_UNCHECKED = 0x00000000; internal const uint MF_CHECKED = 0x00000008; - internal const uint MF_OWNERDRAW = 0x00000100; - internal const uint MF_ENABLED = 0x00000000; internal const uint MF_DISABLED = 0x00000002; + // Standard Handles internal const int STD_OUTPUT_HANDLE = -11; + + // Generic Access Rights internal const uint GENERIC_WRITE = 0x40000000; internal const uint GENERIC_READ = 0x80000000; + + // Notification Icons + internal const int NIF_ICON = 0x00000002; + internal const int NIF_MESSAGE = 0x00000001; + internal const int NIF_TIP = 0x00000004; + internal const int NIM_ADD = 0x00000000; + internal const int NIM_DELETE = 0x00000002; + internal const int NIM_MODIFY = 0x00000001; + + // Track Popup Menu Flags + internal const uint TPM_LEFT_ALIGN = 0x0000; + internal const uint TPM_BOTTOMALIGN = 0x0020; + internal const uint TPM_LEFT_BUTTON = 0x0000; + + // Menu Item Info Flags + internal const uint MNS_AUTO_DISMISS = 0x10000000; + internal const uint MIM_STYLE = 0x00000010; } } diff --git a/src/modules/awake/Awake/Core/TrayHelper.cs b/src/modules/awake/Awake/Core/TrayHelper.cs index ef6794ecfb..eff05e7c5b 100644 --- a/src/modules/awake/Awake/Core/TrayHelper.cs +++ b/src/modules/awake/Awake/Core/TrayHelper.cs @@ -4,12 +4,12 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Drawing; using System.Linq; -using System.Text.RegularExpressions; +using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; -using System.Windows.Forms; using Awake.Core.Models; using Awake.Core.Native; using Awake.Properties; @@ -27,147 +27,348 @@ namespace Awake.Core /// internal static class TrayHelper { + private static NotifyIconData _notifyIconData; + private static ManualResetEvent? _exitSignal; + private static IntPtr _trayMenu; private static IntPtr TrayMenu { get => _trayMenu; set => _trayMenu = value; } - private static NotifyIcon TrayIcon { get; set; } + private static IntPtr _hiddenWindowHandle; + + internal static IntPtr HiddenWindowHandle { get => _hiddenWindowHandle; private set => _hiddenWindowHandle = value; } static TrayHelper() { - TrayIcon = new NotifyIcon(); + TrayMenu = IntPtr.Zero; + HiddenWindowHandle = IntPtr.Zero; } - public static void InitializeTray(string text, Icon icon, ManualResetEvent? exitSignal, ContextMenuStrip? contextMenu = null) + public static void InitializeTray(string text, Icon icon, ManualResetEvent? exitSignal) { - Task.Factory.StartNew( - (tray) => - { - try - { - Logger.LogInfo("Setting up the tray."); - if (tray != null) - { - ((NotifyIcon)tray).Text = text; - ((NotifyIcon)tray).Icon = icon; - ((NotifyIcon)tray).ContextMenuStrip = contextMenu; - ((NotifyIcon)tray).Visible = true; - ((NotifyIcon)tray).MouseClick += TrayClickHandler; - Application.AddMessageFilter(new TrayMessageFilter(exitSignal)); - Application.Run(); - Logger.LogInfo("Tray setup complete."); - } - } - catch (Exception ex) - { - Logger.LogError($"An error occurred initializing the tray. {ex.Message}"); - Logger.LogError($"{ex.StackTrace}"); - } - }, - TrayIcon); + _exitSignal = exitSignal; + + CreateHiddenWindow(icon, text); } - /// - /// Function used to construct the context menu in the tray natively. - /// - /// - /// We need to use the Windows API here instead of the common control exposed - /// by NotifyIcon because the one that is built into the Windows Forms stack - /// hasn't been updated in a while and is looking like Office XP. That introduces - /// scalability and coloring changes on any OS past Windows XP. - /// - /// The sender that triggers the handler. - /// MouseEventArgs instance containing mouse click event information. - private static void TrayClickHandler(object? sender, MouseEventArgs e) + private static void ShowContextMenu(IntPtr hWnd) { - IntPtr windowHandle = Manager.GetHiddenWindow(); + Bridge.SetForegroundWindow(hWnd); - if (windowHandle != IntPtr.Zero) + // Get the handle to the context menu associated with the tray icon + IntPtr hMenu = TrayMenu; + + // Get the current cursor position + Bridge.GetCursorPos(out Models.Point cursorPos); + + Bridge.ScreenToClient(hWnd, ref cursorPos); + + MenuInfo menuInfo = new() { - Bridge.SetForegroundWindow(windowHandle); - Bridge.TrackPopupMenuEx(TrayMenu, 0, Cursor.Position.X, Cursor.Position.Y, windowHandle, IntPtr.Zero); + CbSize = (uint)Marshal.SizeOf(typeof(MenuInfo)), + FMask = Native.Constants.MIM_STYLE, + DwStyle = Native.Constants.MNS_AUTO_DISMISS, + }; + Bridge.SetMenuInfo(hMenu, ref menuInfo); + + // Display the context menu at the cursor position + Bridge.TrackPopupMenuEx( + hMenu, + Native.Constants.TPM_LEFT_ALIGN | Native.Constants.TPM_BOTTOMALIGN | Native.Constants.TPM_LEFT_BUTTON, + cursorPos.X, + cursorPos.Y, + hWnd, + IntPtr.Zero); + } + + private static void CreateHiddenWindow(Icon icon, string text) + { + IntPtr hWnd = IntPtr.Zero; + + // Start the message loop asynchronously + Task.Run(() => + { + RunOnMainThread(() => + { + WndClassEx wcex = new() + { + CbSize = (uint)Marshal.SizeOf(typeof(WndClassEx)), + Style = 0, + LpfnWndProc = Marshal.GetFunctionPointerForDelegate(WndProc), + CbClsExtra = 0, + CbWndExtra = 0, + HInstance = Marshal.GetHINSTANCE(typeof(Program).Module), + HIcon = IntPtr.Zero, + HCursor = IntPtr.Zero, + HbrBackground = IntPtr.Zero, + LpszMenuName = string.Empty, + LpszClassName = Constants.TrayWindowId, + HIconSm = IntPtr.Zero, + }; + + Bridge.RegisterClassEx(ref wcex); + + hWnd = Bridge.CreateWindowEx( + 0, + Constants.TrayWindowId, + text, + 0x00CF0000 | 0x00000001 | 0x00000008, // WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_MINIMIZEBOX + 0, + 0, + 0, + 0, + unchecked(-3), + IntPtr.Zero, + Marshal.GetHINSTANCE(typeof(Program).Module), + IntPtr.Zero); + + if (hWnd == IntPtr.Zero) + { + int errorCode = Marshal.GetLastWin32Error(); + throw new Win32Exception(errorCode, "Failed to add tray icon. Error code: " + errorCode); + } + + // Keep this as a reference because we will need it when we update + // the tray icon in the future. + HiddenWindowHandle = hWnd; + + Bridge.ShowWindow(hWnd, 0); // SW_HIDE + Bridge.UpdateWindow(hWnd); + + SetShellIcon(hWnd, text, icon); + + RunMessageLoop(); + }); + }); + } + + internal static void SetShellIcon(IntPtr hWnd, string text, Icon? icon, TrayIconAction action = TrayIconAction.Add) + { + int message = Native.Constants.NIM_ADD; + + switch (action) + { + case TrayIconAction.Update: + message = Native.Constants.NIM_MODIFY; + break; + case TrayIconAction.Delete: + message = Native.Constants.NIM_DELETE; + break; + case TrayIconAction.Add: + default: + break; + } + + _notifyIconData = action == TrayIconAction.Add || action == TrayIconAction.Update + ? new NotifyIconData + { + CbSize = Marshal.SizeOf(typeof(NotifyIconData)), + HWnd = hWnd, + UId = 1000, + UFlags = Native.Constants.NIF_ICON | Native.Constants.NIF_TIP | Native.Constants.NIF_MESSAGE, + UCallbackMessage = (int)Native.Constants.WM_USER, + HIcon = icon!.Handle, + SzTip = text, + } + : new NotifyIconData + { + CbSize = Marshal.SizeOf(typeof(NotifyIconData)), + HWnd = hWnd, + UId = 1000, + UFlags = 0, + }; + + if (!Bridge.Shell_NotifyIcon(message, ref _notifyIconData)) + { + int errorCode = Marshal.GetLastWin32Error(); + throw new Win32Exception(errorCode, $"Failed to change tray icon. Action: {action} and error code: {errorCode}"); } } - internal static void SetTray(string text, AwakeSettings settings, bool startedFromPowerToys) + private static void RunMessageLoop() + { + while (Bridge.GetMessage(out Msg msg, IntPtr.Zero, 0, 0)) + { + Bridge.TranslateMessage(ref msg); + Bridge.DispatchMessage(ref msg); + } + } + + private static int WndProc(IntPtr hWnd, uint message, IntPtr wParam, IntPtr lParam) + { + switch (message) + { + case Native.Constants.WM_USER: + if (lParam == (IntPtr)Native.Constants.WM_LBUTTONDOWN || lParam == (IntPtr)Native.Constants.WM_RBUTTONDOWN) + { + // Show the context menu associated with the tray icon + ShowContextMenu(hWnd); + } + + break; + case Native.Constants.WM_DESTROY: + // Clean up resources when the window is destroyed + Bridge.PostQuitMessage(0); + break; + case Native.Constants.WM_COMMAND: + int trayCommandsSize = Enum.GetNames(typeof(TrayCommands)).Length; + + long targetCommandIndex = wParam.ToInt64() & 0xFFFF; + + switch (targetCommandIndex) + { + case (uint)TrayCommands.TC_EXIT: + Manager.CompleteExit(0, _exitSignal, true); + break; + case (uint)TrayCommands.TC_DISPLAY_SETTING: + Manager.SetDisplay(); + break; + case (uint)TrayCommands.TC_MODE_INDEFINITE: + Manager.SetIndefiniteKeepAwake(); + break; + case (uint)TrayCommands.TC_MODE_PASSIVE: + Manager.SetPassiveKeepAwake(); + break; + default: + if (targetCommandIndex >= trayCommandsSize) + { + AwakeSettings settings = Manager.ModuleSettings!.GetSettings(Constants.AppName); + if (settings.Properties.CustomTrayTimes.Count == 0) + { + settings.Properties.CustomTrayTimes.AddRange(Manager.GetDefaultTrayOptions()); + } + + int index = (int)targetCommandIndex - (int)TrayCommands.TC_TIME; + uint targetTime = (uint)settings.Properties.CustomTrayTimes.ElementAt(index).Value; + Manager.SetTimedKeepAwake(targetTime); + } + + break; + } + + break; + default: + // Let the default window procedure handle other messages + return Bridge.DefWindowProc(hWnd, message, wParam, lParam); + } + + return Bridge.DefWindowProc(hWnd, message, wParam, lParam); + } + + internal static void RunOnMainThread(Action action) + { + var syncContext = new SingleThreadSynchronizationContext(); + SynchronizationContext.SetSynchronizationContext(syncContext); + +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. + syncContext.Post( + _ => + { + try + { + action(); + } + catch (Exception e) + { + Console.WriteLine("Error: " + e.Message); + } + finally + { + syncContext.EndMessageLoop(); + } + }, + null); +#pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference type. + + syncContext.BeginMessageLoop(); + } + + internal static void SetTray(AwakeSettings settings, bool startedFromPowerToys) { SetTray( - text, settings.Properties.KeepDisplayOn, settings.Properties.Mode, settings.Properties.CustomTrayTimes, startedFromPowerToys); } - public static void SetTray(string text, bool keepDisplayOn, AwakeMode mode, Dictionary trayTimeShortcuts, bool startedFromPowerToys) + public static void SetTray(bool keepDisplayOn, AwakeMode mode, Dictionary trayTimeShortcuts, bool startedFromPowerToys) { - if (TrayMenu != IntPtr.Zero) - { - var destructionStatus = Bridge.DestroyMenu(TrayMenu); - if (destructionStatus != true) - { - Logger.LogError("Failed to destroy menu."); - } - } + ClearExistingTrayMenu(); + CreateNewTrayMenu(startedFromPowerToys, keepDisplayOn, mode); + InsertAwakeModeMenuItems(mode); + + EnsureDefaultTrayTimeShortcuts(trayTimeShortcuts); + CreateAwakeTimeSubMenu(trayTimeShortcuts); + } + + private static void ClearExistingTrayMenu() + { + if (TrayMenu != IntPtr.Zero && !Bridge.DestroyMenu(TrayMenu)) + { + int errorCode = Marshal.GetLastWin32Error(); + Logger.LogError($"Failed to destroy menu: {errorCode}"); + } + } + + private static void CreateNewTrayMenu(bool startedFromPowerToys, bool keepDisplayOn, AwakeMode mode) + { TrayMenu = Bridge.CreatePopupMenu(); - - if (TrayMenu != IntPtr.Zero) + if (TrayMenu == IntPtr.Zero) { - if (!startedFromPowerToys) - { - // If Awake is started from PowerToys, the correct way to exit it is disabling it from Settings. - Bridge.InsertMenu(TrayMenu, 0, Native.Constants.MF_BYPOSITION | Native.Constants.MF_STRING, (uint)TrayCommands.TC_EXIT, Resources.AWAKE_EXIT); - Bridge.InsertMenu(TrayMenu, 0, Native.Constants.MF_BYPOSITION | Native.Constants.MF_SEPARATOR, 0, string.Empty); - } - - Bridge.InsertMenu(TrayMenu, 0, Native.Constants.MF_BYPOSITION | Native.Constants.MF_STRING | (keepDisplayOn ? Native.Constants.MF_CHECKED : Native.Constants.MF_UNCHECKED) | (mode == AwakeMode.PASSIVE ? Native.Constants.MF_DISABLED : Native.Constants.MF_ENABLED), (uint)TrayCommands.TC_DISPLAY_SETTING, Resources.AWAKE_KEEP_SCREEN_ON); + return; } - // In case there are no tray shortcuts defined for the application default to a - // reasonable initial set. + if (!startedFromPowerToys) + { + InsertMenuItem(0, TrayCommands.TC_EXIT, Resources.AWAKE_EXIT); + } + + InsertMenuItem(0, TrayCommands.TC_DISPLAY_SETTING, Resources.AWAKE_KEEP_SCREEN_ON, keepDisplayOn, mode == AwakeMode.PASSIVE); + InsertSeparator(1); + } + + private static void InsertMenuItem(int position, TrayCommands command, string text, bool checkedState = false, bool disabled = false) + { + uint state = Native.Constants.MF_BYPOSITION | Native.Constants.MF_STRING; + state |= checkedState ? Native.Constants.MF_CHECKED : Native.Constants.MF_UNCHECKED; + state |= disabled ? Native.Constants.MF_DISABLED : Native.Constants.MF_ENABLED; + + Bridge.InsertMenu(TrayMenu, (uint)position, state, (uint)command, text); + } + + private static void InsertSeparator(int position) + { + Bridge.InsertMenu(TrayMenu, (uint)position, Native.Constants.MF_BYPOSITION | Native.Constants.MF_SEPARATOR, 0, string.Empty); + } + + private static void EnsureDefaultTrayTimeShortcuts(Dictionary trayTimeShortcuts) + { if (trayTimeShortcuts.Count == 0) { trayTimeShortcuts.AddRange(Manager.GetDefaultTrayOptions()); } + } + private static void CreateAwakeTimeSubMenu(Dictionary trayTimeShortcuts) + { var awakeTimeMenu = Bridge.CreatePopupMenu(); for (int i = 0; i < trayTimeShortcuts.Count; i++) { Bridge.InsertMenu(awakeTimeMenu, (uint)i, Native.Constants.MF_BYPOSITION | Native.Constants.MF_STRING, (uint)TrayCommands.TC_TIME + (uint)i, trayTimeShortcuts.ElementAt(i).Key); } - Bridge.InsertMenu(TrayMenu, 0, Native.Constants.MF_BYPOSITION | Native.Constants.MF_SEPARATOR, 0, string.Empty); - - Bridge.InsertMenu(TrayMenu, 0, Native.Constants.MF_BYPOSITION | Native.Constants.MF_STRING | (mode == AwakeMode.PASSIVE ? Native.Constants.MF_CHECKED : Native.Constants.MF_UNCHECKED), (uint)TrayCommands.TC_MODE_PASSIVE, Resources.AWAKE_OFF); - Bridge.InsertMenu(TrayMenu, 0, Native.Constants.MF_BYPOSITION | Native.Constants.MF_STRING | (mode == AwakeMode.INDEFINITE ? Native.Constants.MF_CHECKED : Native.Constants.MF_UNCHECKED), (uint)TrayCommands.TC_MODE_INDEFINITE, Resources.AWAKE_KEEP_INDEFINITELY); - Bridge.InsertMenu(TrayMenu, 0, Native.Constants.MF_BYPOSITION | Native.Constants.MF_POPUP | (mode == AwakeMode.TIMED ? Native.Constants.MF_CHECKED : Native.Constants.MF_UNCHECKED), (uint)awakeTimeMenu, Resources.AWAKE_KEEP_ON_INTERVAL); - Bridge.InsertMenu(TrayMenu, 0, Native.Constants.MF_BYPOSITION | Native.Constants.MF_STRING | Native.Constants.MF_DISABLED | (mode == AwakeMode.EXPIRABLE ? Native.Constants.MF_CHECKED : Native.Constants.MF_UNCHECKED), (uint)TrayCommands.TC_MODE_EXPIRABLE, Resources.AWAKE_KEEP_UNTIL_EXPIRATION); - - TrayIcon.Text = text; + Bridge.InsertMenu(TrayMenu, 0, Native.Constants.MF_BYPOSITION | Native.Constants.MF_POPUP, (uint)awakeTimeMenu, Resources.AWAKE_KEEP_ON_INTERVAL); } - private sealed class CheckButtonToolStripMenuItemAccessibleObject : ToolStripItem.ToolStripItemAccessibleObject + private static void InsertAwakeModeMenuItems(AwakeMode mode) { - private readonly CheckButtonToolStripMenuItem _menuItem; + InsertSeparator(0); - public CheckButtonToolStripMenuItemAccessibleObject(CheckButtonToolStripMenuItem menuItem) - : base(menuItem) - { - _menuItem = menuItem; - } - - public override AccessibleRole Role => AccessibleRole.CheckButton; - - public override string Name => _menuItem.Text + ", " + Role + ", " + (_menuItem.Checked ? Resources.AWAKE_CHECKED : Resources.AWAKE_UNCHECKED); - } - - private sealed class CheckButtonToolStripMenuItem : ToolStripMenuItem - { - protected override AccessibleObject CreateAccessibilityInstance() - { - return new CheckButtonToolStripMenuItemAccessibleObject(this); - } + InsertMenuItem(0, TrayCommands.TC_MODE_PASSIVE, Resources.AWAKE_OFF, mode == AwakeMode.PASSIVE); + InsertMenuItem(0, TrayCommands.TC_MODE_INDEFINITE, Resources.AWAKE_KEEP_INDEFINITELY, mode == AwakeMode.INDEFINITE); + InsertMenuItem(0, TrayCommands.TC_MODE_EXPIRABLE, Resources.AWAKE_KEEP_UNTIL_EXPIRATION, mode == AwakeMode.EXPIRABLE, true); } } } diff --git a/src/modules/awake/Awake/Core/TrayMessageFilter.cs b/src/modules/awake/Awake/Core/TrayMessageFilter.cs deleted file mode 100644 index ecb3def337..0000000000 --- a/src/modules/awake/Awake/Core/TrayMessageFilter.cs +++ /dev/null @@ -1,172 +0,0 @@ -// 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 System.Linq; -using System.Text.Json; -using System.Threading; -using System.Windows.Forms; -using Awake.Core.Models; -using ManagedCommon; -using Microsoft.PowerToys.Settings.UI.Library; - -namespace Awake.Core -{ - public class TrayMessageFilter : IMessageFilter - { - private static SettingsUtils? _moduleSettings; - - private static SettingsUtils? ModuleSettings { get => _moduleSettings; set => _moduleSettings = value; } - - private static ManualResetEvent? _exitSignal; - - public TrayMessageFilter(ManualResetEvent? exitSignal) - { - _exitSignal = exitSignal; - ModuleSettings = new SettingsUtils(); - } - - public bool PreFilterMessage(ref Message m) - { - var trayCommandsSize = Enum.GetNames(typeof(TrayCommands)).Length; - - switch (m.Msg) - { - case (int)Native.Constants.WM_COMMAND: - var targetCommandIndex = m.WParam.ToInt64() & 0xFFFF; - switch (targetCommandIndex) - { - case (long)TrayCommands.TC_EXIT: - ExitCommandHandler(_exitSignal); - break; - case (long)TrayCommands.TC_DISPLAY_SETTING: - DisplaySettingCommandHandler(Constants.AppName); - break; - case (long)TrayCommands.TC_MODE_INDEFINITE: - IndefiniteKeepAwakeCommandHandler(Constants.AppName); - break; - case (long)TrayCommands.TC_MODE_PASSIVE: - PassiveKeepAwakeCommandHandler(Constants.AppName); - break; - case var _ when targetCommandIndex >= trayCommandsSize: - // Format for the timer block: - // TrayCommands.TC_TIME + ZERO_BASED_INDEX_IN_SETTINGS - AwakeSettings settings = ModuleSettings!.GetSettings(Constants.AppName); - if (settings.Properties.CustomTrayTimes.Count == 0) - { - settings.Properties.CustomTrayTimes.AddRange(Manager.GetDefaultTrayOptions()); - } - - int index = (int)targetCommandIndex - (int)TrayCommands.TC_TIME; - var targetTime = settings.Properties.CustomTrayTimes.ElementAt(index).Value; - TimedKeepAwakeCommandHandler(Constants.AppName, targetTime); - break; - } - - break; - } - - return false; - } - - private static void ExitCommandHandler(ManualResetEvent? exitSignal) - { - Manager.CompleteExit(0, exitSignal, true); - } - - private static void DisplaySettingCommandHandler(string moduleName) - { - AwakeSettings currentSettings; - - try - { - currentSettings = ModuleSettings!.GetSettings(moduleName); - } - catch (Exception ex) - { - string? errorString = $"Failed GetSettings: {ex.Message}"; - Logger.LogError(errorString); - currentSettings = new AwakeSettings(); - } - - currentSettings.Properties.KeepDisplayOn = !currentSettings.Properties.KeepDisplayOn; - - try - { - ModuleSettings!.SaveSettings(JsonSerializer.Serialize(currentSettings), moduleName); - } - catch (Exception ex) - { - string? errorString = $"Failed SaveSettings: {ex.Message}"; - Logger.LogError(errorString); - } - } - - private static void TimedKeepAwakeCommandHandler(string moduleName, int seconds) - { - TimeSpan timeSpan = TimeSpan.FromSeconds(seconds); - - AwakeSettings currentSettings; - - try - { - currentSettings = ModuleSettings!.GetSettings(moduleName); - } - catch (Exception ex) - { - string? errorString = $"Failed GetSettings: {ex.Message}"; - Logger.LogError(errorString); - currentSettings = new AwakeSettings(); - } - - currentSettings.Properties.Mode = AwakeMode.TIMED; - currentSettings.Properties.IntervalHours = (uint)timeSpan.Hours; - currentSettings.Properties.IntervalMinutes = (uint)timeSpan.Minutes; - - try - { - ModuleSettings!.SaveSettings(JsonSerializer.Serialize(currentSettings), moduleName); - } - catch (Exception ex) - { - string? errorString = $"Failed SaveSettings: {ex.Message}"; - Logger.LogError(errorString); - } - } - - private static void PassiveKeepAwakeCommandHandler(string moduleName) - { - Manager.SetPassiveKeepAwakeMode(moduleName); - } - - private static void IndefiniteKeepAwakeCommandHandler(string moduleName) - { - AwakeSettings currentSettings; - - try - { - currentSettings = ModuleSettings!.GetSettings(moduleName); - } - catch (Exception ex) - { - string? errorString = $"Failed GetSettings: {ex.Message}"; - Logger.LogError(errorString); - currentSettings = new AwakeSettings(); - } - - currentSettings.Properties.Mode = AwakeMode.INDEFINITE; - - try - { - ModuleSettings!.SaveSettings(JsonSerializer.Serialize(currentSettings), moduleName); - } - catch (Exception ex) - { - string? errorString = $"Failed SaveSettings: {ex.Message}"; - Logger.LogError(errorString); - } - } - } -} diff --git a/src/modules/awake/Awake/Program.cs b/src/modules/awake/Awake/Program.cs index 2baab45c29..09a660a350 100644 --- a/src/modules/awake/Awake/Program.cs +++ b/src/modules/awake/Awake/Program.cs @@ -18,6 +18,7 @@ using System.Threading.Tasks; using Awake.Core; using Awake.Core.Models; using Awake.Core.Native; +using Awake.Properties; using ManagedCommon; using Microsoft.PowerToys.Settings.UI.Library; @@ -25,13 +26,7 @@ namespace Awake { internal sealed class Program { - // PowerToys Awake build code name. Used for exact logging - // that does not map to PowerToys broad version schema to pinpoint - // internal issues easier. - // Format of the build ID is: CODENAME_MMDDYYYY, where MMDDYYYY - // is representative of the date when the last change was made before - // the pull request is issued. - private static readonly string BuildId = "ATRIOX_04132023"; + private static readonly ManualResetEvent _exitSignal = new(false); private static Mutex? _mutex; private static FileSystemWatcher? _watcher; @@ -46,12 +41,11 @@ namespace Awake private static SystemPowerCapabilities _powerCapabilities; #pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. - private static ManualResetEvent _exitSignal = new ManualResetEvent(false); - internal static readonly string[] AliasesConfigOption = new[] { "--use-pt-config", "-c" }; - internal static readonly string[] AliasesDisplayOption = new[] { "--display-on", "-d" }; - internal static readonly string[] AliasesTimeOption = new[] { "--time-limit", "-t" }; - internal static readonly string[] AliasesPidOption = new[] { "--pid", "-p" }; - internal static readonly string[] AliasesExpireAtOption = new[] { "--expire-at", "-e" }; + internal static readonly string[] AliasesConfigOption = ["--use-pt-config", "-c"]; + internal static readonly string[] AliasesDisplayOption = ["--display-on", "-d"]; + internal static readonly string[] AliasesTimeOption = ["--time-limit", "-t"]; + internal static readonly string[] AliasesPidOption = ["--pid", "-p"]; + internal static readonly string[] AliasesExpireAtOption = ["--expire-at", "-e"]; private static int Main(string[] args) { @@ -73,7 +67,7 @@ namespace Awake Logger.LogInfo($"Launching {Core.Constants.AppName}..."); Logger.LogInfo(FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).FileVersion); - Logger.LogInfo($"Build: {BuildId}"); + Logger.LogInfo($"Build: {Core.Constants.BuildId}"); Logger.LogInfo($"OS: {Environment.OSVersion}"); Logger.LogInfo($"OS Build: {Manager.GetOperatingSystemBuild()}"); @@ -90,69 +84,47 @@ namespace Awake Logger.LogInfo("Parsing parameters..."); - Option configOption = new( - aliases: AliasesConfigOption, - getDefaultValue: () => false, - description: $"Specifies whether {Core.Constants.AppName} will be using the PowerToys configuration file for managing the state.") + var configOption = new Option(AliasesConfigOption, () => false, Resources.AWAKE_CMD_HELP_CONFIG_OPTION) { Arity = ArgumentArity.ZeroOrOne, IsRequired = false, }; - Option displayOption = new( - aliases: AliasesDisplayOption, - getDefaultValue: () => true, - description: "Determines whether the display should be kept awake.") + var displayOption = new Option(AliasesDisplayOption, () => true, Resources.AWAKE_CMD_HELP_DISPLAY_OPTION) { Arity = ArgumentArity.ZeroOrOne, IsRequired = false, }; - Option timeOption = new( - aliases: AliasesTimeOption, - getDefaultValue: () => 0, - description: "Determines the interval, in seconds, during which the computer is kept awake.") + var timeOption = new Option(AliasesTimeOption, () => 0, Resources.AWAKE_CMD_HELP_TIME_OPTION) { Arity = ArgumentArity.ExactlyOne, IsRequired = false, }; - Option pidOption = new( - aliases: AliasesPidOption, - getDefaultValue: () => 0, - description: $"Bind the execution of {Core.Constants.AppName} to another process. When the process ends, the system will resume managing the current sleep and display state.") + var pidOption = new Option(AliasesPidOption, () => 0, Resources.AWAKE_CMD_HELP_PID_OPTION) { Arity = ArgumentArity.ZeroOrOne, IsRequired = false, }; - Option expireAtOption = new( - aliases: AliasesExpireAtOption, - getDefaultValue: () => string.Empty, - description: $"Determines the end date/time when {Core.Constants.AppName} will back off and let the system manage the current sleep and display state.") + var expireAtOption = new Option(AliasesExpireAtOption, () => string.Empty, Resources.AWAKE_CMD_HELP_EXPIRE_AT_OPTION) { Arity = ArgumentArity.ZeroOrOne, IsRequired = false, }; - RootCommand? rootCommand = new() - { + RootCommand? rootCommand = + [ configOption, displayOption, timeOption, pidOption, expireAtOption, - }; + ]; rootCommand.Description = Core.Constants.AppName; - - rootCommand.SetHandler( - HandleCommandLineArguments, - configOption, - displayOption, - timeOption, - pidOption, - expireAtOption); + rootCommand.SetHandler(HandleCommandLineArguments, configOption, displayOption, timeOption, pidOption, expireAtOption); return rootCommand.InvokeAsync(args).Result; } @@ -160,7 +132,7 @@ namespace Awake private static bool ExitHandler(ControlType ctrlType) { Logger.LogInfo($"Exited through handler with control type: {ctrlType}"); - Exit("Exiting from the internal termination handler.", Environment.ExitCode, _exitSignal); + Exit(Resources.AWAKE_EXIT_MESSAGE, Environment.ExitCode, _exitSignal); return false; } @@ -201,27 +173,30 @@ namespace Awake { // Configuration file is used, therefore we disregard any other command-line parameter // and instead watch for changes in the file. + Manager.IsUsingPowerToysConfig = true; + try { var eventHandle = new EventWaitHandle(false, EventResetMode.ManualReset, interop.Constants.AwakeExitEvent()); new Thread(() => { - if (WaitHandle.WaitAny(new WaitHandle[] { _exitSignal, eventHandle }) == 1) + if (WaitHandle.WaitAny([_exitSignal, eventHandle]) == 1) { - Exit("Received a signal to end the process. Making sure we quit...", 0, _exitSignal, true); + Exit(Resources.AWAKE_EXIT_SIGNAL_MESSAGE, 0, _exitSignal, true); } }).Start(); TrayHelper.InitializeTray(Core.Constants.FullAppName, new Icon(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assets/Awake/awake.ico")), _exitSignal); string? settingsPath = _settingsUtils!.GetSettingsFilePath(Core.Constants.AppName); + Logger.LogInfo($"Reading configuration file: {settingsPath}"); if (!File.Exists(settingsPath)) { - string? errorString = $"The settings file does not exist. Scaffolding default configuration..."; + Logger.LogError("The settings file does not exist. Scaffolding default configuration..."); - AwakeSettings scaffoldSettings = new AwakeSettings(); + AwakeSettings scaffoldSettings = new(); _settingsUtils.SaveSettings(JsonSerializer.Serialize(scaffoldSettings), Core.Constants.AppName); } @@ -229,8 +204,7 @@ namespace Awake } catch (Exception ex) { - string? errorString = $"There was a problem with the configuration file. Make sure it exists.\n{ex.Message}"; - Logger.LogError(errorString); + Logger.LogError($"There was a problem with the configuration file. Make sure it exists.\n{ex.Message}"); } } else @@ -241,24 +215,13 @@ namespace Awake { try { - DateTime expirationDateTime = DateTime.Parse(expireAt, CultureInfo.CurrentCulture); - if (expirationDateTime > DateTime.Now) - { - // We want to have a dedicated expirable keep-awake logic instead of - // converting the target date to seconds and then passing to SetupTimedKeepAwake - // because that way we're accounting for the user potentially changing their clock - // while Awake is running. - Logger.LogInfo($"Operating in thread ID {Environment.CurrentManagedThreadId}."); - SetupExpirableKeepAwake(expirationDateTime, displayOn); - } - else - { - Logger.LogInfo($"Target date is not in the future, therefore there is nothing to wait for."); - } + DateTimeOffset expirationDateTime = DateTimeOffset.Parse(expireAt, CultureInfo.CurrentCulture); + Logger.LogInfo($"Operating in thread ID {Environment.CurrentManagedThreadId}."); + Manager.SetExpirableKeepAwake(expirationDateTime, displayOn); } catch (Exception ex) { - Logger.LogError($"Could not parse date string {expireAt} into a viable date."); + Logger.LogError($"Could not parse date string {expireAt} into a DateTimeOffset object."); Logger.LogError(ex.Message); } } @@ -268,11 +231,11 @@ namespace Awake if (mode == AwakeMode.INDEFINITE) { - SetupIndefiniteKeepAwake(displayOn); + Manager.SetIndefiniteKeepAwake(displayOn); } else { - SetupTimedKeepAwake(timeLimit, displayOn); + Manager.SetTimedKeepAwake(timeLimit, displayOn); } } } @@ -282,7 +245,7 @@ namespace Awake RunnerHelper.WaitForPowerToysRunner(pid, () => { Logger.LogInfo($"Triggered PID-based exit handler for PID {pid}."); - Exit("Terminating from process binding hook.", 0, _exitSignal, true); + Exit(Resources.AWAKE_EXIT_BINDING_HOOK_MESSAGE, 0, _exitSignal, true); }); } @@ -293,33 +256,34 @@ namespace Awake { try { + var directory = Path.GetDirectoryName(settingsPath)!; + var fileName = Path.GetFileName(settingsPath); + _watcher = new FileSystemWatcher { - Path = Path.GetDirectoryName(settingsPath)!, + Path = directory, EnableRaisingEvents = true, NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.CreationTime, - Filter = Path.GetFileName(settingsPath), + Filter = fileName, }; - IObservable>? changedObservable = Observable.FromEventPattern( + var mergedObservable = Observable.Merge( + Observable.FromEventPattern( h => _watcher.Changed += h, - h => _watcher.Changed -= h); + h => _watcher.Changed -= h), + Observable.FromEventPattern( + h => _watcher.Created += h, + h => _watcher.Created -= h)); - IObservable>? createdObservable = Observable.FromEventPattern( - cre => _watcher.Created += cre, - cre => _watcher.Created -= cre); - - IObservable>? mergedObservable = Observable.Merge(changedObservable, createdObservable); - - mergedObservable.Throttle(TimeSpan.FromMilliseconds(25)) + mergedObservable + .Throttle(TimeSpan.FromMilliseconds(25)) .SubscribeOn(TaskPoolScheduler.Default) .Select(e => e.EventArgs) .Subscribe(HandleAwakeConfigChange); - TrayHelper.SetTray(Core.Constants.FullAppName, new AwakeSettings(), _startedFromPowerToys); + var settings = Manager.ModuleSettings!.GetSettings(Core.Constants.AppName) ?? new AwakeSettings(); + TrayHelper.SetTray(settings, _startedFromPowerToys); - // Initially the file might not be updated, so we need to start processing - // settings right away. ProcessSettings(); } catch (Exception ex) @@ -328,99 +292,64 @@ namespace Awake } } - private static void SetupIndefiniteKeepAwake(bool displayOn) - { - Manager.SetIndefiniteKeepAwake(displayOn); - } - private static void HandleAwakeConfigChange(FileSystemEventArgs fileEvent) { - Logger.LogInfo("Detected a settings file change. Updating configuration..."); - Logger.LogInfo("Resetting keep-awake to normal state due to settings change."); - ProcessSettings(); + try + { + Logger.LogInfo("Detected a settings file change. Updating configuration..."); + ProcessSettings(); + } + catch (Exception e) + { + Logger.LogError($"Could not handle Awake configuration change. Error: {e.Message}"); + } } private static void ProcessSettings() { try { - AwakeSettings settings = _settingsUtils!.GetSettings(Core.Constants.AppName); + var settings = _settingsUtils!.GetSettings(Core.Constants.AppName) ?? throw new InvalidOperationException("Settings are null."); + Logger.LogInfo($"Identified custom time shortcuts for the tray: {settings.Properties.CustomTrayTimes.Count}"); - if (settings != null) + switch (settings.Properties.Mode) { - Logger.LogInfo($"Identified custom time shortcuts for the tray: {settings.Properties.CustomTrayTimes.Count}"); + case AwakeMode.PASSIVE: + Manager.SetPassiveKeepAwake(); + break; - switch (settings.Properties.Mode) - { - case AwakeMode.PASSIVE: - { - SetupNoKeepAwake(); - break; - } + case AwakeMode.INDEFINITE: + Manager.SetIndefiniteKeepAwake(settings.Properties.KeepDisplayOn); + break; - case AwakeMode.INDEFINITE: - { - SetupIndefiniteKeepAwake(settings.Properties.KeepDisplayOn); - break; - } + case AwakeMode.TIMED: + uint computedTime = (settings.Properties.IntervalHours * 60 * 60) + (settings.Properties.IntervalMinutes * 60); + Manager.SetTimedKeepAwake(computedTime, settings.Properties.KeepDisplayOn); + break; - case AwakeMode.TIMED: - { - uint computedTime = (settings.Properties.IntervalHours * 60 * 60) + (settings.Properties.IntervalMinutes * 60); - SetupTimedKeepAwake(computedTime, settings.Properties.KeepDisplayOn); + case AwakeMode.EXPIRABLE: + // When we are loading from the settings file, let's make sure that we never + // get users in a state where the expirable keep-awake is in the past. + if (settings.Properties.ExpirationDateTime <= DateTimeOffset.Now) + { + settings.Properties.ExpirationDateTime = DateTimeOffset.Now.AddMinutes(5); + _settingsUtils.SaveSettings(JsonSerializer.Serialize(settings), Core.Constants.AppName); + } - break; - } + Manager.SetExpirableKeepAwake(settings.Properties.ExpirationDateTime, settings.Properties.KeepDisplayOn); + break; - case AwakeMode.EXPIRABLE: - { - SetupExpirableKeepAwake(settings.Properties.ExpirationDateTime, settings.Properties.KeepDisplayOn); - - break; - } - - default: - { - string? errorMessage = "Unknown mode of operation. Check config file."; - Logger.LogError(errorMessage); - break; - } - } - - TrayHelper.SetTray(Core.Constants.FullAppName, settings, _startedFromPowerToys); - } - else - { - string? errorMessage = "Settings are null."; - Logger.LogError(errorMessage); + default: + Logger.LogError("Unknown mode of operation. Check config file."); + break; } + + TrayHelper.SetTray(settings, _startedFromPowerToys); } catch (Exception ex) { - string? errorMessage = $"There was a problem reading the configuration file. Error: {ex.GetType()} {ex.Message}"; - Logger.LogError(errorMessage); + Logger.LogError($"There was a problem reading the configuration file. Error: {ex.GetType()} {ex.Message}"); } } - - private static void SetupNoKeepAwake() - { - Logger.LogInfo($"Operating in passive mode (computer's standard power plan). No custom keep awake settings enabled."); - - Manager.SetNoKeepAwake(); - } - - private static void SetupExpirableKeepAwake(DateTimeOffset expireAt, bool displayOn) - { - Logger.LogInfo($"Expirable keep-awake. Expected expiration date/time: {expireAt} with display on setting set to {displayOn}."); - - Manager.SetExpirableKeepAwake(expireAt, displayOn); - } - - private static void SetupTimedKeepAwake(uint time, bool displayOn) - { - Logger.LogInfo($"Timed keep-awake. Expected runtime: {time} seconds with display on setting set to {displayOn}."); - - Manager.SetTimedKeepAwake(time, displayOn); - } } } diff --git a/src/modules/awake/Awake/Properties/Resources.Designer.cs b/src/modules/awake/Awake/Properties/Resources.Designer.cs index dab74f79fa..2a8ac0a8cf 100644 --- a/src/modules/awake/Awake/Properties/Resources.Designer.cs +++ b/src/modules/awake/Awake/Properties/Resources.Designer.cs @@ -60,24 +60,6 @@ namespace Awake.Properties { } } - /// - /// Looks up a localized string similar to 1 hour. - /// - internal static string AWAKE_1_HOUR { - get { - return ResourceManager.GetString("AWAKE_1_HOUR", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to 1 minute. - /// - internal static string AWAKE_1_MINUTE { - get { - return ResourceManager.GetString("AWAKE_1_MINUTE", resourceCulture); - } - } - /// /// Looks up a localized string similar to Checked. /// @@ -87,6 +69,51 @@ namespace Awake.Properties { } } + /// + /// Looks up a localized string similar to Specifies whether Awake will be using the PowerToys configuration file for managing the state.. + /// + internal static string AWAKE_CMD_HELP_CONFIG_OPTION { + get { + return ResourceManager.GetString("AWAKE_CMD_HELP_CONFIG_OPTION", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Determines whether the display should be kept awake.. + /// + internal static string AWAKE_CMD_HELP_DISPLAY_OPTION { + get { + return ResourceManager.GetString("AWAKE_CMD_HELP_DISPLAY_OPTION", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Determines the end date and time when Awake will back off and let the system manage the current sleep and display state.. + /// + internal static string AWAKE_CMD_HELP_EXPIRE_AT_OPTION { + get { + return ResourceManager.GetString("AWAKE_CMD_HELP_EXPIRE_AT_OPTION", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Bind the execution of Awake to another process. When the process ends, the system will resume managing the current sleep and display state.. + /// + internal static string AWAKE_CMD_HELP_PID_OPTION { + get { + return ResourceManager.GetString("AWAKE_CMD_HELP_PID_OPTION", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Determines the interval (in seconds) during which the computer is kept awake.. + /// + internal static string AWAKE_CMD_HELP_TIME_OPTION { + get { + return ResourceManager.GetString("AWAKE_CMD_HELP_TIME_OPTION", resourceCulture); + } + } + /// /// Looks up a localized string similar to Exit. /// @@ -96,6 +123,33 @@ namespace Awake.Properties { } } + /// + /// Looks up a localized string similar to Terminating from process binding hook.. + /// + internal static string AWAKE_EXIT_BINDING_HOOK_MESSAGE { + get { + return ResourceManager.GetString("AWAKE_EXIT_BINDING_HOOK_MESSAGE", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Exiting from the internal termination handler.. + /// + internal static string AWAKE_EXIT_MESSAGE { + get { + return ResourceManager.GetString("AWAKE_EXIT_MESSAGE", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Received a signal to end the process. Making sure we quit.... + /// + internal static string AWAKE_EXIT_SIGNAL_MESSAGE { + get { + return ResourceManager.GetString("AWAKE_EXIT_SIGNAL_MESSAGE", resourceCulture); + } + } + /// /// Looks up a localized string similar to {0} hours. /// @@ -159,6 +213,42 @@ namespace Awake.Properties { } } + /// + /// Looks up a localized string similar to Expiring. + /// + internal static string AWAKE_TRAY_TEXT_EXPIRATION { + get { + return ResourceManager.GetString("AWAKE_TRAY_TEXT_EXPIRATION", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Indefinite. + /// + internal static string AWAKE_TRAY_TEXT_INDEFINITE { + get { + return ResourceManager.GetString("AWAKE_TRAY_TEXT_INDEFINITE", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Passive. + /// + internal static string AWAKE_TRAY_TEXT_OFF { + get { + return ResourceManager.GetString("AWAKE_TRAY_TEXT_OFF", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Timed. + /// + internal static string AWAKE_TRAY_TEXT_TIMED { + get { + return ResourceManager.GetString("AWAKE_TRAY_TEXT_TIMED", resourceCulture); + } + } + /// /// Looks up a localized string similar to Unchecked. /// diff --git a/src/modules/awake/Awake/Properties/Resources.resx b/src/modules/awake/Awake/Properties/Resources.resx index 7ce0a1652d..abb0f8ca36 100644 --- a/src/modules/awake/Awake/Properties/Resources.resx +++ b/src/modules/awake/Awake/Properties/Resources.resx @@ -123,9 +123,6 @@ Exit - - 1 hour - {0} hours {0} shouldn't be removed. It will be replaced by a number greater than 1 at runtime by the application. Used for defining a period to keep the PC awake. @@ -145,9 +142,6 @@ Keep awake until expiration date and time Keep the system awake until expiration date and time - - 1 minute - {0} minutes {0} shouldn't be removed. It will be replaced by a number greater than 1 at runtime by the application. Used for defining a period to keep the PC awake. @@ -159,4 +153,40 @@ Unchecked + + Specifies whether Awake will be using the PowerToys configuration file for managing the state. + + + Determines whether the display should be kept awake. + + + Determines the end date and time when Awake will back off and let the system manage the current sleep and display state. + + + Bind the execution of Awake to another process. When the process ends, the system will resume managing the current sleep and display state. + + + Determines the interval (in seconds) during which the computer is kept awake. + + + Terminating from process binding hook. + + + Exiting from the internal termination handler. + + + Received a signal to end the process. Making sure we quit... + + + Expiring + + + Indefinite + + + Passive + + + Timed + \ No newline at end of file diff --git a/src/settings-ui/Settings.UI.Library/AwakeMode.cs b/src/settings-ui/Settings.UI.Library/AwakeMode.cs new file mode 100644 index 0000000000..202bb3a6ca --- /dev/null +++ b/src/settings-ui/Settings.UI.Library/AwakeMode.cs @@ -0,0 +1,14 @@ +// 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.PowerToys.Settings.UI.Library +{ + public enum AwakeMode + { + PASSIVE = 0, + INDEFINITE = 1, + TIMED = 2, + EXPIRABLE = 3, + } +} diff --git a/src/settings-ui/Settings.UI.Library/AwakeProperties.cs b/src/settings-ui/Settings.UI.Library/AwakeProperties.cs index f9b0b5e4b4..df0da47316 100644 --- a/src/settings-ui/Settings.UI.Library/AwakeProperties.cs +++ b/src/settings-ui/Settings.UI.Library/AwakeProperties.cs @@ -18,7 +18,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library IntervalHours = 0; IntervalMinutes = 1; ExpirationDateTime = DateTimeOffset.Now; - CustomTrayTimes = new Dictionary(); + CustomTrayTimes = []; } [JsonPropertyName("keepDisplayOn")] @@ -40,12 +40,4 @@ namespace Microsoft.PowerToys.Settings.UI.Library [CmdConfigureIgnoreAttribute] public Dictionary CustomTrayTimes { get; set; } } - - public enum AwakeMode - { - PASSIVE = 0, - INDEFINITE = 1, - TIMED = 2, - EXPIRABLE = 3, - } } diff --git a/src/settings-ui/Settings.UI.Library/AwakeSettings.cs b/src/settings-ui/Settings.UI.Library/AwakeSettings.cs index f811dbca37..fb38a3cf36 100644 --- a/src/settings-ui/Settings.UI.Library/AwakeSettings.cs +++ b/src/settings-ui/Settings.UI.Library/AwakeSettings.cs @@ -4,6 +4,7 @@ using System; using System.Linq; +using System.Reflection; using System.Text.Json.Serialization; using Microsoft.PowerToys.Settings.UI.Library.Interfaces; @@ -12,12 +13,11 @@ namespace Microsoft.PowerToys.Settings.UI.Library public class AwakeSettings : BasePTModuleSettings, ISettingsConfig, ICloneable { public const string ModuleName = "Awake"; - public const string ModuleVersion = "0.0.2"; public AwakeSettings() { Name = ModuleName; - Version = ModuleVersion; + Version = Assembly.GetExecutingAssembly().GetName().Version.ToString(); Properties = new AwakeProperties(); } diff --git a/src/settings-ui/Settings.UI/SettingsXAML/Views/AwakePage.xaml b/src/settings-ui/Settings.UI/SettingsXAML/Views/AwakePage.xaml index e855cc6c96..ae9816b91f 100644 --- a/src/settings-ui/Settings.UI/SettingsXAML/Views/AwakePage.xaml +++ b/src/settings-ui/Settings.UI/SettingsXAML/Views/AwakePage.xaml @@ -27,7 +27,7 @@ x:Uid="Awake_EnableSettingsCard" HeaderIcon="{ui:BitmapIcon Source=/Assets/Settings/Icons/Awake.png}" IsEnabled="{x:Bind ViewModel.IsEnabledGpoConfigured, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}"> - + ModuleSettings.Properties.Mode == AwakeMode.EXPIRABLE && IsEnabled; - } + public bool IsExpirationConfigurationEnabled => ModuleSettings.Properties.Mode == AwakeMode.EXPIRABLE && IsEnabled; - public bool IsTimeConfigurationEnabled - { - get => ModuleSettings.Properties.Mode == AwakeMode.TIMED && IsEnabled; - } + public bool IsTimeConfigurationEnabled => ModuleSettings.Properties.Mode == AwakeMode.TIMED && IsEnabled; - public bool IsScreenConfigurationPossibleEnabled - { - get => ModuleSettings.Properties.Mode != AwakeMode.PASSIVE && IsEnabled; - } + public bool IsScreenConfigurationPossibleEnabled => ModuleSettings.Properties.Mode != AwakeMode.PASSIVE && IsEnabled; public AwakeMode Mode { @@ -90,6 +80,26 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels { ModuleSettings.Properties.Mode = value; + if (value == AwakeMode.TIMED && IntervalMinutes == 0 && IntervalHours == 0) + { + // Handle the special case where both hours and minutes are zero. + // Otherwise, this will reset to passive very quickly in the UI. + ModuleSettings.Properties.IntervalMinutes = 1; + OnPropertyChanged(nameof(IntervalMinutes)); + } + else if (value == AwakeMode.EXPIRABLE && ExpirationDateTime <= DateTimeOffset.Now) + { + // To make sure that we're not tracking expirable keep-awake in the past, + // let's make sure that every time it's enabled from the settings UI, it's + // five (5) minutes into the future. + ExpirationDateTime = DateTimeOffset.Now.AddMinutes(5); + + // The expiration date/time is updated and will send the notification + // but we need to do this manually for the expiration time that is + // bound to the time control on the settings page. + OnPropertyChanged(nameof(ExpirationTime)); + } + OnPropertyChanged(nameof(IsTimeConfigurationEnabled)); OnPropertyChanged(nameof(IsScreenConfigurationPossibleEnabled)); OnPropertyChanged(nameof(IsExpirationConfigurationEnabled));