Skip to content

Commit e8ad4fa

Browse files
authored
[Awake]Fix DAISY build issues (#34054)
This PR addresses some post-merge issues caught by @davidegiacometti, including: 1. Separator in the context menu shown when not running from inside PowerToys. 2. "Keep display on" setting not persisting across switches between modes. 3. Awake not launching in standalone mode. Additionally: 1. Exits are now properly handled in **timed** and **expirable** keep-awake modes when running standalone. This ensures that Awake exists after completion and doesn't switch to an in-actionable passive mode. 2. Tray tooltips now cover how much time is left on the timer. 3. Fixes #29354 4. Avoids a nasty memory leak because of re-instantiating of `Icon` objects for every tray update. 5. Adds DPI awareness to the context menu (#16123)
1 parent 5d77874 commit e8ad4fa

File tree

8 files changed

+246
-104
lines changed

8 files changed

+246
-104
lines changed

Diff for: src/modules/awake/Awake/Awake.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
<CsWinRTIncludes>PowerToys.GPOWrapper</CsWinRTIncludes>
3636
<CsWinRTGeneratedFilesDir>$(OutDir)</CsWinRTGeneratedFilesDir>
3737
<ErrorOnDuplicatePublishOutputFiles>false</ErrorOnDuplicatePublishOutputFiles>
38+
<ApplicationManifest>app.manifest</ApplicationManifest>
3839
</PropertyGroup>
3940

4041
<PropertyGroup Condition="'$(Configuration)'=='Debug'">

Diff for: src/modules/awake/Awake/Core/ExtensionMethods.cs

+12
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,17 @@ public static void AddRange<T>(this ICollection<T> target, IEnumerable<T> source
1919
target.Add(element);
2020
}
2121
}
22+
23+
public static string ToHumanReadableString(this TimeSpan timeSpan)
24+
{
25+
// Get days, hours, minutes, and seconds from the TimeSpan
26+
int days = timeSpan.Days;
27+
int hours = timeSpan.Hours;
28+
int minutes = timeSpan.Minutes;
29+
int seconds = timeSpan.Seconds;
30+
31+
// Format the string based on the presence of days, hours, minutes, and seconds
32+
return $"{days:D2}{Properties.Resources.AWAKE_LABEL_DAYS} {hours:D2}{Properties.Resources.AWAKE_LABEL_HOURS} {minutes:D2}{Properties.Resources.AWAKE_LABEL_MINUTES} {seconds:D2}{Properties.Resources.AWAKE_LABEL_SECONDS}";
33+
}
2234
}
2335
}

Diff for: src/modules/awake/Awake/Core/Manager.cs

+56-29
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ public class Manager
3939

4040
private static readonly BlockingCollection<ExecutionState> _stateQueue;
4141

42+
// Core icons used for the tray
43+
private static readonly Icon _timedIcon = new(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assets/Awake/timed.ico"));
44+
private static readonly Icon _expirableIcon = new(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assets/Awake/expirable.ico"));
45+
private static readonly Icon _indefiniteIcon = new(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assets/Awake/indefinite.ico"));
46+
private static readonly Icon _disabledIcon = new(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assets/Awake/disabled.ico"));
47+
4248
private static CancellationTokenSource _tokenSource;
4349

4450
private static SettingsUtils? _moduleSettings;
@@ -135,7 +141,7 @@ internal static void SetIndefiniteKeepAwake(bool keepDisplayOn = false)
135141

136142
_stateQueue.Add(ComputeAwakeState(keepDisplayOn));
137143

138-
TrayHelper.SetShellIcon(TrayHelper.HiddenWindowHandle, $"{Constants.FullAppName} [{Resources.AWAKE_TRAY_TEXT_INDEFINITE}]", new Icon(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assets/Awake/indefinite.ico")), TrayIconAction.Update);
144+
TrayHelper.SetShellIcon(TrayHelper.HiddenWindowHandle, $"{Constants.FullAppName} [{Resources.AWAKE_TRAY_TEXT_INDEFINITE}]", _indefiniteIcon, TrayIconAction.Update);
139145

140146
if (IsUsingPowerToysConfig)
141147
{
@@ -172,14 +178,23 @@ internal static void SetExpirableKeepAwake(DateTimeOffset expireAt, bool keepDis
172178
Logger.LogInfo($"Starting expirable log for {expireAt}");
173179
_stateQueue.Add(ComputeAwakeState(keepDisplayOn));
174180

175-
TrayHelper.SetShellIcon(TrayHelper.HiddenWindowHandle, $"{Constants.FullAppName} [{Resources.AWAKE_TRAY_TEXT_EXPIRATION}]", new Icon(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assets/Awake/expirable.ico")), TrayIconAction.Update);
181+
TrayHelper.SetShellIcon(TrayHelper.HiddenWindowHandle, $"{Constants.FullAppName} [{Resources.AWAKE_TRAY_TEXT_EXPIRATION} - {expireAt}]", _expirableIcon, TrayIconAction.Update);
176182

177183
Observable.Timer(expireAt - DateTimeOffset.Now).Subscribe(
178184
_ =>
179185
{
180186
Logger.LogInfo($"Completed expirable keep-awake.");
181187
CancelExistingThread();
182-
SetPassiveKeepAwake();
188+
189+
if (IsUsingPowerToysConfig)
190+
{
191+
SetPassiveKeepAwake();
192+
}
193+
else
194+
{
195+
Logger.LogInfo("Exiting after expirable keep awake.");
196+
CompleteExit(Environment.ExitCode);
197+
}
183198
},
184199
_tokenSource.Token);
185200
}
@@ -224,16 +239,40 @@ internal static void SetTimedKeepAwake(uint seconds, bool keepDisplayOn = true)
224239
Logger.LogInfo($"Timed keep awake started for {seconds} seconds.");
225240
_stateQueue.Add(ComputeAwakeState(keepDisplayOn));
226241

227-
TrayHelper.SetShellIcon(TrayHelper.HiddenWindowHandle, $"{Constants.FullAppName} [{Resources.AWAKE_TRAY_TEXT_TIMED}]", new Icon(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assets/Awake/timed.ico")), TrayIconAction.Update);
242+
TrayHelper.SetShellIcon(TrayHelper.HiddenWindowHandle, $"{Constants.FullAppName} [{Resources.AWAKE_TRAY_TEXT_TIMED}]", _timedIcon, TrayIconAction.Update);
228243

229-
Observable.Timer(TimeSpan.FromSeconds(seconds)).Subscribe(
230-
_ =>
231-
{
232-
Logger.LogInfo($"Completed timed thread.");
233-
CancelExistingThread();
234-
SetPassiveKeepAwake();
235-
},
236-
_tokenSource.Token);
244+
var timerObservable = Observable.Timer(TimeSpan.FromSeconds(seconds));
245+
var intervalObservable = Observable.Interval(TimeSpan.FromSeconds(1)).TakeUntil(timerObservable);
246+
247+
var combinedObservable = Observable.CombineLatest(intervalObservable, timerObservable.StartWith(0), (elapsedSeconds, _) => elapsedSeconds + 1);
248+
249+
combinedObservable.Subscribe(
250+
elapsedSeconds =>
251+
{
252+
var timeRemaining = seconds - (uint)elapsedSeconds;
253+
if (timeRemaining >= 0)
254+
{
255+
TrayHelper.SetShellIcon(TrayHelper.HiddenWindowHandle, $"{Constants.FullAppName} [{Resources.AWAKE_TRAY_TEXT_TIMED}]\n{TimeSpan.FromSeconds(timeRemaining).ToHumanReadableString()}", _timedIcon, TrayIconAction.Update);
256+
}
257+
},
258+
() =>
259+
{
260+
Console.WriteLine("Completed timed thread.");
261+
CancelExistingThread();
262+
263+
if (IsUsingPowerToysConfig)
264+
{
265+
// If we're using PowerToys settings, we need to make sure that
266+
// we just switch over the Passive Keep-Awake.
267+
SetPassiveKeepAwake();
268+
}
269+
else
270+
{
271+
Logger.LogInfo("Exiting after timed keep-awake.");
272+
CompleteExit(Environment.ExitCode);
273+
}
274+
},
275+
_tokenSource.Token);
237276

238277
if (IsUsingPowerToysConfig)
239278
{
@@ -264,9 +303,7 @@ internal static void SetTimedKeepAwake(uint seconds, bool keepDisplayOn = true)
264303
/// Performs a clean exit from Awake.
265304
/// </summary>
266305
/// <param name="exitCode">Exit code to exit with.</param>
267-
/// <param name="exitSignal">Exit signal tracking the state.</param>
268-
/// <param name="force">Determines whether to force exit and post a quitting message.</param>
269-
internal static void CompleteExit(int exitCode, ManualResetEvent? exitSignal, bool force = false)
306+
internal static void CompleteExit(int exitCode)
270307
{
271308
SetPassiveKeepAwake(updateSettings: false);
272309

@@ -277,22 +314,12 @@ internal static void CompleteExit(int exitCode, ManualResetEvent? exitSignal, bo
277314

278315
// Close the message window that we used for the tray.
279316
Bridge.SendMessage(TrayHelper.HiddenWindowHandle, Native.Constants.WM_CLOSE, 0, 0);
280-
}
281-
282-
if (force)
283-
{
284-
Bridge.PostQuitMessage(exitCode);
285-
}
286317

287-
try
288-
{
289-
exitSignal?.Set();
290318
Bridge.DestroyWindow(TrayHelper.HiddenWindowHandle);
291319
}
292-
catch (Exception ex)
293-
{
294-
Logger.LogError($"Exit signal error ${ex}");
295-
}
320+
321+
Bridge.PostQuitMessage(exitCode);
322+
Environment.Exit(exitCode);
296323
}
297324

298325
/// <summary>
@@ -350,7 +377,7 @@ internal static void SetPassiveKeepAwake(bool updateSettings = true)
350377

351378
CancelExistingThread();
352379

353-
TrayHelper.SetShellIcon(TrayHelper.HiddenWindowHandle, $"{Constants.FullAppName} [{Resources.AWAKE_TRAY_TEXT_OFF}]", new Icon(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assets/Awake/disabled.ico")), TrayIconAction.Update);
380+
TrayHelper.SetShellIcon(TrayHelper.HiddenWindowHandle, $"{Constants.FullAppName} [{Resources.AWAKE_TRAY_TEXT_OFF}]", _disabledIcon, TrayIconAction.Update);
354381

355382
if (IsUsingPowerToysConfig && updateSettings)
356383
{

0 commit comments

Comments
 (0)