diff --git a/ColorControl/ColorControl.csproj b/ColorControl/ColorControl.csproj
index 403a92c..d71a006 100644
--- a/ColorControl/ColorControl.csproj
+++ b/ColorControl/ColorControl.csproj
@@ -18,8 +18,8 @@
Maassoft
Maassoft
0
- 9.8.2.0
- 9.8.2.0
+ 9.8.2.1
+ 9.8.2.1
false
true
false
diff --git a/ColorControl/MainForm.cs b/ColorControl/MainForm.cs
index 3187676..4a460d7 100644
--- a/ColorControl/MainForm.cs
+++ b/ColorControl/MainForm.cs
@@ -1,13 +1,13 @@
using ColorControl.Forms;
using ColorControl.Services.AMD;
using ColorControl.Services.Common;
-using ColorControl.Services.EventDispatcher;
using ColorControl.Services.GameLauncher;
using ColorControl.Services.LG;
using ColorControl.Services.NVIDIA;
using ColorControl.Services.Samsung;
using ColorControl.Shared.Common;
using ColorControl.Shared.Contracts;
+using ColorControl.Shared.EventDispatcher;
using ColorControl.Shared.Forms;
using ColorControl.Shared.Native;
using ColorControl.Shared.Services;
diff --git a/ColorControl/Program.cs b/ColorControl/Program.cs
index fc84fbb..6590a95 100644
--- a/ColorControl/Program.cs
+++ b/ColorControl/Program.cs
@@ -1,12 +1,12 @@
using ColorControl.Forms;
using ColorControl.Services.Common;
-using ColorControl.Services.EventDispatcher;
using ColorControl.Services.GameLauncher;
using ColorControl.Services.LG;
using ColorControl.Services.NVIDIA;
using ColorControl.Services.Samsung;
using ColorControl.Shared.Common;
using ColorControl.Shared.Contracts;
+using ColorControl.Shared.EventDispatcher;
using ColorControl.Shared.Native;
using ColorControl.Shared.Services;
using ColorControl.Svc;
@@ -73,11 +73,6 @@ namespace ColorControl
return;
}
- var host = CreateHostBuilder().Build();
- ServiceProvider = host.Services;
-
- var mutexId = $"Global\\{typeof(MainForm).GUID}";
-
var currentDomain = AppDomain.CurrentDomain;
// Handler for unhandled exceptions.
currentDomain.UnhandledException += GlobalUnhandledExceptionHandler;
@@ -86,16 +81,24 @@ namespace ColorControl
LoadConfig();
+ if (Config.UseGdiScaling)
+ {
+ var result = Application.SetHighDpiMode(HighDpiMode.DpiUnawareGdiScaled);
+
+ Logger.Debug($"Result of setting SetHighDpiMode: {result}");
+ }
+
+ var host = CreateHostBuilder().Build();
+ ServiceProvider = host.Services;
+
+ var mutexId = $"Global\\{typeof(MainForm).GUID}";
+
var appContextProvider = ServiceProvider.GetRequiredService();
var startUpParams = StartUpParams.Parse(args);
AppContext = new GlobalContext(Config, startUpParams, DataDir, _loggingRule, mutexId);
appContextProvider.SetAppContext(AppContext);
- if (Config.UseGdiScaling)
- {
- Application.SetHighDpiMode(HighDpiMode.DpiUnawareGdiScaled);
- }
var existingProcess = Utils.GetProcessByName("ColorControl");
diff --git a/ColorControl/Services/Common/PresetBase.cs b/ColorControl/Services/Common/PresetBase.cs
index fa47a87..2de771a 100644
--- a/ColorControl/Services/Common/PresetBase.cs
+++ b/ColorControl/Services/Common/PresetBase.cs
@@ -1,6 +1,6 @@
-using ColorControl.Services.EventDispatcher;
-using ColorControl.Shared.Common;
+using ColorControl.Shared.Common;
using ColorControl.Shared.Contracts;
+using ColorControl.Shared.EventDispatcher;
using NStandard;
using System;
using System.Collections.Generic;
diff --git a/ColorControl/Services/Common/ServiceBase.cs b/ColorControl/Services/Common/ServiceBase.cs
index d790320..073ce6a 100644
--- a/ColorControl/Services/Common/ServiceBase.cs
+++ b/ColorControl/Services/Common/ServiceBase.cs
@@ -1,4 +1,4 @@
-using ColorControl.Services.EventDispatcher;
+using ColorControl.Shared.EventDispatcher;
using ColorControl.Shared.Native;
using ColorControl.Shared.Services;
using Newtonsoft.Json;
diff --git a/ColorControl/Services/EventDispatcher/EventExtensions.cs b/ColorControl/Services/EventDispatcher/EventExtensions.cs
deleted file mode 100644
index 071da6d..0000000
--- a/ColorControl/Services/EventDispatcher/EventExtensions.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace ColorControl.Services.EventDispatcher
-{
- public static class EventExtensions
- {
- public delegate Task AsyncEventHandler(object sender, TEventArgs e, CancellationToken token);
-
- public static Task InvokeAsync(this AsyncEventHandler func, object sender, TArgs e)
- {
- return func == null ? Task.CompletedTask
- : Task.WhenAll(func.GetInvocationList().Cast>().Select(f => f(sender, e, CancellationToken.None)));
- }
- }
-}
diff --git a/ColorControl/Services/EventDispatcher/PowerEventDispatcher.cs b/ColorControl/Services/EventDispatcher/PowerEventDispatcher.cs
deleted file mode 100644
index 11ca589..0000000
--- a/ColorControl/Services/EventDispatcher/PowerEventDispatcher.cs
+++ /dev/null
@@ -1,117 +0,0 @@
-using Microsoft.Win32;
-using NWin32;
-using System;
-using System.Threading.Tasks;
-
-namespace ColorControl.Services.EventDispatcher
-{
- public enum PowerOnOffState
- {
- None = 0,
- StartUp = 1,
- Resume = 2,
- ScreenSaver = 3,
- ShutDown = 4,
- StandBy = 5,
- MonitorOff = 6,
- MonitorOn = 7
- }
-
- internal enum WindowsMonitorPowerSetting
- {
- Off = 0,
- On = 1,
- Dimmed = 2
- }
-
- public class PowerStateChangedEventArgs : EventArgs
- {
- public PowerOnOffState State { get; private set; }
-
- public PowerStateChangedEventArgs(PowerOnOffState state)
- {
- State = state;
- }
- }
-
- public class PowerEventDispatcher : EventDispatcher
- {
- public const string Event_Suspend = "Suspend";
- public const string Event_Resume = "Resume";
- public const string Event_Startup = "Startup";
- public const string Event_Shutdown = "Shutdown";
- public const string Event_MonitorOff = "MonitorOff";
- public const string Event_MonitorOn = "MonitorOn";
-
- private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
-
- public PowerEventDispatcher()
- {
- SystemEvents.PowerModeChanged += OnPowerModeChanged;
- }
-
- public void SendEvent(string eventName)
- {
- var state = eventName switch
- {
- Event_Shutdown => PowerOnOffState.ShutDown,
- Event_Startup => PowerOnOffState.StartUp,
- Event_MonitorOff => PowerOnOffState.MonitorOff,
- Event_MonitorOn => PowerOnOffState.MonitorOn,
- _ => PowerOnOffState.None
- };
-
- if (state == PowerOnOffState.None)
- {
- return;
- }
-
- if (state == PowerOnOffState.ShutDown)
- {
- DispatchEventWithExecutionState(Event_Shutdown, PowerOnOffState.ShutDown);
- return;
- }
-
- DispatchEvent(eventName, new PowerStateChangedEventArgs(state));
- }
-
- public async Task SendEventAsync(string eventName)
- {
- var state = eventName switch
- {
- Event_Startup => PowerOnOffState.StartUp,
- _ => PowerOnOffState.None
- };
-
- await DispatchEventAsync(eventName, new PowerStateChangedEventArgs(state));
- }
-
- private async void OnPowerModeChanged(object sender, PowerModeChangedEventArgs e)
- {
- if (e.Mode == PowerModes.Suspend)
- {
- DispatchEventWithExecutionState(Event_Suspend, PowerOnOffState.StandBy);
- }
- else if (e.Mode == PowerModes.Resume)
- {
- await DispatchEventAsync(Event_Resume, new PowerStateChangedEventArgs(PowerOnOffState.Resume));
- DispatchEvent(Event_Resume, new PowerStateChangedEventArgs(PowerOnOffState.Resume));
- }
- }
-
- private void DispatchEventWithExecutionState(string eventName, PowerOnOffState powerState)
- {
- var error = NativeMethods.SetThreadExecutionState(NativeConstants.ES_CONTINUOUS | NativeConstants.ES_SYSTEM_REQUIRED | NativeConstants.ES_AWAYMODE_REQUIRED);
- try
- {
- Logger.Debug($"SetThreadExecutionState: {error}, Thread#: {Environment.CurrentManagedThreadId}");
- DispatchEvent(eventName, new PowerStateChangedEventArgs(powerState));
- }
- finally
- {
- var error2 = NativeMethods.SetThreadExecutionState(NativeConstants.ES_CONTINUOUS);
- Logger.Debug($"SetThreadExecutionState (reset): {error2}, Thread#: {Environment.CurrentManagedThreadId}");
- }
- }
- }
-}
diff --git a/ColorControl/Services/EventDispatcher/ProcessEventDispatcher.cs b/ColorControl/Services/EventDispatcher/ProcessEventDispatcher.cs
deleted file mode 100644
index 4ffc2b5..0000000
--- a/ColorControl/Services/EventDispatcher/ProcessEventDispatcher.cs
+++ /dev/null
@@ -1,141 +0,0 @@
-using ColorControl.Shared.Common;
-using ColorControl.Shared.Forms;
-using ColorControl.Shared.Services;
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Linq;
-using System.Management;
-using System.Threading.Tasks;
-
-namespace ColorControl.Services.EventDispatcher
-{
- public enum ScreenSaverTransitionState
- {
- None = 0,
- Started = 1,
- Running = 2,
- Stopped = 3
- }
-
- public class ProcessChangedEventArgs : EventArgs
- {
- public IList StartedProcesses { get; set; }
- public IList StoppedProcesses { get; set; }
- public IList RunningProcesses { get; set; }
- public bool IsNotificationDisabled { get; set; }
- public Process ForegroundProcess { get; set; }
- public bool ForegroundProcessIsFullScreen { get; set; }
- public string LastFullScreenProcessName = string.Empty;
- public bool StoppedFullScreen { get; set; }
- public bool IsScreenSaverActive { get; set; }
- public ScreenSaverTransitionState ScreenSaverTransitionState { get; set; }
- }
-
-
- public class ProcessEventDispatcher : EventDispatcher
- {
- public const string Event_ProcessChanged = "ProcessChanged";
- public bool IsRunning { get; set; }
- public ProcessChangedEventArgs MonitorContext { get; private set; }
-
- protected static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
-
- private AppContextProvider _appContextProvider { get; }
-
- public ProcessEventDispatcher(AppContextProvider appContextProvider)
- {
- _appContextProvider = appContextProvider;
-
- IsRunning = true;
-
- //Task.Run(async () => await CheckProcesses());
-
- var _ = CheckProcesses();
- }
-
- private async Task CheckProcesses()
- {
- await Task.Delay(2000);
-
- //var startWatch = new ManagementEventWatcher("SELECT * FROM Win32_ProcessStartTrace");
- //startWatch.EventArrived += startWatch_EventArrived;
- //startWatch.Start();
-
- MonitorContext ??= new ProcessChangedEventArgs();
-
- while (IsRunning)
- {
- await Task.Delay(_appContextProvider.GetAppContext().Config.ProcessMonitorPollingInterval);
-
- if (!HasHandlers(Event_ProcessChanged))
- {
- continue;
- }
-
- try
- {
- FillContext(MonitorContext);
-
- // Ignore if own process has the foreground
- if (MonitorContext.ForegroundProcess?.Id == Environment.ProcessId)
- {
- continue;
- }
-
- await DispatchEventAsync(Event_ProcessChanged, MonitorContext);
- DispatchEvent(Event_ProcessChanged, MonitorContext);
- }
- catch (Exception ex)
- {
- Logger.Error("CheckProcesses: " + ex.ToLogString());
- }
- }
- }
-
- private void FillContext(ProcessChangedEventArgs context)
- {
- var processes = Process.GetProcesses();
-
- context.StartedProcesses = processes.Where(p => context.RunningProcesses?.Any(rp => rp.Id == p.Id) == false).ToList();
- context.StoppedProcesses = context.RunningProcesses?.Where(p => processes.Any(rp => rp.Id == p.Id) == false).ToList();
- context.RunningProcesses = processes;
-
- context.IsNotificationDisabled = FormUtils.IsNotificationDisabled();
-
- var (processId, isFullScreen) = FormUtils.GetForegroundProcessIdAndIfFullScreen();
-
- if (processId > 0)
- {
- var process = context.RunningProcesses.FirstOrDefault(p => p.Id == processId);
-
- var screenSaverActive = process?.ProcessName?.Contains(".scr") == true;
-
- context.IsScreenSaverActive = screenSaverActive;
- context.ScreenSaverTransitionState = screenSaverActive ?
- context.ScreenSaverTransitionState == ScreenSaverTransitionState.None ? ScreenSaverTransitionState.Started : ScreenSaverTransitionState.Running :
- context.ScreenSaverTransitionState == ScreenSaverTransitionState.Running ? ScreenSaverTransitionState.Stopped : ScreenSaverTransitionState.None;
- context.ForegroundProcess = process;
- context.ForegroundProcessIsFullScreen = isFullScreen;
-
- if (isFullScreen)
- {
- context.LastFullScreenProcessName = context.ForegroundProcess.ProcessName;
- //Logger.Debug($"Foreground fullscreen app detected: {context.ForegroundProcess.ProcessName}");
- }
- }
- else
- {
- context.StoppedFullScreen = context.ForegroundProcessIsFullScreen;
- context.ForegroundProcess = null;
- context.ForegroundProcessIsFullScreen = false;
- context.LastFullScreenProcessName = string.Empty;
- }
- }
-
- private void startWatch_EventArrived(object sender, EventArrivedEventArgs e)
- {
- //Logger.Debug("Process started: " + e.NewEvent.Properties["ProcessName"].Value);
- }
- }
-}
diff --git a/ColorControl/Services/EventDispatcher/SessionSwitchDispatcher.cs b/ColorControl/Services/EventDispatcher/SessionSwitchDispatcher.cs
deleted file mode 100644
index 413ae9b..0000000
--- a/ColorControl/Services/EventDispatcher/SessionSwitchDispatcher.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-using Microsoft.Win32;
-
-namespace ColorControl.Services.EventDispatcher
-{
- public class SessionSwitchDispatcher : EventDispatcher
- {
- public const string Event_SessionSwitch = "SessionSwitch";
-
- private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
-
- public bool UserLocalSession { get; private set; } = true;
- public SessionSwitchReason LastSessionSwitchReason { get; private set; } = 0;
-
- public SessionSwitchDispatcher()
- {
- SystemEvents.SessionSwitch += SessionSwitchHandler;
- }
-
- public void SessionSwitchHandler(object sender, SessionSwitchEventArgs evt)
- {
- if (evt.Reason == SessionSwitchReason.ConsoleDisconnect)
- {
- Logger.Debug("Detected a disconnect from the console");
- UserLocalSession = false;
-
- DispatchEvent(Event_SessionSwitch, evt);
- }
- else if (evt.Reason == SessionSwitchReason.ConsoleConnect)
- {
- Logger.Debug("Detected a connect to the console");
- if (!UserLocalSession)
- {
- Logger.Debug("Session state switched to local");
- UserLocalSession = true;
- DispatchEvent(Event_SessionSwitch, evt);
- }
- }
- LastSessionSwitchReason = evt.Reason;
- }
- }
-}
diff --git a/ColorControl/Services/GameLauncher/GameService.cs b/ColorControl/Services/GameLauncher/GameService.cs
index 21ba132..79490f9 100644
--- a/ColorControl/Services/GameLauncher/GameService.cs
+++ b/ColorControl/Services/GameLauncher/GameService.cs
@@ -1,6 +1,6 @@
using ColorControl.Services.Common;
-using ColorControl.Services.EventDispatcher;
using ColorControl.Shared.Common;
+using ColorControl.Shared.EventDispatcher;
using ColorControl.Shared.Services;
using Newtonsoft.Json;
using System;
diff --git a/ColorControl/Services/LG/LgPanel.cs b/ColorControl/Services/LG/LgPanel.cs
index 51125c2..ee45323 100644
--- a/ColorControl/Services/LG/LgPanel.cs
+++ b/ColorControl/Services/LG/LgPanel.cs
@@ -1,9 +1,9 @@
using ColorControl.Services.AMD;
using ColorControl.Services.Common;
-using ColorControl.Services.EventDispatcher;
using ColorControl.Services.NVIDIA;
using ColorControl.Shared.Common;
using ColorControl.Shared.Contracts;
+using ColorControl.Shared.EventDispatcher;
using ColorControl.Shared.Forms;
using ColorControl.Shared.Native;
using LgTv;
diff --git a/ColorControl/Services/LG/LgService.cs b/ColorControl/Services/LG/LgService.cs
index a79214e..86897b0 100644
--- a/ColorControl/Services/LG/LgService.cs
+++ b/ColorControl/Services/LG/LgService.cs
@@ -1,7 +1,7 @@
using ColorControl.Services.Common;
-using ColorControl.Services.EventDispatcher;
using ColorControl.Shared.Common;
using ColorControl.Shared.Contracts;
+using ColorControl.Shared.EventDispatcher;
using ColorControl.Shared.Native;
using ColorControl.Shared.Services;
using LgTv;
diff --git a/ColorControl/Services/NVIDIA/NvService.cs b/ColorControl/Services/NVIDIA/NvService.cs
index 8b56f7d..69b41d4 100644
--- a/ColorControl/Services/NVIDIA/NvService.cs
+++ b/ColorControl/Services/NVIDIA/NvService.cs
@@ -1,8 +1,8 @@
using ColorControl.Services.Common;
-using ColorControl.Services.EventDispatcher;
using ColorControl.Shared.Common;
using ColorControl.Shared.Contracts;
using ColorControl.Shared.Contracts.NVIDIA;
+using ColorControl.Shared.EventDispatcher;
using ColorControl.Shared.Forms;
using ColorControl.Shared.Native;
using ColorControl.Shared.Services;
diff --git a/ColorControl/Services/Samsung/SamsungPanel.cs b/ColorControl/Services/Samsung/SamsungPanel.cs
index cdf90f2..4a102e3 100644
--- a/ColorControl/Services/Samsung/SamsungPanel.cs
+++ b/ColorControl/Services/Samsung/SamsungPanel.cs
@@ -1,9 +1,9 @@
using ColorControl.Services.AMD;
using ColorControl.Services.Common;
-using ColorControl.Services.EventDispatcher;
using ColorControl.Services.NVIDIA;
using ColorControl.Shared.Common;
using ColorControl.Shared.Contracts;
+using ColorControl.Shared.EventDispatcher;
using ColorControl.Shared.Forms;
using ColorControl.Shared.Native;
using NLog;
diff --git a/ColorControl/Services/Samsung/SamsungService.cs b/ColorControl/Services/Samsung/SamsungService.cs
index a048360..cb71848 100644
--- a/ColorControl/Services/Samsung/SamsungService.cs
+++ b/ColorControl/Services/Samsung/SamsungService.cs
@@ -1,6 +1,6 @@
using ColorControl.Services.Common;
-using ColorControl.Services.EventDispatcher;
using ColorControl.Shared.Common;
+using ColorControl.Shared.EventDispatcher;
using ColorControl.Shared.Native;
using ColorControl.Shared.Services;
using Microsoft.Extensions.DependencyInjection;
diff --git a/ColorControl/Svc/ColorControlBackgroundService.cs b/ColorControl/Svc/ColorControlBackgroundService.cs
index 4bb9998..c24324b 100644
--- a/ColorControl/Svc/ColorControlBackgroundService.cs
+++ b/ColorControl/Svc/ColorControlBackgroundService.cs
@@ -1,7 +1,7 @@
-using ColorControl.Services.EventDispatcher;
-using ColorControl.Services.LG;
+using ColorControl.Services.LG;
using ColorControl.Shared.Common;
using ColorControl.Shared.Contracts;
+using ColorControl.Shared.EventDispatcher;
using ColorControl.Shared.Services;
using Microsoft.Extensions.Hosting;
using Newtonsoft.Json;
diff --git a/ColorControl/Services/EventDispatcher/EventDispatcher.cs b/Shared/EventDispatcher/EventDispatcher.cs
similarity index 89%
rename from ColorControl/Services/EventDispatcher/EventDispatcher.cs
rename to Shared/EventDispatcher/EventDispatcher.cs
index 08fae03..b4f3e9c 100644
--- a/ColorControl/Services/EventDispatcher/EventDispatcher.cs
+++ b/Shared/EventDispatcher/EventDispatcher.cs
@@ -1,9 +1,6 @@
-using System;
-using System.Collections.Generic;
-using System.Threading.Tasks;
-using static ColorControl.Services.EventDispatcher.EventExtensions;
+using static ColorControl.Shared.EventDispatcher.EventExtensions;
-namespace ColorControl.Services.EventDispatcher;
+namespace ColorControl.Shared.EventDispatcher;
public class EventDispatcher where T : EventArgs
{
diff --git a/Shared/EventDispatcher/EventExtensions.cs b/Shared/EventDispatcher/EventExtensions.cs
new file mode 100644
index 0000000..e345850
--- /dev/null
+++ b/Shared/EventDispatcher/EventExtensions.cs
@@ -0,0 +1,12 @@
+namespace ColorControl.Shared.EventDispatcher;
+
+public static class EventExtensions
+{
+ public delegate Task AsyncEventHandler(object sender, TEventArgs e, CancellationToken token);
+
+ public static Task InvokeAsync(this AsyncEventHandler func, object sender, TArgs e)
+ {
+ return func == null ? Task.CompletedTask
+ : Task.WhenAll(func.GetInvocationList().Cast>().Select(f => f(sender, e, CancellationToken.None)));
+ }
+}
diff --git a/Shared/EventDispatcher/PowerEventDispatcher.cs b/Shared/EventDispatcher/PowerEventDispatcher.cs
new file mode 100644
index 0000000..4a077fe
--- /dev/null
+++ b/Shared/EventDispatcher/PowerEventDispatcher.cs
@@ -0,0 +1,114 @@
+using Microsoft.Win32;
+using NWin32;
+
+namespace ColorControl.Shared.EventDispatcher;
+
+public enum PowerOnOffState
+{
+ None = 0,
+ StartUp = 1,
+ Resume = 2,
+ ScreenSaver = 3,
+ ShutDown = 4,
+ StandBy = 5,
+ MonitorOff = 6,
+ MonitorOn = 7
+}
+
+public enum WindowsMonitorPowerSetting
+{
+ Off = 0,
+ On = 1,
+ Dimmed = 2
+}
+
+public class PowerStateChangedEventArgs : EventArgs
+{
+ public PowerOnOffState State { get; private set; }
+
+ public PowerStateChangedEventArgs(PowerOnOffState state)
+ {
+ State = state;
+ }
+}
+
+public class PowerEventDispatcher : EventDispatcher
+{
+ public const string Event_Suspend = "Suspend";
+ public const string Event_Resume = "Resume";
+ public const string Event_Startup = "Startup";
+ public const string Event_Shutdown = "Shutdown";
+ public const string Event_MonitorOff = "MonitorOff";
+ public const string Event_MonitorOn = "MonitorOn";
+
+ private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
+
+ public PowerEventDispatcher()
+ {
+ SystemEvents.PowerModeChanged += OnPowerModeChanged;
+ }
+
+ public void SendEvent(string eventName)
+ {
+ var state = eventName switch
+ {
+ Event_Shutdown => PowerOnOffState.ShutDown,
+ Event_Startup => PowerOnOffState.StartUp,
+ Event_MonitorOff => PowerOnOffState.MonitorOff,
+ Event_MonitorOn => PowerOnOffState.MonitorOn,
+ _ => PowerOnOffState.None
+ };
+
+ if (state == PowerOnOffState.None)
+ {
+ return;
+ }
+
+ if (state == PowerOnOffState.ShutDown)
+ {
+ DispatchEventWithExecutionState(Event_Shutdown, PowerOnOffState.ShutDown);
+ return;
+ }
+
+ DispatchEvent(eventName, new PowerStateChangedEventArgs(state));
+ }
+
+ public async Task SendEventAsync(string eventName)
+ {
+ var state = eventName switch
+ {
+ Event_Startup => PowerOnOffState.StartUp,
+ _ => PowerOnOffState.None
+ };
+
+ await DispatchEventAsync(eventName, new PowerStateChangedEventArgs(state));
+ }
+
+ private async void OnPowerModeChanged(object sender, PowerModeChangedEventArgs e)
+ {
+ if (e.Mode == PowerModes.Suspend)
+ {
+ DispatchEventWithExecutionState(Event_Suspend, PowerOnOffState.StandBy);
+ }
+ else if (e.Mode == PowerModes.Resume)
+ {
+ await DispatchEventAsync(Event_Resume, new PowerStateChangedEventArgs(PowerOnOffState.Resume));
+ DispatchEvent(Event_Resume, new PowerStateChangedEventArgs(PowerOnOffState.Resume));
+ }
+ }
+
+ private void DispatchEventWithExecutionState(string eventName, PowerOnOffState powerState)
+ {
+ var error = NativeMethods.SetThreadExecutionState(NativeConstants.ES_CONTINUOUS | NativeConstants.ES_SYSTEM_REQUIRED | NativeConstants.ES_AWAYMODE_REQUIRED);
+ try
+ {
+ Logger.Debug($"SetThreadExecutionState: {error}, Thread#: {Environment.CurrentManagedThreadId}");
+ DispatchEvent(eventName, new PowerStateChangedEventArgs(powerState));
+ }
+ finally
+ {
+ var error2 = NativeMethods.SetThreadExecutionState(NativeConstants.ES_CONTINUOUS);
+ Logger.Debug($"SetThreadExecutionState (reset): {error2}, Thread#: {Environment.CurrentManagedThreadId}");
+ }
+ }
+}
diff --git a/Shared/EventDispatcher/ProcessEventDispatcher.cs b/Shared/EventDispatcher/ProcessEventDispatcher.cs
new file mode 100644
index 0000000..bea6d5b
--- /dev/null
+++ b/Shared/EventDispatcher/ProcessEventDispatcher.cs
@@ -0,0 +1,136 @@
+using ColorControl.Shared.Common;
+using ColorControl.Shared.Forms;
+using ColorControl.Shared.Services;
+using System.Diagnostics;
+using System.Management;
+
+namespace ColorControl.Shared.EventDispatcher;
+
+public enum ScreenSaverTransitionState
+{
+ None = 0,
+ Started = 1,
+ Running = 2,
+ Stopped = 3
+}
+
+public class ProcessChangedEventArgs : EventArgs
+{
+ public IList StartedProcesses { get; set; }
+ public IList StoppedProcesses { get; set; }
+ public IList RunningProcesses { get; set; }
+ public bool IsNotificationDisabled { get; set; }
+ public Process ForegroundProcess { get; set; }
+ public bool ForegroundProcessIsFullScreen { get; set; }
+ public string LastFullScreenProcessName = string.Empty;
+ public bool StoppedFullScreen { get; set; }
+ public bool IsScreenSaverActive { get; set; }
+ public ScreenSaverTransitionState ScreenSaverTransitionState { get; set; }
+}
+
+
+public class ProcessEventDispatcher : EventDispatcher
+{
+ public const string Event_ProcessChanged = "ProcessChanged";
+ public bool IsRunning { get; set; }
+ public ProcessChangedEventArgs MonitorContext { get; private set; }
+
+ protected static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
+
+ private AppContextProvider _appContextProvider { get; }
+
+ public ProcessEventDispatcher(AppContextProvider appContextProvider)
+ {
+ _appContextProvider = appContextProvider;
+
+ IsRunning = true;
+
+ //Task.Run(async () => await CheckProcesses());
+
+ var _ = CheckProcesses();
+ }
+
+ private async Task CheckProcesses()
+ {
+ await Task.Delay(2000);
+
+ //var startWatch = new ManagementEventWatcher("SELECT * FROM Win32_ProcessStartTrace");
+ //startWatch.EventArrived += startWatch_EventArrived;
+ //startWatch.Start();
+
+ MonitorContext ??= new ProcessChangedEventArgs();
+
+ while (IsRunning)
+ {
+ await Task.Delay(_appContextProvider.GetAppContext().Config.ProcessMonitorPollingInterval);
+
+ if (!HasHandlers(Event_ProcessChanged))
+ {
+ continue;
+ }
+
+ try
+ {
+ FillContext(MonitorContext);
+
+ // Ignore if own process has the foreground
+ if (MonitorContext.ForegroundProcess?.Id == Environment.ProcessId)
+ {
+ continue;
+ }
+
+ await DispatchEventAsync(Event_ProcessChanged, MonitorContext);
+ DispatchEvent(Event_ProcessChanged, MonitorContext);
+ }
+ catch (Exception ex)
+ {
+ Logger.Error("CheckProcesses: " + ex.ToLogString());
+ }
+ }
+ }
+
+ private void FillContext(ProcessChangedEventArgs context)
+ {
+ var processes = Process.GetProcesses();
+
+ context.StartedProcesses = processes.Where(p => context.RunningProcesses?.Any(rp => rp.Id == p.Id) == false).ToList();
+ context.StoppedProcesses = context.RunningProcesses?.Where(p => processes.Any(rp => rp.Id == p.Id) == false).ToList();
+ context.RunningProcesses = processes;
+
+ context.IsNotificationDisabled = FormUtils.IsNotificationDisabled();
+
+ var (processId, isFullScreen) = FormUtils.GetForegroundProcessIdAndIfFullScreen();
+
+ if (processId > 0)
+ {
+ var process = context.RunningProcesses.FirstOrDefault(p => p.Id == processId);
+
+ var screenSaverActive = process?.ProcessName?.Contains(".scr") == true;
+
+ context.IsScreenSaverActive = screenSaverActive;
+ context.ScreenSaverTransitionState = screenSaverActive ?
+ context.ScreenSaverTransitionState == ScreenSaverTransitionState.None ? ScreenSaverTransitionState.Started : ScreenSaverTransitionState.Running :
+ context.ScreenSaverTransitionState == ScreenSaverTransitionState.Running ? ScreenSaverTransitionState.Stopped : ScreenSaverTransitionState.None;
+ context.ForegroundProcess = process;
+ context.ForegroundProcessIsFullScreen = isFullScreen;
+
+ if (isFullScreen)
+ {
+ context.LastFullScreenProcessName = context.ForegroundProcess.ProcessName;
+ //Logger.Debug($"Foreground fullscreen app detected: {context.ForegroundProcess.ProcessName}");
+ }
+ }
+ else
+ {
+ context.StoppedFullScreen = context.ForegroundProcessIsFullScreen;
+ context.ForegroundProcess = null;
+ context.ForegroundProcessIsFullScreen = false;
+ context.LastFullScreenProcessName = string.Empty;
+ }
+ }
+
+ private void startWatch_EventArrived(object sender, EventArrivedEventArgs e)
+ {
+ //Logger.Debug("Process started: " + e.NewEvent.Properties["ProcessName"].Value);
+ }
+}
diff --git a/Shared/EventDispatcher/SessionSwitchDispatcher.cs b/Shared/EventDispatcher/SessionSwitchDispatcher.cs
new file mode 100644
index 0000000..0beaf06
--- /dev/null
+++ b/Shared/EventDispatcher/SessionSwitchDispatcher.cs
@@ -0,0 +1,40 @@
+using Microsoft.Win32;
+
+namespace ColorControl.Shared.EventDispatcher;
+
+public class SessionSwitchDispatcher : EventDispatcher
+{
+ public const string Event_SessionSwitch = "SessionSwitch";
+
+ private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
+
+ public bool UserLocalSession { get; private set; } = true;
+ public SessionSwitchReason LastSessionSwitchReason { get; private set; } = 0;
+
+ public SessionSwitchDispatcher()
+ {
+ SystemEvents.SessionSwitch += SessionSwitchHandler;
+ }
+
+ public void SessionSwitchHandler(object sender, SessionSwitchEventArgs evt)
+ {
+ if (evt.Reason == SessionSwitchReason.ConsoleDisconnect)
+ {
+ Logger.Debug("Detected a disconnect from the console");
+ UserLocalSession = false;
+
+ DispatchEvent(Event_SessionSwitch, evt);
+ }
+ else if (evt.Reason == SessionSwitchReason.ConsoleConnect)
+ {
+ Logger.Debug("Detected a connect to the console");
+ if (!UserLocalSession)
+ {
+ Logger.Debug("Session state switched to local");
+ UserLocalSession = true;
+ DispatchEvent(Event_SessionSwitch, evt);
+ }
+ }
+ LastSessionSwitchReason = evt.Reason;
+ }
+}