fix some issues after new release

This commit is contained in:
Vincent Maas committed 2024-08-03 16:19:27 +02:00
1 parent 18f32e1d46
commit 9e8e77d89b
12 files changed
+2842 -2875

No files matched your search

@@ -93,7 +93,7 @@
{
<input class="form-check-input me-1" style="font-size: 1rem" title="Apply these settings" type="checkbox" @bind="Preset.DisplayConfig.ApplyResolution" id="applyResolution">
}
<button class="accordion-button py-2 @(Preset.DisplayConfig.ApplyResolution ? "text-warning fw-bold" : "")" type="button" data-bs-toggle="collapse" data-bs-target="#resolutionSettings">
<button class="accordion-button py-2 @(!Preset.IsDisplayPreset ? "collapsed" : "") @(Preset.DisplayConfig.ApplyResolution ? "text-warning fw-bold" : "")" type="button" data-bs-toggle="collapse" data-bs-target="#resolutionSettings">
Resolution
</button>
</span>
@@ -157,7 +157,7 @@
</button>
</span>
</h2>
<div id="refreshRateSettings" class="accordion-collapse collapse show" data-bs-parent="#presetAccordion">
<div id="refreshRateSettings" class="accordion-collapse collapse" data-bs-parent="#presetAccordion">
<div class="accordion-body">
<div class="mb-2">
<label class="form-label" for="refreshRate">Refresh Rate</label>
@@ -356,7 +356,7 @@
if (Preset.IsDisplayPreset)
{
//Preset.UpdateAutoApplySettings(PresetParam);
Preset.UpdateAutoApplySettings(PresetParam);
await ApplyDisplayPreset();
return;
@@ -38,31 +38,35 @@
else
{
<div class="row mb-3">
<div class="col">
@if (!DisplayPresets.Any())
{
<span>No displays found</span>
}
@foreach (var preset in DisplayPresets)
{
<div class="card">
<div class="card-header">
@preset.displayName
@if (preset.DisplayConfig.IsPrimary == true)
{
<small class="text-muted ms-2">Primary</small>
}
<button type="button" class="btn btn-sm btn-primary ms-2" data-bs-toggle="modal" data-bs-target="#presetModal" @onclick="() => DisplayPresetOnClick(preset)">
Settings
</button>
@if (!DisplayPresets.Any())
{
<span>No displays found</span>
}
@foreach (var preset in DisplayPresets)
{
<div class="col-lg-6 mb-3">
<div class="card h-100">
<div class="card-header d-flex align-items-baseline">
<span>
@preset.displayName
@if (preset.DisplayConfig.IsPrimary == true)
{
<small class="text-muted ms-2">Primary</small>
}
</span>
<div class="d-flex ms-auto">
<button type="button" class="btn btn-sm btn-primary ms-2" data-bs-toggle="modal" data-bs-target="#presetModal" @onclick="() => DisplayPresetOnClick(preset)">
Settings
</button>
</div>
</div>
<div class="card-body">
<small class="text-body">@preset.DisplayConfig.Resolution.ToString() @@ @preset.DisplayConfig.RefreshRate.ToString()Hz</small>
<small class="text-muted">@preset.colorDepth, @preset.pixelFormat</small>
</div>
</div>
}
</div>
</div>
}
</div>
}
@@ -157,6 +161,7 @@ else
private async Task PresetOnCloneClick(AmdPreset preset)
{
CurrentPreset = new AmdPreset(preset);
CurrentPreset.name = preset.name;
CurrentPreset.SetCloneValues();
}
@@ -27,7 +27,7 @@
<div class="mb-2">
<label class="form-label" for="nvPreset">NVIDIA preset</label>
<select class="form-select" id="nvPreset" @bind="NvPresetToAddId">
<option value="null">Select preset</option>
<option value="">Select preset</option>
@foreach (var preset in NvPresets)
{
<option value="@preset.id">@preset.IdOrName</option>
@@ -40,7 +40,7 @@
<div class="mb-2">
<label class="form-label" for="samsungPreset">Samsung preset</label>
<select class="form-select" id="samsungPreset" @bind="SamsungPresetToAddId">
<option value="null">Select preset</option>
<option value="">Select preset</option>
@foreach (var preset in SamsungPresets)
{
<option value="@preset.id">@preset.IdOrName</option>
@@ -53,7 +53,7 @@
<div class="mb-2">
<label class="form-label" for="lgPreset">LG preset</label>
<select class="form-select" id="lgPreset" @bind="LgPresetToAddId">
<option value="null">Select preset</option>
<option value="">Select preset</option>
@foreach (var preset in LgPresets)
{
<option value="@preset.id">@preset.IdOrName</option>
@@ -68,7 +68,7 @@
<div class="mb-2">
<label class="form-label" for="customItem">@customItem.Name</label>
<select class="form-select" id="customItem" @bind="customItem.SelectedItem">
<option value="null">Select item</option>
<option value="">Select item</option>
@foreach (var item in customItem.Items)
{
<option value="@item">@item</option>
@@ -84,7 +84,7 @@
<div class="mb-2">
<label class="form-label" for="advancedCustomItem">@customItem.Name</label>
<select class="form-select" id="advancedCustomItem" @bind="customItem.SelectedActionName" @bind:after="() => AdvancedItemChanged(customItem)">
<option value="null">Select action</option>
<option value="">Select action</option>
@foreach (var keyValue in customItem.GroupedActions)
{
<optgroup label="@keyValue.Key">
@@ -49,31 +49,35 @@
else
{
<div class="row mb-3">
<div class="col">
@if (!DisplayPresets.Any())
{
<span>No displays found</span>
}
@foreach (var preset in DisplayPresets)
{
<div class="card mb-3">
<div class="card-header">
@preset.displayName
@if (preset.DisplayConfig.IsPrimary == true)
{
<span class="ms-2 badge text-bg-primary" title="Primary display">Primary</span>
}
<button type="button" class="btn btn-sm btn-primary ms-2" data-bs-toggle="modal" data-bs-target="#presetModal" @onclick="() => DisplayPresetOnClick(preset)">
Settings
</button>
@if (!DisplayPresets.Any())
{
<span>No displays found</span>
}
@foreach (var preset in DisplayPresets)
{
<div class="col-lg-6 mb-3">
<div class="card h-100">
<div class="card-header d-flex align-items-baseline">
<span>
@preset.displayName
@if (preset.DisplayConfig.IsPrimary == true)
{
<span class="ms-2 badge text-bg-primary" title="Primary display">Primary</span>
}
</span>
<div class="d-flex ms-auto">
<button type="button" class="btn btn-sm btn-primary ms-2" data-bs-toggle="modal" data-bs-target="#presetModal" @onclick="() => DisplayPresetOnClick(preset)">
Settings
</button>
</div>
</div>
<div class="card-body">
<small class="text-body">@preset.DisplayConfig.Resolution.ToString() @@ @preset.DisplayConfig.RefreshRate.ToString()Hz</small>
<small class="text-muted">@preset.colorData</small>
</div>
</div>
}
</div>
</div>
}
</div>
}
@@ -187,6 +191,7 @@ else
private async Task PresetOnCloneClick(NvPreset preset)
{
CurrentPreset = new NvPreset(preset);
CurrentPreset.name = preset.name;
CurrentPreset.SetCloneValues();
}
@@ -49,11 +49,11 @@ else
<label class="form-label" for="elevationMethod">
Elevation Method
</label>
<select class="form-select" @bind="elevationMethod" id="elevationMethod" @oninput="ElevationMethodInput" aria-describedby="elevationMethodHelp">
<option value="0">None</option>
<option value="1">Run as administrator</option>
<option value="2">Use service</option>
<option value="3">Use elevated process</option>
<select class="form-select" @bind="config.ElevationMethod" id="elevationMethod" @oninput="ElevationMethodInput" aria-describedby="elevationMethodHelp">
@foreach (var method in Enum.GetValues<ElevationMethod>())
{
<option value="@method">@method.GetDescription()</option>
}
</select>
<div id="elevationMethodHelp" class="form-text">
Elevation is needed in some cases where ColorControl needs administrator rights.
@@ -186,12 +186,10 @@ else
@code {
private Config? config;
private string elevationMethod = "0";
protected override async Task OnInitializedAsync()
{
config = await _rpcClientService.CallAsync<Config>("OptionsService", "GetConfig");
elevationMethod = ((int)config.ElevationMethod).ToString();
}
private async Task SaveConfig()
@@ -299,8 +297,6 @@ else
{
var value = e.Value != null ? (ElevationMethod)int.Parse((string)e.Value) : ElevationMethod.None;
await _rpcClientService.CallAsync<bool>("OptionsService", "SetElevationMethod", value);
config!.ElevationMethod = value;
}
private async Task UiTypeOnInput(ChangeEventArgs e)
+2 -2
View File
@@ -18,8 +18,8 @@
<PublisherName>Maassoft</PublisherName>
<Company>Maassoft</Company>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>10.0.0.0</ApplicationVersion>
<Version>10.0.0.0</Version>
<ApplicationVersion>10.0.0.1</ApplicationVersion>
<Version>10.0.0.1</Version>
<UseApplicationTrust>false</UseApplicationTrust>
<PublishWizardCompleted>true</PublishWizardCompleted>
<BootstrapperEnabled>false</BootstrapperEnabled>
+5
View File
@@ -107,6 +107,11 @@ internal class MainWorker
_keyboardShortcutDispatcher.RegisterShortcut(SHORTCUTID_SCREENSAVER, _config.ScreenSaverShortcut);
_keyboardShortcutDispatcher.RegisterEventHandler(KeyboardShortcutDispatcher.Event_HotKey, HandleHotKeyEvent);
if (_config.UiType != UiType.WinForms)
{
await Program.StartUiServer();
}
}
private bool _startupSent = false;
+432 -426
View File
@@ -29,430 +29,436 @@ using System.Windows.Forms;
namespace ColorControl
{
static class Program
{
public const string TS_TASKNAME = "ColorControl";
public static string DataDir { get; private set; }
public static string ConfigFilename { get; private set; }
public static string LogFilename { get; private set; }
public static Config Config { get; private set; }
public static GlobalContext AppContext { get; private set; }
public static bool IsRestarting { get; private set; }
public static bool UserExit = false;
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private static Mutex _mutex;
public static MainForm _mainForm;
private static LoggingRule _loggingRule;
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread] // autogenerated
public static void Main(string[] args)
{
// STA
MainAsync(args).GetAwaiter().GetResult();
}
static async Task MainAsync(string[] args)
{
DataDir = Utils.GetDataPath();
var runAsService = args.Contains("--service") || WinApiService.IsAdministratorStatic() && Process.GetCurrentProcess().Parent()?.ProcessName?.Equals("services", StringComparison.InvariantCultureIgnoreCase) == true;
var runElevated = args.Contains("--elevated");
InitLogger(runAsService, runElevated);
Logger.Debug($"Using data path: {DataDir}");
//Logger.Debug("Parent process: " + Process.GetCurrentProcess().Parent()?.ProcessName);
if (runAsService)
{
await RunService(args);
return;
}
await RunApp(args);
}
static async Task RunApp(string[] args)
{
var startTime = DateTime.Now;
var currentDomain = AppDomain.CurrentDomain;
// Handler for unhandled exceptions.
currentDomain.UnhandledException += GlobalUnhandledExceptionHandler;
// Handler for exceptions in threads behind forms.
Application.ThreadException += GlobalThreadExceptionHandler;
LoadConfig();
if (Config.UseGdiScaling)
{
var result = Application.SetHighDpiMode(HighDpiMode.DpiUnawareGdiScaled);
Logger.Debug($"Result of setting SetHighDpiMode: {result}");
}
var mutexId = $"Global\\{typeof(MainForm).GUID}";
var startUpParams = StartUpParams.Parse(args);
AppContext = new GlobalContext(Config, startUpParams, DataDir, _loggingRule, null, startTime, mutexId);
var host = CreateHostBuilder().Build();
ServiceProvider = host.Services;
AppContext.ServiceProvider = ServiceProvider;
MessageForms.Title = AppContext.ApplicationTitle;
var existingProcess = Utils.GetProcessByName("ColorControl");
try
{
if (await CommandLineHandler.HandleStartupParams(startUpParams, existingProcess))
{
return;
}
}
finally
{
Utils.CloseConsole();
}
_mutex = new Mutex(true, AppContext.MutexId, out var mutexCreated);
try
{
if (!mutexCreated)
{
if (existingProcess != null && existingProcess.Threads.Count > 0)
{
var thread = existingProcess.Threads[0];
NativeMethods.EnumThreadWindows((uint)thread.Id, EnumThreadWindows, IntPtr.Zero);
return;
}
MessageBox.Show("Only one instance of this program can be active.", "ColorControl");
}
else
{
_mutex.WaitOne();
try
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
if (Debugger.IsAttached)
{
//Utils.StartService();
var winApiService = ServiceProvider.GetRequiredService<WinApiService>();
if (winApiService.IsAdministrator())
{
var backgroundService = ServiceProvider.GetRequiredService<ColorControlBackgroundService>();
backgroundService.PipeName = PipeUtils.ElevatedPipe;
Task.Run(async () => await backgroundService.StartAsync(CancellationToken.None));
}
}
var worker = ServiceProvider.GetRequiredService<MainWorker>();
await worker.DoWork();
if (Debugger.IsAttached && !IsRestarting)
{
var winApiAdminService = ServiceProvider.GetRequiredService<WinApiAdminService>();
winApiAdminService.StopService();
}
}
catch (Exception ex)
{
MessageBox.Show("Error while initializing application: " + ex.ToLogString(Environment.StackTrace), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
finally
{
if (mutexCreated)
{
_mutex?.Close();
}
}
}
public static void OpenDefaultUi()
{
var _ = Config.UiType switch
{
UiType.WebDefaultBrowser => OpenNewUi(),
UiType.WebEmbedded => OpenNewUiEmbedded(),
_ => OpenMainForm()
};
}
public static async Task OpenMainForm()
{
_mainForm ??= ServiceProvider.GetRequiredService<MainForm>();
_mainForm.OpenForm();
}
public static void Exit()
{
UserExit = true;
_mainForm?.Close();
if (AppContext.MainHandle != 0)
{
NativeMethods.SendMessageW(AppContext.MainHandle, NativeConstants.WM_CLOSE, 0, 0);
}
}
public static void Restart()
{
IsRestarting = true;
_mainForm?.CloseForRestart();
_mutex?.Close();
_mutex = null;
Application.Restart();
Environment.Exit(0);
}
public static async Task OpenNewUi()
{
await StartUiServer();
var winApi = AppContext.ServiceProvider.GetRequiredService<WinApiAdminService>();
winApi.StartProcess(GetNewUiUrl());
}
public static string GetNewUiUrl()
{
return $"http://localhost:{(Config.UiPort > 0 ? Config.UiPort : 5000)}";
}
public static async Task OpenNewUiEmbedded()
{
await StartUiServer();
BrowserWindow.CreateAndShow(GetNewUiUrl());
}
private static bool UiServerStarted;
private static async Task StartUiServer()
{
if (UiServerStarted)
{
return;
}
var backgroundService = ServiceProvider.GetRequiredService<ColorControlBackgroundService>();
backgroundService.PipeName = PipeUtils.MainPipe;
await backgroundService.StartAsync(CancellationToken.None);
var _ = Task.Run(() => ColorControl.UI.Blazor.Start(Config));
UiServerStarted = true;
await Task.Delay(500);
}
private static void InitLogger(bool runAsService, bool runElevated)
{
var config = new LoggingConfiguration();
// Targets where to log to: File and Console
var logFileAppendix = runAsService ? "_svc" : runElevated ? "_elevated" : "";
LogFilename = Path.Combine(DataDir, $"LogFile{logFileAppendix}.txt");
var logfile = new NLog.Targets.FileTarget("logfile") { FileName = LogFilename };
_loggingRule = new LoggingRule("*", LogLevel.Trace, LogLevel.Fatal, logfile);
_loggingRule.RuleName = "ColorControl";
// Rules for mapping loggers to targets
config.AddRule(_loggingRule);
// Apply config
LogManager.Configuration = config;
}
private static void LoadConfig()
{
ConfigFilename = Path.Combine(DataDir, "Settings.json");
try
{
if (File.Exists(ConfigFilename))
{
var data = File.ReadAllText(ConfigFilename);
Config = JsonConvert.DeserializeObject<Config>(data);
}
}
catch (Exception ex)
{
Logger.Error($"LoadConfig: {ex.Message}");
}
Config ??= new Config();
var minLogLevel = LogLevel.FromString(Config.LogLevel);
if (minLogLevel != LogLevel.Trace)
{
_loggingRule.SetLoggingLevels(minLogLevel, LogLevel.Fatal);
LogManager.ReconfigExistingLoggers();
}
}
public static IServiceProvider ServiceProvider { get; private set; }
private static IHostBuilder CreateHostBuilder()
{
return Host.CreateDefaultBuilder()
.ConfigureServices((context, services) =>
{
//services.AddSingleton<NvService>();
services.RegisterSharedServices();
services.AddSingleton<MainWorker>();
services.AddSingleton<NotifyIconManager>();
services.AddSingleton<LgService>();
services.AddSingleton<GameService>();
services.AddSingleton<SamsungService>();
services.AddSingleton<AmdService>();
services.AddSingleton<PowerEventDispatcher>();
services.AddSingleton<ProcessEventDispatcher>();
services.AddSingleton<WindowMessageDispatcher>();
services.AddSingleton<KeyboardShortcutDispatcher>();
services.AddSingleton<MainForm>();
services.AddSingleton<LogWindow>();
services.AddSingleton<BrowserWindow>();
services.AddTransient<ColorProfileWindow>();
services.AddSingleton<RestartDetector>();
services.AddSingleton<InfoPanel>();
services.AddSingleton<OptionsPanel>();
services.AddSingleton<ElevationService>();
services.AddSingleton<UpdateManager>();
services.AddSingleton<OptionsService>();
services.AddSingleton<LoggingService>();
services.AddSingleton<AmdPanel>();
services.AddSingleton<NvPanel>();
services.AddSingleton<LgPanel>();
services.AddSingleton<SamsungPanel>();
services.AddSingleton<GamePanel>();
});
}
private static async Task RunService(string[] args)
{
var startTime = DateTime.Now;
Logger.Debug("RUNNING SERVICE");
AppContext = new GlobalContext(null, new StartUpParams(), DataDir, _loggingRule, null, startTime);
using IHost host = Host.CreateDefaultBuilder(args)
.UseWindowsService(options =>
{
options.ServiceName = "ColorControl Service";
})
.ConfigureServices(services =>
{
services.RegisterSharedServices();
services.AddSingleton<PowerEventDispatcher>();
services.AddHostedService<ColorControlBackgroundService>();
})
.Build();
ServiceProvider = host.Services;
AppContext.ServiceProvider = ServiceProvider;
await host.RunAsync();
}
private static void RegisterSharedServices(this IServiceCollection services)
{
services.AddSingleton(AppContext);
services.AddSingleton<SessionSwitchDispatcher>();
services.AddSingleton<WinApiAdminService>();
services.AddSingleton<WinApiService>();
services.AddSingleton<WinElevatedProcessManager>();
services.AddTransient<RpcClientService>();
services.AddTransient<RpcServerService>();
services.AddSingleton<NvService>();
services.AddSingleton<WolService>();
services.AddSingleton<ColorControlBackgroundService>();
services.AddSingleton<ServiceManager>();
RpcServerService.ServiceTypes.Add(typeof(NvService));
RpcServerService.ServiceTypes.Add(typeof(GameService));
RpcServerService.ServiceTypes.Add(typeof(OptionsService));
RpcServerService.ServiceTypes.Add(typeof(LoggingService));
RpcServerService.ServiceTypes.Add(typeof(SamsungService));
RpcServerService.ServiceTypes.Add(typeof(LgService));
RpcServerService.ServiceTypes.Add(typeof(AmdService));
}
public static int EnumThreadWindows(IntPtr handle, IntPtr param)
{
NativeMethods.SendMessageW(handle, Utils.WM_BRINGTOFRONT, UIntPtr.Zero, IntPtr.Zero);
return 1;
}
private static void GlobalUnhandledExceptionHandler(object sender, UnhandledExceptionEventArgs e)
{
GlobalHandleException((Exception)e.ExceptionObject, "Unhandled exception");
}
private static void GlobalThreadExceptionHandler(object sender, ThreadExceptionEventArgs e)
{
GlobalHandleException(e.Exception, "Exception in thread");
}
private static void GlobalHandleException(Exception exception, string type)
{
if (UserExit)
{
return;
}
var trace = exception.ToLogString(Environment.StackTrace);
var message = $"{type}: {trace}";
Logger.Error(message);
MessageBox.Show(message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
internal static void SetTheme(bool useDarkMode)
{
DarkModeUtils.SetDarkMode(useDarkMode);
WinApi.RefreshImmersiveColorPolicyState();
DarkModeUtils.InitWpfTheme();
var notifyIconManager = ServiceProvider.GetRequiredService<NotifyIconManager>();
DarkModeUtils.SetContextMenuForeColor(notifyIconManager.NotifyIcon.ContextMenuStrip, FormUtils.CurrentForeColor);
_mainForm?.SetTheme(useDarkMode);
}
internal static NotifyIcon GetNotifyIcon()
{
var notifyIconManager = ServiceProvider.GetRequiredService<NotifyIconManager>();
return notifyIconManager.NotifyIcon;
}
}
static class Program
{
public const string TS_TASKNAME = "ColorControl";
public static string DataDir { get; private set; }
public static string ConfigFilename { get; private set; }
public static string LogFilename { get; private set; }
public static Config Config { get; private set; }
public static GlobalContext AppContext { get; private set; }
public static bool IsRestarting { get; private set; }
public static bool UserExit = false;
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private static Mutex _mutex;
public static MainForm _mainForm;
private static LoggingRule _loggingRule;
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread] // autogenerated
public static void Main(string[] args)
{
// STA
MainAsync(args).GetAwaiter().GetResult();
}
static async Task MainAsync(string[] args)
{
DataDir = Utils.GetDataPath();
var runAsService = args.Contains("--service") || WinApiService.IsAdministratorStatic() && Process.GetCurrentProcess().Parent()?.ProcessName?.Equals("services", StringComparison.InvariantCultureIgnoreCase) == true;
var runElevated = args.Contains("--elevated");
InitLogger(runAsService, runElevated);
Logger.Debug($"Using data path: {DataDir}");
//Logger.Debug("Parent process: " + Process.GetCurrentProcess().Parent()?.ProcessName);
if (runAsService)
{
await RunService(args);
return;
}
await RunApp(args);
}
static async Task RunApp(string[] args)
{
var startTime = DateTime.Now;
var currentDomain = AppDomain.CurrentDomain;
// Handler for unhandled exceptions.
currentDomain.UnhandledException += GlobalUnhandledExceptionHandler;
// Handler for exceptions in threads behind forms.
Application.ThreadException += GlobalThreadExceptionHandler;
LoadConfig();
if (Config.UseGdiScaling)
{
var result = Application.SetHighDpiMode(HighDpiMode.DpiUnawareGdiScaled);
Logger.Debug($"Result of setting SetHighDpiMode: {result}");
}
var mutexId = $"Global\\{typeof(MainForm).GUID}";
var startUpParams = StartUpParams.Parse(args);
AppContext = new GlobalContext(Config, startUpParams, DataDir, _loggingRule, null, startTime, mutexId);
var host = CreateHostBuilder().Build();
ServiceProvider = host.Services;
AppContext.ServiceProvider = ServiceProvider;
MessageForms.Title = AppContext.ApplicationTitle;
var existingProcess = Utils.GetProcessByName("ColorControl");
try
{
if (await CommandLineHandler.HandleStartupParams(startUpParams, existingProcess))
{
return;
}
}
finally
{
Utils.CloseConsole();
}
_mutex = new Mutex(true, AppContext.MutexId, out var mutexCreated);
try
{
if (!mutexCreated)
{
if (existingProcess != null && existingProcess.Threads.Count > 0)
{
var thread = existingProcess.Threads[0];
NativeMethods.EnumThreadWindows((uint)thread.Id, EnumThreadWindows, IntPtr.Zero);
return;
}
MessageBox.Show("Only one instance of this program can be active.", "ColorControl");
}
else
{
_mutex.WaitOne();
try
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
if (Debugger.IsAttached)
{
//Utils.StartService();
var winApiService = ServiceProvider.GetRequiredService<WinApiService>();
if (winApiService.IsAdministrator())
{
var backgroundService = ServiceProvider.GetRequiredService<ColorControlBackgroundService>();
backgroundService.PipeName = PipeUtils.ElevatedPipe;
Task.Run(async () => await backgroundService.StartAsync(CancellationToken.None));
}
}
var worker = ServiceProvider.GetRequiredService<MainWorker>();
await worker.DoWork();
if (Debugger.IsAttached && !IsRestarting)
{
var winApiAdminService = ServiceProvider.GetRequiredService<WinApiAdminService>();
winApiAdminService.StopService();
}
}
catch (Exception ex)
{
MessageBox.Show("Error while initializing application: " + ex.ToLogString(Environment.StackTrace), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
finally
{
if (mutexCreated)
{
_mutex?.Close();
}
}
}
public static void OpenDefaultUi()
{
var _ = Config.UiType switch
{
UiType.WebDefaultBrowser => OpenNewUi(),
UiType.WebEmbedded => OpenNewUiEmbedded(),
_ => OpenMainForm()
};
}
public static async Task OpenMainForm()
{
_mainForm ??= ServiceProvider.GetRequiredService<MainForm>();
_mainForm.OpenForm();
}
public static void Exit()
{
UserExit = true;
_mainForm?.Close();
if (AppContext.MainHandle != 0)
{
NativeMethods.SendMessageW(AppContext.MainHandle, NativeConstants.WM_CLOSE, 0, 0);
}
}
public static void Restart()
{
IsRestarting = true;
_mainForm?.CloseForRestart();
_mutex?.Close();
_mutex = null;
Application.Restart();
Environment.Exit(0);
}
public static async Task OpenNewUi()
{
if (await StartUiServer())
{
await Task.Delay(500);
}
var winApi = AppContext.ServiceProvider.GetRequiredService<WinApiAdminService>();
winApi.StartProcess(GetNewUiUrl());
}
public static string GetNewUiUrl()
{
return $"http://localhost:{(Config.UiPort > 0 ? Config.UiPort : 5000)}";
}
public static async Task OpenNewUiEmbedded()
{
if (await StartUiServer())
{
await Task.Delay(500);
}
BrowserWindow.CreateAndShow(GetNewUiUrl());
}
private static bool UiServerStarted;
public static async Task<bool> StartUiServer()
{
if (UiServerStarted)
{
return false;
}
var backgroundService = ServiceProvider.GetRequiredService<ColorControlBackgroundService>();
backgroundService.PipeName = PipeUtils.MainPipe;
await backgroundService.StartAsync(CancellationToken.None);
var _ = Task.Run(() => ColorControl.UI.Blazor.Start(Config));
UiServerStarted = true;
return true;
}
private static void InitLogger(bool runAsService, bool runElevated)
{
var config = new LoggingConfiguration();
// Targets where to log to: File and Console
var logFileAppendix = runAsService ? "_svc" : runElevated ? "_elevated" : "";
LogFilename = Path.Combine(DataDir, $"LogFile{logFileAppendix}.txt");
var logfile = new NLog.Targets.FileTarget("logfile") { FileName = LogFilename };
_loggingRule = new LoggingRule("*", LogLevel.Trace, LogLevel.Fatal, logfile);
_loggingRule.RuleName = "ColorControl";
// Rules for mapping loggers to targets
config.AddRule(_loggingRule);
// Apply config
LogManager.Configuration = config;
}
private static void LoadConfig()
{
ConfigFilename = Path.Combine(DataDir, "Settings.json");
try
{
if (File.Exists(ConfigFilename))
{
var data = File.ReadAllText(ConfigFilename);
Config = JsonConvert.DeserializeObject<Config>(data);
}
}
catch (Exception ex)
{
Logger.Error($"LoadConfig: {ex.Message}");
}
Config ??= new Config();
var minLogLevel = LogLevel.FromString(Config.LogLevel);
if (minLogLevel != LogLevel.Trace)
{
_loggingRule.SetLoggingLevels(minLogLevel, LogLevel.Fatal);
LogManager.ReconfigExistingLoggers();
}
}
public static IServiceProvider ServiceProvider { get; private set; }
private static IHostBuilder CreateHostBuilder()
{
return Host.CreateDefaultBuilder()
.ConfigureServices((context, services) =>
{
//services.AddSingleton<NvService>();
services.RegisterSharedServices();
services.AddSingleton<MainWorker>();
services.AddSingleton<NotifyIconManager>();
services.AddSingleton<LgService>();
services.AddSingleton<GameService>();
services.AddSingleton<SamsungService>();
services.AddSingleton<AmdService>();
services.AddSingleton<PowerEventDispatcher>();
services.AddSingleton<ProcessEventDispatcher>();
services.AddSingleton<WindowMessageDispatcher>();
services.AddSingleton<KeyboardShortcutDispatcher>();
services.AddSingleton<MainForm>();
services.AddSingleton<LogWindow>();
services.AddSingleton<BrowserWindow>();
services.AddTransient<ColorProfileWindow>();
services.AddSingleton<RestartDetector>();
services.AddSingleton<InfoPanel>();
services.AddSingleton<OptionsPanel>();
services.AddSingleton<ElevationService>();
services.AddSingleton<UpdateManager>();
services.AddSingleton<OptionsService>();
services.AddSingleton<LoggingService>();
services.AddSingleton<AmdPanel>();
services.AddSingleton<NvPanel>();
services.AddSingleton<LgPanel>();
services.AddSingleton<SamsungPanel>();
services.AddSingleton<GamePanel>();
});
}
private static async Task RunService(string[] args)
{
var startTime = DateTime.Now;
Logger.Debug("RUNNING SERVICE");
AppContext = new GlobalContext(null, new StartUpParams(), DataDir, _loggingRule, null, startTime);
using IHost host = Host.CreateDefaultBuilder(args)
.UseWindowsService(options =>
{
options.ServiceName = "ColorControl Service";
})
.ConfigureServices(services =>
{
services.RegisterSharedServices();
services.AddSingleton<PowerEventDispatcher>();
services.AddHostedService<ColorControlBackgroundService>();
})
.Build();
ServiceProvider = host.Services;
AppContext.ServiceProvider = ServiceProvider;
await host.RunAsync();
}
private static void RegisterSharedServices(this IServiceCollection services)
{
services.AddSingleton(AppContext);
services.AddSingleton<SessionSwitchDispatcher>();
services.AddSingleton<WinApiAdminService>();
services.AddSingleton<WinApiService>();
services.AddSingleton<WinElevatedProcessManager>();
services.AddTransient<RpcClientService>();
services.AddTransient<RpcServerService>();
services.AddSingleton<NvService>();
services.AddSingleton<WolService>();
services.AddSingleton<ColorControlBackgroundService>();
services.AddSingleton<ServiceManager>();
RpcServerService.ServiceTypes.Add(typeof(NvService));
RpcServerService.ServiceTypes.Add(typeof(GameService));
RpcServerService.ServiceTypes.Add(typeof(OptionsService));
RpcServerService.ServiceTypes.Add(typeof(LoggingService));
RpcServerService.ServiceTypes.Add(typeof(SamsungService));
RpcServerService.ServiceTypes.Add(typeof(LgService));
RpcServerService.ServiceTypes.Add(typeof(AmdService));
}
public static int EnumThreadWindows(IntPtr handle, IntPtr param)
{
NativeMethods.SendMessageW(handle, Utils.WM_BRINGTOFRONT, UIntPtr.Zero, IntPtr.Zero);
return 1;
}
private static void GlobalUnhandledExceptionHandler(object sender, UnhandledExceptionEventArgs e)
{
GlobalHandleException((Exception)e.ExceptionObject, "Unhandled exception");
}
private static void GlobalThreadExceptionHandler(object sender, ThreadExceptionEventArgs e)
{
GlobalHandleException(e.Exception, "Exception in thread");
}
private static void GlobalHandleException(Exception exception, string type)
{
if (UserExit)
{
return;
}
var trace = exception.ToLogString(Environment.StackTrace);
var message = $"{type}: {trace}";
Logger.Error(message);
MessageBox.Show(message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
internal static void SetTheme(bool useDarkMode)
{
DarkModeUtils.SetDarkMode(useDarkMode);
WinApi.RefreshImmersiveColorPolicyState();
DarkModeUtils.InitWpfTheme();
var notifyIconManager = ServiceProvider.GetRequiredService<NotifyIconManager>();
DarkModeUtils.SetContextMenuForeColor(notifyIconManager.NotifyIcon.ContextMenuStrip, FormUtils.CurrentForeColor);
_mainForm?.SetTheme(useDarkMode);
}
internal static NotifyIcon GetNotifyIcon()
{
var notifyIconManager = ServiceProvider.GetRequiredService<NotifyIconManager>();
return notifyIconManager.NotifyIcon;
}
}
}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+36 -17
View File
@@ -23,9 +23,11 @@ public class AmdPreset : PresetBase
[JsonIgnore]
public string InfoLine { get; private set; }
public static AmdPreset DefaultPreset = new AmdPreset();
public AmdPreset() : base()
{
applyColorData = true;
applyColorData = false;
applyDithering = false;
ditherState = ADLDitherState.DRIVER_DEFAULT;
applyHDR = false;
@@ -39,22 +41,7 @@ public class AmdPreset : PresetBase
{
id = GetNewId();
primaryDisplay = preset.primaryDisplay;
displayName = preset.displayName;
DisplayId = preset.DisplayId;
applyColorData = preset.applyColorData;
colorDepth = preset.colorDepth;
pixelFormat = preset.pixelFormat;
applyHDR = preset.applyHDR;
HDREnabled = preset.HDREnabled;
toggleHDR = preset.toggleHDR;
SDRBrightness = preset.SDRBrightness;
applyDithering = preset.applyDithering;
ditherState = preset.ditherState;
DisplayConfig = new DisplayConfig(DisplayConfig);
Update(preset);
}
public AmdPreset Clone()
@@ -74,6 +61,38 @@ public class AmdPreset : PresetBase
return preset;
}
public void Update(AmdPreset preset)
{
primaryDisplay = preset.primaryDisplay;
displayName = preset.displayName;
DisplayId = preset.DisplayId;
applyColorData = preset.applyColorData;
colorDepth = preset.colorDepth;
pixelFormat = preset.pixelFormat;
applyHDR = preset.applyHDR;
HDREnabled = preset.HDREnabled;
toggleHDR = preset.toggleHDR;
SDRBrightness = preset.SDRBrightness;
applyDithering = preset.applyDithering;
ditherState = preset.ditherState;
DisplayConfig = new DisplayConfig(preset.DisplayConfig);
}
public void UpdateAutoApplySettings(AmdPreset currentSettings = null, bool keepChanges = false)
{
currentSettings ??= DefaultPreset;
applyColorData = keepChanges && applyColorData || colorDepth != currentSettings.colorDepth || pixelFormat != currentSettings.pixelFormat;
applyDithering = keepChanges && applyDithering || ditherState != currentSettings.ditherState;
applyHDR = keepChanges && applyHDR || (HDREnabled != currentSettings.HDREnabled || toggleHDR || SDRBrightness != currentSettings.SDRBrightness);
DisplayConfig.ApplyResolution = keepChanges && DisplayConfig.ApplyResolution || (DisplayConfig.Resolution.IsDifferent(currentSettings.DisplayConfig.Resolution) ||
DisplayConfig.Scaling != currentSettings.DisplayConfig.Scaling || DisplayConfig.Rotation != currentSettings.DisplayConfig.Rotation || DisplayConfig.IsPrimary != null && DisplayConfig.IsPrimary != currentSettings.DisplayConfig.IsPrimary);
DisplayConfig.ApplyRefreshRate = keepChanges && DisplayConfig.ApplyRefreshRate || !DisplayConfig.RefreshRate.Equals(currentSettings.DisplayConfig.RefreshRate);
}
public static string[] GetColumnNames()
{
return new[] { "Name", "Display|140", "Color settings (BPC, format)|260", "Refresh rate|100", "Resolution|120", "Dithering", "HDR", "Shortcut", "Apply on startup" };
+112 -105
View File
@@ -1,115 +1,122 @@
using System.ComponentModel;
namespace ColorControl.Shared.Contracts
{
public enum ElevationMethod
{
None = 0,
RunAsAdmin = 1,
UseService = 2,
UseElevatedProcess = 3
}
public enum ElevationMethod
{
None = 0,
[Description("Run as administrator")]
RunAsAdmin = 1,
[Description("Use service")]
UseService = 2,
[Description("Use elevated process")]
UseElevatedProcess = 3
}
public enum UiType
{
WinForms = 0,
WebDefaultBrowser = 1,
WebEmbedded = 2
}
public enum UiType
{
WinForms = 0,
[Description("Web (default browser)")]
WebDefaultBrowser = 1,
[Description("Web (embedded browser)")]
WebEmbedded = 2
}
public class Config
{
public bool AutoStart { get; set; }
public bool StartMinimized { get; set; }
public bool MinimizeOnClose { get; set; }
public bool MinimizeToTray { get; set; }
public bool CheckForUpdates { get; set; }
public bool AutoInstallUpdates { get; set; }
public bool UseDarkMode { get; set; }
public int DisplaySettingsDelay { get; set; }
public string ScreenSaverShortcut { get; set; }
public int FormWidth { get; set; }
public int FormHeight { get; set; }
public double XFormWidth { get; set; }
public double XFormHeight { get; set; }
public int NvPresetId_ApplyOnStartup { get; set; }
public int AmdPresetId_ApplyOnStartup { get; set; }
public bool FixChromeFonts { get; set; }
public bool UseGdiScaling { get; set; }
public ListViewSortState NvPresetsSortState { get; set; }
public ListViewSortState AmdPresetsSortState { get; set; }
public ListViewSortState LgPresetsSortState { get; set; }
public ListViewSortState SamsungPresetsSortState { get; set; }
public ListViewSortState GamePresetsSortState { get; set; }
public string AmdQuickAccessShortcut { get; set; }
public string LgQuickAccessShortcut { get; set; }
public bool UseDedicatedElevatedProcess { get; set; }
public ElevationMethod ElevationMethod { get; set; }
public bool ElevationMethodAsked { get; set; }
public int ProcessMonitorPollingInterval { get; set; }
public string LogLevel { get; set; }
public List<Module> Modules { get; set; }
public bool UseRawInput { get; set; }
public bool SetMinTmlAndMaxTml { get; set; }
public bool DisableErrorPopupWhenApplyingPreset { get; set; }
public UiType UiType { get; set; }
public int UiPort { get; set; }
public class Config
{
public bool AutoStart { get; set; }
public bool StartMinimized { get; set; }
public bool MinimizeOnClose { get; set; }
public bool MinimizeToTray { get; set; }
public bool CheckForUpdates { get; set; }
public bool AutoInstallUpdates { get; set; }
public bool UseDarkMode { get; set; }
public int DisplaySettingsDelay { get; set; }
public string ScreenSaverShortcut { get; set; }
public int FormWidth { get; set; }
public int FormHeight { get; set; }
public double XFormWidth { get; set; }
public double XFormHeight { get; set; }
public int NvPresetId_ApplyOnStartup { get; set; }
public int AmdPresetId_ApplyOnStartup { get; set; }
public bool FixChromeFonts { get; set; }
public bool UseGdiScaling { get; set; }
public ListViewSortState NvPresetsSortState { get; set; }
public ListViewSortState AmdPresetsSortState { get; set; }
public ListViewSortState LgPresetsSortState { get; set; }
public ListViewSortState SamsungPresetsSortState { get; set; }
public ListViewSortState GamePresetsSortState { get; set; }
public string AmdQuickAccessShortcut { get; set; }
public string LgQuickAccessShortcut { get; set; }
public bool UseDedicatedElevatedProcess { get; set; }
public ElevationMethod ElevationMethod { get; set; }
public bool ElevationMethodAsked { get; set; }
public int ProcessMonitorPollingInterval { get; set; }
public string LogLevel { get; set; }
public List<Module> Modules { get; set; }
public bool UseRawInput { get; set; }
public bool SetMinTmlAndMaxTml { get; set; }
public bool DisableErrorPopupWhenApplyingPreset { get; set; }
public UiType UiType { get; set; }
public int UiPort { get; set; }
public Config()
{
AutoStart = false;
LogLevel = "DEBUG";
DisplaySettingsDelay = 1000;
ScreenSaverShortcut = string.Empty;
FormWidth = 900;
FormHeight = 600;
XFormWidth = 1280;
XFormHeight = 720;
MinimizeToTray = true;
CheckForUpdates = true;
FixChromeFonts = false;
UseGdiScaling = true;
UseDedicatedElevatedProcess = false;
ElevationMethod = ElevationMethod.None;
ElevationMethodAsked = false;
ProcessMonitorPollingInterval = 1000;
UiType = UiType.WinForms;
UiPort = 5000;
LgPresetsSortState = new ListViewSortState();
NvPresetsSortState = new ListViewSortState();
AmdPresetsSortState = new ListViewSortState();
SamsungPresetsSortState = new ListViewSortState();
GamePresetsSortState = new ListViewSortState();
Modules = new List<Module>();
}
public Config()
{
AutoStart = false;
LogLevel = "DEBUG";
DisplaySettingsDelay = 1000;
ScreenSaverShortcut = string.Empty;
FormWidth = 900;
FormHeight = 600;
XFormWidth = 1280;
XFormHeight = 720;
MinimizeToTray = true;
CheckForUpdates = true;
FixChromeFonts = false;
UseGdiScaling = true;
UseDedicatedElevatedProcess = false;
ElevationMethod = ElevationMethod.None;
ElevationMethodAsked = false;
ProcessMonitorPollingInterval = 1000;
UiType = UiType.WinForms;
UiPort = 5000;
LgPresetsSortState = new ListViewSortState();
NvPresetsSortState = new ListViewSortState();
AmdPresetsSortState = new ListViewSortState();
SamsungPresetsSortState = new ListViewSortState();
GamePresetsSortState = new ListViewSortState();
Modules = new List<Module>();
}
public Config(Config config) : this()
{
Update(config);
}
public Config(Config config) : this()
{
Update(config);
}
public void Update(Config config)
{
AutoStart = config.AutoStart;
StartMinimized = config.StartMinimized;
MinimizeOnClose = config.MinimizeOnClose;
MinimizeToTray = config.MinimizeToTray;
CheckForUpdates = config.CheckForUpdates;
AutoInstallUpdates = config.AutoInstallUpdates;
UseDarkMode = config.UseDarkMode;
ScreenSaverShortcut = config.ScreenSaverShortcut;
FixChromeFonts = config.FixChromeFonts;
UseGdiScaling = config.UseGdiScaling;
ProcessMonitorPollingInterval = config.ProcessMonitorPollingInterval;
UseRawInput = config.UseRawInput;
SetMinTmlAndMaxTml = config.SetMinTmlAndMaxTml;
DisableErrorPopupWhenApplyingPreset = config.DisableErrorPopupWhenApplyingPreset;
UiType = config.UiType;
UiPort = config.UiPort;
}
public void Update(Config config)
{
AutoStart = config.AutoStart;
StartMinimized = config.StartMinimized;
MinimizeOnClose = config.MinimizeOnClose;
MinimizeToTray = config.MinimizeToTray;
CheckForUpdates = config.CheckForUpdates;
AutoInstallUpdates = config.AutoInstallUpdates;
UseDarkMode = config.UseDarkMode;
ScreenSaverShortcut = config.ScreenSaverShortcut;
FixChromeFonts = config.FixChromeFonts;
UseGdiScaling = config.UseGdiScaling;
ProcessMonitorPollingInterval = config.ProcessMonitorPollingInterval;
UseRawInput = config.UseRawInput;
SetMinTmlAndMaxTml = config.SetMinTmlAndMaxTml;
DisableErrorPopupWhenApplyingPreset = config.DisableErrorPopupWhenApplyingPreset;
UiType = config.UiType;
UiPort = config.UiPort;
}
public bool HasModule(string name)
{
return Modules?.Any(m => m.DisplayName == name) == true;
}
}
public bool HasModule(string name)
{
return Modules?.Any(m => m.DisplayName == name) == true;
}
}
}