Disable sleep idle timeout when audio is playing via SetThreadExecutionState.
This commit is contained in:
@@ -102,5 +102,6 @@
|
|||||||
<PublishReadyToRun Condition="'$(Configuration)' != 'Debug'">True</PublishReadyToRun>
|
<PublishReadyToRun Condition="'$(Configuration)' != 'Debug'">True</PublishReadyToRun>
|
||||||
<PublishTrimmed Condition="'$(Configuration)' == 'Debug'">False</PublishTrimmed>
|
<PublishTrimmed Condition="'$(Configuration)' == 'Debug'">False</PublishTrimmed>
|
||||||
<PublishTrimmed Condition="'$(Configuration)' != 'Debug'">True</PublishTrimmed>
|
<PublishTrimmed Condition="'$(Configuration)' != 'Debug'">True</PublishTrimmed>
|
||||||
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
</Project>
|
</Project>
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
|
using Harmonia.Core.Player;
|
||||||
using Harmonia.WinUI.Session;
|
using Harmonia.WinUI.Session;
|
||||||
using Microsoft.UI.Windowing;
|
using Microsoft.UI.Windowing;
|
||||||
using Microsoft.UI.Xaml;
|
using Microsoft.UI.Xaml;
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Harmonia.WinUI;
|
namespace Harmonia.WinUI;
|
||||||
|
|
||||||
@@ -8,16 +11,23 @@ public sealed partial class MainWindow : Window
|
|||||||
{
|
{
|
||||||
private const string ApplicationTitle = "Harmonia";
|
private const string ApplicationTitle = "Harmonia";
|
||||||
|
|
||||||
|
[LibraryImport("kernel32.dll", SetLastError = true)]
|
||||||
|
private static partial EXECUTION_STATE SetThreadExecutionState(EXECUTION_STATE esFlags);
|
||||||
|
|
||||||
private readonly ISessionService _sessionService;
|
private readonly ISessionService _sessionService;
|
||||||
private readonly ISessionTracker _sessionTracker;
|
private readonly ISessionTracker _sessionTracker;
|
||||||
|
private readonly IAudioPlayer _audioPlayer;
|
||||||
|
|
||||||
private bool _isSaved;
|
private bool _isSaved;
|
||||||
|
|
||||||
public MainWindow(ISessionService sessionService, ISessionTracker sessionTracker)
|
public MainWindow(ISessionService sessionService, ISessionTracker sessionTracker, IAudioPlayer audioPlayer)
|
||||||
{
|
{
|
||||||
_sessionService = sessionService;
|
_sessionService = sessionService;
|
||||||
_sessionTracker = sessionTracker;
|
_sessionTracker = sessionTracker;
|
||||||
|
|
||||||
|
_audioPlayer = audioPlayer;
|
||||||
|
_audioPlayer.PropertyChanged += OnAudioPlayerPropertyChanged;
|
||||||
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
InitializeTitleBar();
|
InitializeTitleBar();
|
||||||
InitializeWindowState();
|
InitializeWindowState();
|
||||||
@@ -54,6 +64,8 @@ public sealed partial class MainWindow : Window
|
|||||||
|
|
||||||
private async void OnMainWindowClosed(object sender, WindowEventArgs args)
|
private async void OnMainWindowClosed(object sender, WindowEventArgs args)
|
||||||
{
|
{
|
||||||
|
EnableSleepIdleTimeout();
|
||||||
|
|
||||||
if (_isSaved)
|
if (_isSaved)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -65,4 +77,53 @@ public sealed partial class MainWindow : Window
|
|||||||
_isSaved = true;
|
_isSaved = true;
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnAudioPlayerPropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
switch (e.PropertyName)
|
||||||
|
{
|
||||||
|
case nameof(_audioPlayer.State):
|
||||||
|
OnAudioPlayerStateChanged(sender, e);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnAudioPlayerStateChanged(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
// SetThreadExecutionState is per-thread, so always marshal to the UI thread to
|
||||||
|
// guarantee the ES_CONTINUOUS flags are set and cleared on the same thread.
|
||||||
|
DispatcherQueue.TryEnqueue(() =>
|
||||||
|
{
|
||||||
|
switch (_audioPlayer.State)
|
||||||
|
{
|
||||||
|
case Core.Engine.AudioPlaybackState.Playing:
|
||||||
|
DisableSleepIdleTimeout();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
EnableSleepIdleTimeout();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void EnableSleepIdleTimeout()
|
||||||
|
{
|
||||||
|
// Clear EXECUTION_STATE flags to allow the system to idle to sleep normally.
|
||||||
|
SetThreadExecutionState(EXECUTION_STATE.ES_CONTINUOUS);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void DisableSleepIdleTimeout()
|
||||||
|
{
|
||||||
|
// Prevent the system sleep idle time-out while still allowing the display to sleep.
|
||||||
|
SetThreadExecutionState(EXECUTION_STATE.ES_CONTINUOUS | EXECUTION_STATE.ES_SYSTEM_REQUIRED);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
private enum EXECUTION_STATE : uint
|
||||||
|
{
|
||||||
|
ES_CONTINUOUS = 0x80000000,
|
||||||
|
ES_SYSTEM_REQUIRED = 0x00000001,
|
||||||
|
ES_DISPLAY_REQUIRED = 0x00000002,
|
||||||
|
ES_AWAYMODE_REQUIRED = 0x00000040
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user