2023-01-05 23:35:31 +01:00
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
|
using CommonHelpers;
|
|
|
|
|
|
using ExternalHelpers;
|
|
|
|
|
|
using PowerControl.Helper;
|
|
|
|
|
|
using PowerControl.Menu;
|
|
|
|
|
|
|
|
|
|
|
|
namespace PowerControl
|
|
|
|
|
|
{
|
|
|
|
|
|
public class ProfilesController : IDisposable
|
|
|
|
|
|
{
|
|
|
|
|
|
public const bool AutoCreateProfiles = true;
|
2023-01-10 11:12:31 +01:00
|
|
|
|
public const int ApplyProfileDelayMs = 500;
|
2023-01-05 23:35:31 +01:00
|
|
|
|
|
|
|
|
|
|
private Dictionary<int, PowerControl.Helper.ProfileSettings> watchedProcesses = new Dictionary<int, PowerControl.Helper.ProfileSettings>();
|
2023-01-21 13:25:06 +01:00
|
|
|
|
private CancellationTokenSource? changeTask;
|
2023-01-05 23:35:31 +01:00
|
|
|
|
|
|
|
|
|
|
private System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer()
|
|
|
|
|
|
{
|
|
|
|
|
|
Interval = 1000
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
public IEnumerable<String> WatchedProfiles
|
|
|
|
|
|
{
|
|
|
|
|
|
get
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var process in watchedProcesses)
|
|
|
|
|
|
yield return process.Value.ProfileName;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-04-01 13:11:12 +02:00
|
|
|
|
public ProfileSettings? GameProfileSettings { get; private set; }
|
|
|
|
|
|
|
|
|
|
|
|
public ProfileSettings? SessionProfileSettings { get; private set; }
|
2023-04-01 13:41:53 +02:00
|
|
|
|
public ProfileSettings AutostartProfileSettings { get; private set; }
|
2023-01-05 23:35:31 +01:00
|
|
|
|
|
|
|
|
|
|
public ProfilesController()
|
|
|
|
|
|
{
|
|
|
|
|
|
PowerControl.Options.Profiles.Controller = this;
|
|
|
|
|
|
MenuStack.Root.ValueChanged += Root_OnOptionValueChange;
|
|
|
|
|
|
|
2023-04-01 13:41:53 +02:00
|
|
|
|
AutostartProfileSettings = new ProfileSettings("PowerControl", "Autostart");
|
|
|
|
|
|
|
2023-01-05 23:35:31 +01:00
|
|
|
|
timer.Start();
|
|
|
|
|
|
timer.Tick += Timer_Tick;
|
2023-04-01 13:41:53 +02:00
|
|
|
|
|
|
|
|
|
|
ProfileChanged(null);
|
|
|
|
|
|
ApplyProfile(AutostartProfileSettings);
|
2023-01-05 23:35:31 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
~ProfilesController()
|
|
|
|
|
|
{
|
|
|
|
|
|
Dispose();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void Dispose()
|
|
|
|
|
|
{
|
|
|
|
|
|
GC.SuppressFinalize(this);
|
|
|
|
|
|
PowerControl.Options.Profiles.Controller = null;
|
|
|
|
|
|
MenuStack.Root.ValueChanged -= Root_OnOptionValueChange;
|
|
|
|
|
|
timer.Stop();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void Timer_Tick(object? sender, EventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
timer.Enabled = false;
|
|
|
|
|
|
|
|
|
|
|
|
try { RefreshProfiles(); }
|
|
|
|
|
|
finally { timer.Enabled = true; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void RefreshProfiles()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (DisplayConfig.IsInternalConnected != true)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var process in watchedProcesses)
|
|
|
|
|
|
RemoveProcess(process.Key);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-02-08 19:40:16 +01:00
|
|
|
|
OSDHelpers.Applications.Instance.Refresh();
|
2023-01-05 23:35:31 +01:00
|
|
|
|
|
2023-02-08 19:40:16 +01:00
|
|
|
|
if (OSDHelpers.Applications.Instance.FindForeground(out var processId, out var processName))
|
2023-01-05 23:35:31 +01:00
|
|
|
|
{
|
|
|
|
|
|
if (!BringUpProcess(processId))
|
|
|
|
|
|
AddProcess(processId, processName);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var process in watchedProcesses)
|
|
|
|
|
|
{
|
2023-02-08 19:40:16 +01:00
|
|
|
|
if (OSDHelpers.Applications.Instance.IsRunning(process.Key))
|
2023-01-05 23:35:31 +01:00
|
|
|
|
continue;
|
|
|
|
|
|
RemoveProcess(process.Key);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private bool BringUpProcess(int processId)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!watchedProcesses.TryGetValue(processId, out var profileSettings))
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
2023-04-01 13:11:12 +02:00
|
|
|
|
if (GameProfileSettings != profileSettings)
|
2023-01-05 23:35:31 +01:00
|
|
|
|
{
|
|
|
|
|
|
Log.TraceLine("ProfilesController: Foreground changed: {0} => {1}",
|
2023-04-01 13:11:12 +02:00
|
|
|
|
GameProfileSettings?.ProfileName, profileSettings.ProfileName);
|
|
|
|
|
|
GameProfileSettings = profileSettings;
|
|
|
|
|
|
ProfileChanged(profileSettings);
|
2023-01-05 23:35:31 +01:00
|
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void AddProcess(int processId, string processName)
|
|
|
|
|
|
{
|
|
|
|
|
|
Log.TraceLine("ProfilesController: New Process: {0}/{1}", processId, processName);
|
|
|
|
|
|
|
2023-04-01 13:41:53 +02:00
|
|
|
|
var profileSettings = new ProfileSettings("PowerControl.Process", processName);
|
2023-01-05 23:35:31 +01:00
|
|
|
|
watchedProcesses.Add(processId, profileSettings);
|
|
|
|
|
|
|
2023-04-01 13:11:12 +02:00
|
|
|
|
// Create memory only SessionProfileSettings
|
|
|
|
|
|
if (SessionProfileSettings is null)
|
|
|
|
|
|
{
|
2023-04-01 13:41:53 +02:00
|
|
|
|
SessionProfileSettings = new ProfileSettings("PowerControl.Session", "Session." + processName) { UseConfigFile = false };
|
2023-04-01 13:11:12 +02:00
|
|
|
|
SaveProfile(SessionProfileSettings);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
GameProfileSettings = profileSettings;
|
|
|
|
|
|
ProfileChanged(profileSettings);
|
2023-01-05 23:35:31 +01:00
|
|
|
|
ApplyProfile(profileSettings);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void RemoveProcess(int processId)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!watchedProcesses.Remove(processId, out var profileSettings))
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
2023-04-01 13:11:12 +02:00
|
|
|
|
if (GameProfileSettings == profileSettings)
|
|
|
|
|
|
GameProfileSettings = null;
|
2023-01-05 23:35:31 +01:00
|
|
|
|
|
|
|
|
|
|
Log.TraceLine("ProfilesController: Removed Process: {0}", processId);
|
|
|
|
|
|
|
|
|
|
|
|
if (watchedProcesses.Any())
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
ResetProfile();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void Root_OnOptionValueChange(MenuItemWithOptions options, string? oldValue, string newValue)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (options.PersistentKey is null)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
2023-04-01 13:11:12 +02:00
|
|
|
|
// No active profile, cannot persist
|
|
|
|
|
|
if (GameProfileSettings is null)
|
|
|
|
|
|
return;
|
2023-01-05 23:35:31 +01:00
|
|
|
|
|
2023-04-01 13:11:12 +02:00
|
|
|
|
// Do not auto-create profile unless requested
|
|
|
|
|
|
if (!GameProfileSettings.Exists && !AutoCreateProfiles)
|
|
|
|
|
|
return;
|
2023-01-05 23:35:31 +01:00
|
|
|
|
|
2023-04-01 13:11:12 +02:00
|
|
|
|
GameProfileSettings.SetValue(options.PersistentKey, newValue);
|
|
|
|
|
|
options.ProfileOption = newValue;
|
|
|
|
|
|
|
|
|
|
|
|
Log.TraceLine("ProfilesController: Stored: {0} {1} = {2}",
|
|
|
|
|
|
GameProfileSettings.ProfileName, options.PersistentKey, newValue);
|
2023-01-05 23:35:31 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2023-04-01 13:11:12 +02:00
|
|
|
|
private void ProfileChanged(ProfileSettings? profileSettings)
|
2023-01-05 23:35:31 +01:00
|
|
|
|
{
|
2023-01-10 11:12:31 +01:00
|
|
|
|
foreach (var menuItem in PersistableOptions())
|
2023-01-05 23:35:31 +01:00
|
|
|
|
{
|
2023-04-01 13:11:12 +02:00
|
|
|
|
menuItem.ProfileOption = profileSettings?.GetValue(menuItem.PersistentKey ?? "");
|
2023-01-05 23:35:31 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void CreateProfile(bool saveAll = true)
|
|
|
|
|
|
{
|
2023-04-01 13:11:12 +02:00
|
|
|
|
var profileSettings = GameProfileSettings;
|
|
|
|
|
|
if (profileSettings is null)
|
|
|
|
|
|
return;
|
2023-01-05 23:35:31 +01:00
|
|
|
|
|
2023-04-01 13:11:12 +02:00
|
|
|
|
profileSettings.TouchFile();
|
2023-01-05 23:35:31 +01:00
|
|
|
|
|
|
|
|
|
|
Log.TraceLine("ProfilesController: Created Profile: {0}, SaveAll={1}",
|
2023-04-01 13:11:12 +02:00
|
|
|
|
profileSettings.ProfileName, saveAll);
|
2023-01-05 23:35:31 +01:00
|
|
|
|
|
2023-04-01 13:11:12 +02:00
|
|
|
|
if (saveAll)
|
|
|
|
|
|
SaveProfile(profileSettings);
|
2023-01-05 23:35:31 +01:00
|
|
|
|
|
2023-04-01 13:11:12 +02:00
|
|
|
|
ProfileChanged(profileSettings);
|
2023-01-05 23:35:31 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void DeleteProfile()
|
|
|
|
|
|
{
|
2023-04-01 13:11:12 +02:00
|
|
|
|
GameProfileSettings?.DeleteFile();
|
|
|
|
|
|
ProfileChanged(GameProfileSettings);
|
2023-01-05 23:35:31 +01:00
|
|
|
|
|
2023-04-01 13:11:12 +02:00
|
|
|
|
Log.TraceLine("ProfilesController: Deleted Profile: {0}", GameProfileSettings?.ProfileName);
|
2023-01-05 23:35:31 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2023-04-01 13:11:12 +02:00
|
|
|
|
private void SaveProfile(ProfileSettings profileSettings, bool force = false)
|
2023-01-05 23:35:31 +01:00
|
|
|
|
{
|
2023-04-01 13:11:12 +02:00
|
|
|
|
foreach (var menuItem in PersistableOptions())
|
|
|
|
|
|
{
|
|
|
|
|
|
if (menuItem.ActiveOption is null || !menuItem.PersistOnCreate && !force)
|
|
|
|
|
|
continue;
|
|
|
|
|
|
profileSettings?.SetValue(menuItem.PersistentKey ?? "", menuItem.ActiveOption);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2023-01-05 23:35:31 +01:00
|
|
|
|
|
2023-04-01 13:11:12 +02:00
|
|
|
|
private void ApplyProfile(ProfileSettings profileSettings)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (profileSettings is null || profileSettings?.Exists != true)
|
2023-01-05 23:35:31 +01:00
|
|
|
|
return;
|
|
|
|
|
|
|
2023-04-01 13:11:12 +02:00
|
|
|
|
int delay = profileSettings.GetInt("ApplyDelay", ApplyProfileDelayMs);
|
2023-01-05 23:35:31 +01:00
|
|
|
|
|
2023-01-21 13:25:06 +01:00
|
|
|
|
changeTask?.Cancel();
|
|
|
|
|
|
changeTask = Dispatcher.RunWithDelay(delay, () =>
|
2023-01-05 23:35:31 +01:00
|
|
|
|
{
|
2023-01-21 13:25:06 +01:00
|
|
|
|
foreach (var menuItem in PersistableOptions())
|
2023-01-05 23:35:31 +01:00
|
|
|
|
{
|
2023-04-01 13:11:12 +02:00
|
|
|
|
var persistedValue = profileSettings.GetValue(menuItem.PersistentKey ?? "");
|
2023-01-21 13:25:06 +01:00
|
|
|
|
if (persistedValue is null)
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
menuItem.Set(persistedValue, true, false);
|
|
|
|
|
|
|
|
|
|
|
|
Log.TraceLine("ProfilesController: Applied from Profile: {0}: {1} = {2}",
|
2023-04-01 13:11:12 +02:00
|
|
|
|
profileSettings.ProfileName, menuItem.PersistentKey, persistedValue);
|
2023-01-21 13:25:06 +01:00
|
|
|
|
}
|
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
|
{
|
|
|
|
|
|
Log.TraceLine("ProfilesController: Exception Profile: {0}: {1} = {2} => {3}",
|
2023-04-01 13:11:12 +02:00
|
|
|
|
profileSettings.ProfileName, menuItem.PersistentKey, persistedValue, e);
|
2023-01-21 13:25:06 +01:00
|
|
|
|
|
2023-04-01 13:11:12 +02:00
|
|
|
|
profileSettings.DeleteKey(menuItem.PersistentKey ?? "");
|
2023-01-21 13:25:06 +01:00
|
|
|
|
menuItem.ProfileOption = null;
|
|
|
|
|
|
}
|
2023-01-05 23:35:31 +01:00
|
|
|
|
}
|
2023-01-21 13:25:06 +01:00
|
|
|
|
});
|
2023-01-05 23:35:31 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void ResetProfile()
|
|
|
|
|
|
{
|
2023-04-01 13:11:12 +02:00
|
|
|
|
GameProfileSettings = null;
|
|
|
|
|
|
ProfileChanged(null);
|
2023-01-05 23:35:31 +01:00
|
|
|
|
|
2023-04-01 13:11:12 +02:00
|
|
|
|
if (SessionProfileSettings is not null)
|
2023-01-05 23:35:31 +01:00
|
|
|
|
{
|
2023-04-01 13:11:12 +02:00
|
|
|
|
ApplyProfile(SessionProfileSettings);
|
|
|
|
|
|
SessionProfileSettings = null;
|
|
|
|
|
|
}
|
2023-01-05 23:35:31 +01:00
|
|
|
|
}
|
2023-01-10 11:12:31 +01:00
|
|
|
|
|
|
|
|
|
|
private IEnumerable<MenuItemWithOptions> PersistableOptions()
|
|
|
|
|
|
{
|
|
|
|
|
|
return MenuItemWithOptions.
|
|
|
|
|
|
Order(MenuStack.Root.AllMenuItemOptions()).
|
|
|
|
|
|
Where((item) => item.PersistentKey is not null).
|
|
|
|
|
|
Reverse();
|
|
|
|
|
|
}
|
2023-01-05 23:35:31 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|