Skip to content

Commit

Permalink
[Awake]Fix DAISY build issues (#34054)
Browse files Browse the repository at this point in the history
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)
  • Loading branch information
dend authored Jul 30, 2024
1 parent 5d77874 commit e8ad4fa
Show file tree
Hide file tree
Showing 8 changed files with 246 additions and 104 deletions.
1 change: 1 addition & 0 deletions src/modules/awake/Awake/Awake.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
<CsWinRTIncludes>PowerToys.GPOWrapper</CsWinRTIncludes>
<CsWinRTGeneratedFilesDir>$(OutDir)</CsWinRTGeneratedFilesDir>
<ErrorOnDuplicatePublishOutputFiles>false</ErrorOnDuplicatePublishOutputFiles>
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)'=='Debug'">
Expand Down
12 changes: 12 additions & 0 deletions src/modules/awake/Awake/Core/ExtensionMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,17 @@ public static void AddRange<T>(this ICollection<T> target, IEnumerable<T> source
target.Add(element);
}
}

public static string ToHumanReadableString(this TimeSpan timeSpan)
{
// Get days, hours, minutes, and seconds from the TimeSpan
int days = timeSpan.Days;
int hours = timeSpan.Hours;
int minutes = timeSpan.Minutes;
int seconds = timeSpan.Seconds;

// Format the string based on the presence of days, hours, minutes, and seconds
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}";
}
}
}
85 changes: 56 additions & 29 deletions src/modules/awake/Awake/Core/Manager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ public class Manager

private static readonly BlockingCollection<ExecutionState> _stateQueue;

// Core icons used for the tray
private static readonly Icon _timedIcon = new(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assets/Awake/timed.ico"));
private static readonly Icon _expirableIcon = new(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assets/Awake/expirable.ico"));
private static readonly Icon _indefiniteIcon = new(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assets/Awake/indefinite.ico"));
private static readonly Icon _disabledIcon = new(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assets/Awake/disabled.ico"));

private static CancellationTokenSource _tokenSource;

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

_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);
TrayHelper.SetShellIcon(TrayHelper.HiddenWindowHandle, $"{Constants.FullAppName} [{Resources.AWAKE_TRAY_TEXT_INDEFINITE}]", _indefiniteIcon, TrayIconAction.Update);

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

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

Observable.Timer(expireAt - DateTimeOffset.Now).Subscribe(
_ =>
{
Logger.LogInfo($"Completed expirable keep-awake.");
CancelExistingThread();
SetPassiveKeepAwake();
if (IsUsingPowerToysConfig)
{
SetPassiveKeepAwake();
}
else
{
Logger.LogInfo("Exiting after expirable keep awake.");
CompleteExit(Environment.ExitCode);
}
},
_tokenSource.Token);
}
Expand Down Expand Up @@ -224,16 +239,40 @@ internal static void SetTimedKeepAwake(uint seconds, bool keepDisplayOn = true)
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);
TrayHelper.SetShellIcon(TrayHelper.HiddenWindowHandle, $"{Constants.FullAppName} [{Resources.AWAKE_TRAY_TEXT_TIMED}]", _timedIcon, TrayIconAction.Update);

Observable.Timer(TimeSpan.FromSeconds(seconds)).Subscribe(
_ =>
{
Logger.LogInfo($"Completed timed thread.");
CancelExistingThread();
SetPassiveKeepAwake();
},
_tokenSource.Token);
var timerObservable = Observable.Timer(TimeSpan.FromSeconds(seconds));
var intervalObservable = Observable.Interval(TimeSpan.FromSeconds(1)).TakeUntil(timerObservable);

var combinedObservable = Observable.CombineLatest(intervalObservable, timerObservable.StartWith(0), (elapsedSeconds, _) => elapsedSeconds + 1);

combinedObservable.Subscribe(
elapsedSeconds =>
{
var timeRemaining = seconds - (uint)elapsedSeconds;
if (timeRemaining >= 0)
{
TrayHelper.SetShellIcon(TrayHelper.HiddenWindowHandle, $"{Constants.FullAppName} [{Resources.AWAKE_TRAY_TEXT_TIMED}]\n{TimeSpan.FromSeconds(timeRemaining).ToHumanReadableString()}", _timedIcon, TrayIconAction.Update);
}
},
() =>
{
Console.WriteLine("Completed timed thread.");
CancelExistingThread();
if (IsUsingPowerToysConfig)
{
// If we're using PowerToys settings, we need to make sure that
// we just switch over the Passive Keep-Awake.
SetPassiveKeepAwake();
}
else
{
Logger.LogInfo("Exiting after timed keep-awake.");
CompleteExit(Environment.ExitCode);
}
},
_tokenSource.Token);

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

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

// Close the message window that we used for the tray.
Bridge.SendMessage(TrayHelper.HiddenWindowHandle, Native.Constants.WM_CLOSE, 0, 0);
}

if (force)
{
Bridge.PostQuitMessage(exitCode);
}

try
{
exitSignal?.Set();
Bridge.DestroyWindow(TrayHelper.HiddenWindowHandle);
}
catch (Exception ex)
{
Logger.LogError($"Exit signal error ${ex}");
}

Bridge.PostQuitMessage(exitCode);
Environment.Exit(exitCode);
}

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

CancelExistingThread();

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

if (IsUsingPowerToysConfig && updateSettings)
{
Expand Down
Loading

0 comments on commit e8ad4fa

Please sign in to comment.