From d0d3bb4682c483b0b2c14a794958abf2d142100e Mon Sep 17 00:00:00 2001 From: Maassoft Date: Sat, 2 May 2026 17:39:33 +0200 Subject: [PATCH] upgrade to .NET, fix webOS 26 compatibility, run new UI in separate process --- ColorControl.UI/Blazor.cs | 93 +++- ColorControl.UI/ColorControl.UI.csproj | 6 +- ColorControl.UI/Components/App.razor | 26 +- .../Components/Pages/AMD/AmdSummary.razor | 9 + .../ColorProfile/ColorProfileSummary.razor | 10 + .../Pages/Game/GamePresetPage.razor | 1 - .../Pages/Generic/CustomComponentBase.cs | 20 + .../Pages/Generic/StartProgramInput.razor | 6 +- .../Pages/Generic/SummaryComponentBase.cs | 13 + .../Pages/Generic/TriggerInput.razor | 23 +- .../Components/Pages/LG/LgDevicePage.razor | 6 +- .../Components/Pages/LG/LgPresetPage.razor | 1 - .../Components/Pages/LG/LgSummary.razor | 9 + .../Pages/Nvidia/NvidiaDithering.razor | 1 - .../Pages/Nvidia/NvidiaDriverSettings.razor | 1 - .../Pages/Nvidia/NvidiaGpuSettings.razor | 1 - .../Components/Pages/Nvidia/NvidiaInfo.razor | 1 - .../Pages/Nvidia/NvidiaPreset.razor | 64 ++- .../Pages/Nvidia/NvidiaSummary.razor | 9 + .../Pages/RemoteControl/GenericRcPage.razor | 1 - .../Pages/Samsung/SamsungDevicePage.razor | 1 - .../Pages/Samsung/SamsungPresetPage.razor | 1 - .../Pages/Samsung/SamsungServiceMenu.razor | 4 +- .../Pages/Samsung/SamsungSummary.razor | 9 + ColorControl.UI/Constants.cs | 2 - ColorControl.UI/Program.cs | 44 +- .../Properties/launchSettings.json | 15 - ColorControl.UI/Services/JSHelper.cs | 5 + .../Services/RpcUiClientService.cs | 11 +- ColorControl.UI/wwwroot/helper.js | 6 +- ColorControl.sln | 111 ---- ColorControl.slnx | 17 + ColorControl/BlazorUiManager.cs | 111 ++++ ColorControl/ColorControl.csproj | 23 +- ColorControl/LgTv/LgTvConnectionCws.cs | 7 +- ColorControl/MainWorker.cs | 2 + ColorControl/Program.cs | 51 +- .../Resources/LG_register_legacy.json | 77 +++ .../Services/Common/GraphicsService.cs | 5 + .../Services/Common/OptionsService.cs | 11 +- ColorControl/Services/Common/UpdateManager.cs | 330 ++++++------ .../Services/GameLauncher/GameService.cs | 2 +- ColorControl/Services/LG/LgDevice.cs | 5 +- ColorControl/Services/LG/LgPanel.Designer.cs | 14 +- ColorControl/Services/LG/LgPanel.cs | 23 +- ColorControl/Services/LG/LgService.cs | 3 +- ColorControl/Services/NVIDIA/NvDisplayInfo.cs | 2 +- ColorControl/Services/NVIDIA/NvPanel.cs | 2 +- ColorControl/Services/NVIDIA/NvService.cs | 122 +++-- .../Services/Samsung/SamsungDevice.cs | 2 +- ColorControl/Services/Samsung/SamsungPanel.cs | 21 +- .../Svc/ColorControlBackgroundService.cs | 16 +- ColorControl/XForms/BrowserWindow.xaml | 2 +- ColorControl/XForms/BrowserWindow.xaml.cs | 33 +- ColorControl/XForms/ColorProfileViewModel.cs | 490 +++++++++--------- ColorControl/XForms/ColorProfileWindow.xaml | 14 +- .../XForms/ColorProfileWindow.xaml.cs | 4 + ColorControl/lgtv/LgTvApi.cs | 51 +- LittleCms/LittleCms.csproj | 2 +- MHC2Gen/IccContext.cs | 8 +- MHC2Gen/MHC2Gen.csproj | 2 +- NLogViewer/NLogViewer.csproj | 6 +- Nspector/Nspector.csproj | 6 +- Nspector/nspector/CustomSettingNames.xml | 139 ++++- NvAPIWrapper/NvAPIWrapper.csproj | 2 +- README.md | 4 +- Shared/Common/GlobalContext.cs | 2 + Shared/Common/Utils.cs | 109 ++-- Shared/Contracts/Config.cs | 6 +- Shared/Contracts/DisplayConfig.cs | 2 + Shared/Contracts/DisplayEnums.cs | 8 + Shared/Contracts/LG/LgDeviceOptions.cs | 4 +- Shared/Contracts/NVIDIA/NvPreset.cs | 10 +- Shared/Contracts/Presets/PresetBase.cs | 29 +- Shared/Contracts/Samsung/SamsungPresets.cs | 12 +- Shared/Native/CCD.cs | 77 ++- Shared/Services/WinApiAdminService.cs | 23 + Shared/Shared.csproj | 17 +- novideo_srgb/MainViewModel.cs | 2 +- novideo_srgb/novideo_srgb.csproj | 9 +- 80 files changed, 1517 insertions(+), 912 deletions(-) create mode 100644 ColorControl.UI/Components/Pages/Generic/CustomComponentBase.cs create mode 100644 ColorControl.UI/Components/Pages/Generic/SummaryComponentBase.cs delete mode 100644 ColorControl.sln create mode 100644 ColorControl.slnx create mode 100644 ColorControl/BlazorUiManager.cs create mode 100644 ColorControl/Resources/LG_register_legacy.json create mode 100644 Shared/Contracts/DisplayEnums.cs diff --git a/ColorControl.UI/Blazor.cs b/ColorControl.UI/Blazor.cs index 6f0310d..d6f808c 100644 --- a/ColorControl.UI/Blazor.cs +++ b/ColorControl.UI/Blazor.cs @@ -1,7 +1,10 @@ +using ColorControl.Shared.Common; using ColorControl.Shared.Contracts; +using ColorControl.UI.Pages.Generic; using ColorControl.UI.Services; using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Hosting.Server.Features; +using NStandard; using System.Net; namespace ColorControl.UI; @@ -9,17 +12,15 @@ namespace ColorControl.UI; public static class Blazor { private static WebApplication? CurrentApplication; - private static int Port; - private static bool AllowRemoteConnections; - public static bool IsRunning(Config config) => CurrentApplication != null && Port == config.UiPort && AllowRemoteConnections == config.UiAllowRemoteConnections; + public static CustomComponentBase? CurrentComponent { get; private set; } - public static async Task Start(Config config) + public static async Task Start(string[] args) { - if (IsRunning(config)) - { - return; - } + var mutexId = args.GetValueOrDefault(0); + var useDarkMode = args.GetValueOrDefault(1) == "True"; + var uiPort = Utils.ParseInt(args.GetValueOrDefault(2)); + var allowRemoteConnections = args.GetValueOrDefault(3) == "True"; await Stop(); @@ -29,7 +30,7 @@ public static class Blazor builder.Services.AddRazorComponents() .AddInteractiveServerComponents(); - builder.Services.AddSingleton(new AppState { SelectedTheme = config.UseDarkMode ? "dark" : "light" }); + builder.Services.AddSingleton(new AppState { SelectedTheme = useDarkMode ? "dark" : "light" }); builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddHttpContextAccessor(); @@ -37,11 +38,11 @@ public static class Blazor builder.Services.Configure(opts => opts.ShutdownTimeout = TimeSpan.FromSeconds(3)); - var listenPort = config.UiPort > 0 ? config.UiPort : 0; + var listenPort = uiPort > 0 ? uiPort : 0; builder.WebHost.ConfigureKestrel(options => { - if (config.UiAllowRemoteConnections) + if (allowRemoteConnections) { options.ListenAnyIP(listenPort); } @@ -51,6 +52,8 @@ public static class Blazor } }); + builder.WebHost.UseStaticWebAssets(); + var app = builder.Build(); // Configure the HTTP request pipeline. @@ -61,17 +64,56 @@ public static class Blazor app.UseHsts(); } - app.UseHttpsRedirection(); + app.UseStatusCodePagesWithReExecute("/not-found", createScopeForStatusCodePages: true); + //app.UseHttpsRedirection(); - app.UseStaticFiles(); app.UseAntiforgery(); + app.MapStaticAssets(); + //app.UsePathBase("/"); + app.MapRazorComponents() .AddInteractiveServerRenderMode(); CurrentApplication = app; - Port = config.UiPort; - AllowRemoteConnections = config.UiAllowRemoteConnections; + + var _ = Task.Run(async () => + { + await Task.Delay(500); + + var port = GetCurrentPort(); + + if (port == -1) + { + return; + } + + var rpcServer = app.Services.GetRequiredService(); + + await rpcServer.CallAsync("OptionsService", "SetCurrentUiSettings", port, allowRemoteConnections); + + if (!mutexId.IsNullOrWhiteSpace()) + { + Console.WriteLine("Waiting for mutex: " + mutexId); + var mutex = new Mutex(false, mutexId, out var createdNew); + if (createdNew) + { + Console.WriteLine("Mutex was created, skipping."); + return; + } + try + { + mutex.WaitOne(); + Console.WriteLine("Waiting done."); + } + catch (Exception ex) + { + Console.WriteLine("Wait completed: " + ex.Message); + } + + Environment.Exit(0); + } + }); await app.RunAsync(); } @@ -85,14 +127,7 @@ public static class Blazor } } - public static string GetCurrentUrl() - { - var port = GetCurrentPort(); - - return $"http://localhost:{port}"; - } - - public static int GetCurrentPort() + public static int GetCurrentPort(Config? config = null) { if (CurrentApplication == null) { @@ -115,4 +150,16 @@ public static class Blazor return -1; } + public static void SetCurrentComponent(CustomComponentBase? customComponentBase) + { + CurrentComponent = customComponentBase; + } + + public static void ClearCurrentComponent(CustomComponentBase customComponentBase) + { + if (CurrentComponent == customComponentBase) + { + CurrentComponent = null; + } + } } diff --git a/ColorControl.UI/ColorControl.UI.csproj b/ColorControl.UI/ColorControl.UI.csproj index a7de281..1eecbee 100644 --- a/ColorControl.UI/ColorControl.UI.csproj +++ b/ColorControl.UI/ColorControl.UI.csproj @@ -1,15 +1,15 @@  - net9.0-windows + net10.0-windows enable enable - Library None + true - + diff --git a/ColorControl.UI/Components/App.razor b/ColorControl.UI/Components/App.razor index a0ff549..4acc35a 100644 --- a/ColorControl.UI/Components/App.razor +++ b/ColorControl.UI/Components/App.razor @@ -1,5 +1,6 @@ @using ColorControl.Shared.Common @using ColorControl.Shared.Contracts +@using ColorControl.UI.Pages.Generic @using ColorControl.UI.Services @using ColorControl.UI.Components.Pages.Generic @using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage @@ -9,6 +10,7 @@ @inject NavigationManager _navigationManager @inject NotificationService _notificationService @inject ProtectedSessionStorage _sessionStorage +@inject JSHelper _jsHelper @implements IDisposable @attribute [StreamRendering] @@ -20,19 +22,26 @@ + + - - + + - - + + @@ -59,4 +68,13 @@ { AppState.OnChange -= StateHasChanged; } + + [JSInvokable] + public static async Task RefreshSummary(bool isModalShown) + { + if (Blazor.CurrentComponent is SummaryComponentBase summaryComponent && !isModalShown) + { + await summaryComponent.RefreshExternal(); + } + } } \ No newline at end of file diff --git a/ColorControl.UI/Components/Pages/AMD/AmdSummary.razor b/ColorControl.UI/Components/Pages/AMD/AmdSummary.razor index d1fc18a..5480cc9 100644 --- a/ColorControl.UI/Components/Pages/AMD/AmdSummary.razor +++ b/ColorControl.UI/Components/Pages/AMD/AmdSummary.razor @@ -3,10 +3,12 @@ @using ColorControl.Shared.Common @using ColorControl.Shared.Contracts @using ColorControl.Shared.Contracts.AMD +@using ColorControl.UI.Pages.Generic @using ColorControl.UI.Services; @using ColorControl.UI.Components.Pages.Generic @using ColorControl.UI.Generics @using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage +@inherits SummaryComponentBase @rendermode Constants.RenderMode @@ -144,6 +146,13 @@ else private PresetOrder PresetOrder; protected override async Task OnInitializedAsync() + { + await base.OnInitializedAsync(); + + await Refresh(); + } + + protected override async Task Refresh() { await RefreshPresets(); DisplayPresets = await _rpcClientService.CallAsync>("AmdService", "GetDisplayPresets"); diff --git a/ColorControl.UI/Components/Pages/ColorProfile/ColorProfileSummary.razor b/ColorControl.UI/Components/Pages/ColorProfile/ColorProfileSummary.razor index 1c264e8..6c6f968 100644 --- a/ColorControl.UI/Components/Pages/ColorProfile/ColorProfileSummary.razor +++ b/ColorControl.UI/Components/Pages/ColorProfile/ColorProfileSummary.razor @@ -5,7 +5,9 @@ @using ColorControl.Shared.Contracts.DisplayInfo @using ColorControl.UI.Components.Pages.Generic @using ColorControl.UI.Generics +@using ColorControl.UI.Pages.Generic @using ColorControl.UI.Services +@inherits SummaryComponentBase @rendermode Constants.RenderMode @@ -190,7 +192,15 @@ else private FieldDefinition AskHdrAssociationField = new FieldDefinition { Label = "Associate as HDR profile", FieldType = FieldType.CheckBox, Value = false }; + protected override async Task OnInitializedAsync() + { + await base.OnInitializedAsync(); + + await Refresh(); + } + + protected override async Task Refresh() { await RefreshDisplays(); } diff --git a/ColorControl.UI/Components/Pages/Game/GamePresetPage.razor b/ColorControl.UI/Components/Pages/Game/GamePresetPage.razor index 6dc4651..ca0f3cb 100644 --- a/ColorControl.UI/Components/Pages/Game/GamePresetPage.razor +++ b/ColorControl.UI/Components/Pages/Game/GamePresetPage.razor @@ -3,7 +3,6 @@ @using ColorControl.Shared.Contracts.Game @using ColorControl.UI.Services @using ColorControl.UI.Components.Pages.Generic -@using NvAPIWrapper.Native.Display @using ColorControl.Shared.Common @rendermode Constants.RenderMode diff --git a/ColorControl.UI/Components/Pages/Generic/CustomComponentBase.cs b/ColorControl.UI/Components/Pages/Generic/CustomComponentBase.cs new file mode 100644 index 0000000..5f60cf2 --- /dev/null +++ b/ColorControl.UI/Components/Pages/Generic/CustomComponentBase.cs @@ -0,0 +1,20 @@ +using Microsoft.AspNetCore.Components; + +namespace ColorControl.UI.Pages.Generic; + +public abstract class CustomComponentBase : ComponentBase, IDisposable +{ + public void Dispose() + { + GC.SuppressFinalize(this); + + Blazor.ClearCurrentComponent(this); + } + + protected override Task OnInitializedAsync() + { + Blazor.SetCurrentComponent(this); + + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/ColorControl.UI/Components/Pages/Generic/StartProgramInput.razor b/ColorControl.UI/Components/Pages/Generic/StartProgramInput.razor index 4d96f45..f23f9b9 100644 --- a/ColorControl.UI/Components/Pages/Generic/StartProgramInput.razor +++ b/ColorControl.UI/Components/Pages/Generic/StartProgramInput.razor @@ -44,9 +44,9 @@ try { var options = new RpcUiClientOptions - { - Timeout = 60000 - }; + { + Timeout = 60000 + }; var result = await _rpcClientService.CallWithOptionsAsync("GameService", "SelectPath", options); diff --git a/ColorControl.UI/Components/Pages/Generic/SummaryComponentBase.cs b/ColorControl.UI/Components/Pages/Generic/SummaryComponentBase.cs new file mode 100644 index 0000000..e1a2c2c --- /dev/null +++ b/ColorControl.UI/Components/Pages/Generic/SummaryComponentBase.cs @@ -0,0 +1,13 @@ +namespace ColorControl.UI.Pages.Generic; + +public abstract class SummaryComponentBase : CustomComponentBase +{ + protected abstract Task Refresh(); + + public async Task RefreshExternal() + { + await Refresh(); + + await InvokeAsync(StateHasChanged); + } +} \ No newline at end of file diff --git a/ColorControl.UI/Components/Pages/Generic/TriggerInput.razor b/ColorControl.UI/Components/Pages/Generic/TriggerInput.razor index 6d657ba..e6bc838 100644 --- a/ColorControl.UI/Components/Pages/Generic/TriggerInput.razor +++ b/ColorControl.UI/Components/Pages/Generic/TriggerInput.razor @@ -7,16 +7,20 @@ @if (Triggers != null) { - if (!Triggers.Any()) + if (Triggers.Count < 2) {
- +
} foreach (var trigger in Triggers) { +
+ + +
- +
@@ -40,6 +44,11 @@
+ + @if (Triggers.IndexOf(trigger) < Triggers.Count - 1) + { +
+ } } } @@ -49,14 +58,8 @@ private List ConditionLabels = Utils.GetDescriptions(fromValue: 1).ToList(); - public void ConditionsChanged(uint value) + public void ConditionsChanged(uint value, PresetTrigger trigger) { - if (Triggers == null || !Triggers.Any()) - { - return; - } - - var trigger = Triggers.First(); trigger.Conditions = (PresetConditionType)value; } } \ No newline at end of file diff --git a/ColorControl.UI/Components/Pages/LG/LgDevicePage.razor b/ColorControl.UI/Components/Pages/LG/LgDevicePage.razor index 98ddb0d..d92de57 100644 --- a/ColorControl.UI/Components/Pages/LG/LgDevicePage.razor +++ b/ColorControl.UI/Components/Pages/LG/LgDevicePage.razor @@ -1,7 +1,7 @@ @using ColorControl.Shared.Contracts @using ColorControl.Shared.Contracts.LG @using ColorControl.UI.Services -@using NvAPIWrapper.Native.Display +@using Microsoft.AspNetCore.Components.Web @using ColorControl.Shared.Common @using ColorControl.UI.Components.Pages.Generic @@ -154,6 +154,10 @@ +
+ + +
diff --git a/ColorControl.UI/Components/Pages/LG/LgPresetPage.razor b/ColorControl.UI/Components/Pages/LG/LgPresetPage.razor index 0b93fd9..4118c46 100644 --- a/ColorControl.UI/Components/Pages/LG/LgPresetPage.razor +++ b/ColorControl.UI/Components/Pages/LG/LgPresetPage.razor @@ -2,7 +2,6 @@ @using ColorControl.Shared.Contracts.LG @using ColorControl.UI.Services @using ColorControl.UI.Components.Pages.Generic -@using NvAPIWrapper.Native.Display @using ColorControl.Shared.Common @using static ColorControl.UI.Components.Pages.Generic.StepsInput diff --git a/ColorControl.UI/Components/Pages/LG/LgSummary.razor b/ColorControl.UI/Components/Pages/LG/LgSummary.razor index b8820b9..8ebb3e5 100644 --- a/ColorControl.UI/Components/Pages/LG/LgSummary.razor +++ b/ColorControl.UI/Components/Pages/LG/LgSummary.razor @@ -5,10 +5,12 @@ @using ColorControl.Shared.Contracts.NVIDIA @using ColorControl.Shared.Contracts.LG @using ColorControl.UI.Components.Pages.RemoteControl +@using ColorControl.UI.Pages.Generic @using ColorControl.UI.Services; @using ColorControl.UI.Components.Pages.Generic @using ColorControl.UI.Generics @using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage +@inherits SummaryComponentBase @rendermode Constants.RenderMode @@ -239,6 +241,13 @@ else private List RcPresets = [LgPresets.InStartPreset, LgPresets.EzAdjustPreset]; protected override async Task OnInitializedAsync() + { + await base.OnInitializedAsync(); + + await Refresh(); + } + + protected override async Task Refresh() { Config = await _rpcClientService.CallAsync("LgService", "GetConfig"); await RefreshPresets(); diff --git a/ColorControl.UI/Components/Pages/Nvidia/NvidiaDithering.razor b/ColorControl.UI/Components/Pages/Nvidia/NvidiaDithering.razor index 561b5df..8ae675e 100644 --- a/ColorControl.UI/Components/Pages/Nvidia/NvidiaDithering.razor +++ b/ColorControl.UI/Components/Pages/Nvidia/NvidiaDithering.razor @@ -1,7 +1,6 @@ @using ColorControl.Shared.Contracts @using ColorControl.Shared.Contracts.NVIDIA @using ColorControl.UI.Services; -@using NvAPIWrapper.Native.Display @using ColorControl.Shared.Common; @rendermode Constants.RenderMode diff --git a/ColorControl.UI/Components/Pages/Nvidia/NvidiaDriverSettings.razor b/ColorControl.UI/Components/Pages/Nvidia/NvidiaDriverSettings.razor index e86a65c..c34326a 100644 --- a/ColorControl.UI/Components/Pages/Nvidia/NvidiaDriverSettings.razor +++ b/ColorControl.UI/Components/Pages/Nvidia/NvidiaDriverSettings.razor @@ -2,7 +2,6 @@ @using ColorControl.Shared.Contracts.NVIDIA @using ColorControl.UI.Components.Pages.Generic @using ColorControl.UI.Services; -@using NvAPIWrapper.Native.Display @using ColorControl.Shared.Common; @rendermode Constants.RenderMode diff --git a/ColorControl.UI/Components/Pages/Nvidia/NvidiaGpuSettings.razor b/ColorControl.UI/Components/Pages/Nvidia/NvidiaGpuSettings.razor index 3c6d3bd..5b3bb23 100644 --- a/ColorControl.UI/Components/Pages/Nvidia/NvidiaGpuSettings.razor +++ b/ColorControl.UI/Components/Pages/Nvidia/NvidiaGpuSettings.razor @@ -2,7 +2,6 @@ @using ColorControl.Shared.Contracts.NVIDIA @using ColorControl.UI.Components.Pages.Generic @using ColorControl.UI.Services; -@using NvAPIWrapper.Native.Display @using ColorControl.Shared.Common; @rendermode Constants.RenderMode diff --git a/ColorControl.UI/Components/Pages/Nvidia/NvidiaInfo.razor b/ColorControl.UI/Components/Pages/Nvidia/NvidiaInfo.razor index 1320b52..fde3d91 100644 --- a/ColorControl.UI/Components/Pages/Nvidia/NvidiaInfo.razor +++ b/ColorControl.UI/Components/Pages/Nvidia/NvidiaInfo.razor @@ -1,7 +1,6 @@ @using ColorControl.Shared.Contracts @using ColorControl.Shared.Contracts.NVIDIA @using ColorControl.UI.Services; -@using NvAPIWrapper.Native.Display @using ColorControl.Shared.Common; @using static ColorControl.Shared.Common.NestedItemsBuilder diff --git a/ColorControl.UI/Components/Pages/Nvidia/NvidiaPreset.razor b/ColorControl.UI/Components/Pages/Nvidia/NvidiaPreset.razor index 2c853e7..530b0ec 100644 --- a/ColorControl.UI/Components/Pages/Nvidia/NvidiaPreset.razor +++ b/ColorControl.UI/Components/Pages/Nvidia/NvidiaPreset.razor @@ -45,50 +45,62 @@ }
- @if (!Preset.IsDisplayPreset) - { -
-

- - @if (!Preset.IsDisplayPreset) - { - - } - - -

-
-
+
+

+ + @if (!Preset.IsDisplayPreset) + { + + } + + +

+
+
+ @if (!Preset.IsDisplayPreset) + {
- @if (displayPresets != null) + } + @if (displayPresets != null) + { + if (!Preset.IsDisplayPreset) {
- @foreach (var display in displayPresets) { }
-
- - -
} +
+ + +
+ } +
+ +
- } +
@if (resolutions != null) { @@ -745,7 +757,7 @@ ApplyImmediately = false; - Preset = PresetParam == null ? null : PresetParam.CloneWithId(); + Preset = PresetParam?.CloneWithId(); displayPresets = await _rpcClientService.CallAsync>("NvService", "GetDisplayPresets"); if (Preset?.IsDisplayPreset == true) diff --git a/ColorControl.UI/Components/Pages/Nvidia/NvidiaSummary.razor b/ColorControl.UI/Components/Pages/Nvidia/NvidiaSummary.razor index 7243acd..fa03a80 100644 --- a/ColorControl.UI/Components/Pages/Nvidia/NvidiaSummary.razor +++ b/ColorControl.UI/Components/Pages/Nvidia/NvidiaSummary.razor @@ -2,11 +2,13 @@ @using ColorControl.Shared.Contracts @using ColorControl.Shared.Contracts.NVIDIA +@using ColorControl.UI.Pages.Generic @using ColorControl.UI.Services; @using ColorControl.UI.Components.Pages.Generic @using ColorControl.Shared.Common; @using ColorControl.UI.Generics @using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage +@inherits SummaryComponentBase @rendermode Constants.RenderMode @@ -276,6 +278,13 @@ else private PresetOrder PresetOrder; protected override async Task OnInitializedAsync() + { + await base.OnInitializedAsync(); + + await Refresh(); + } + + protected override async Task Refresh() { NvConfig = await _rpcClientService.CallAsync("NvService", "GetConfig"); await RefreshPresets(); diff --git a/ColorControl.UI/Components/Pages/RemoteControl/GenericRcPage.razor b/ColorControl.UI/Components/Pages/RemoteControl/GenericRcPage.razor index 4831ead..abfa2b6 100644 --- a/ColorControl.UI/Components/Pages/RemoteControl/GenericRcPage.razor +++ b/ColorControl.UI/Components/Pages/RemoteControl/GenericRcPage.razor @@ -2,7 +2,6 @@ @using ColorControl.Shared.Contracts.Base @using ColorControl.Shared.Contracts.RemoteControl @using ColorControl.UI.Services -@using NvAPIWrapper.Native.Display @using ColorControl.Shared.Common @using System.Globalization diff --git a/ColorControl.UI/Components/Pages/Samsung/SamsungDevicePage.razor b/ColorControl.UI/Components/Pages/Samsung/SamsungDevicePage.razor index 45316db..7d4a953 100644 --- a/ColorControl.UI/Components/Pages/Samsung/SamsungDevicePage.razor +++ b/ColorControl.UI/Components/Pages/Samsung/SamsungDevicePage.razor @@ -2,7 +2,6 @@ @using ColorControl.Shared.Contracts.Samsung @using ColorControl.UI.Components.Pages.Generic @using ColorControl.UI.Services -@using NvAPIWrapper.Native.Display @using ColorControl.Shared.Common @rendermode Constants.RenderMode diff --git a/ColorControl.UI/Components/Pages/Samsung/SamsungPresetPage.razor b/ColorControl.UI/Components/Pages/Samsung/SamsungPresetPage.razor index 2ded1ab..3587b18 100644 --- a/ColorControl.UI/Components/Pages/Samsung/SamsungPresetPage.razor +++ b/ColorControl.UI/Components/Pages/Samsung/SamsungPresetPage.razor @@ -2,7 +2,6 @@ @using ColorControl.Shared.Contracts.Samsung @using ColorControl.UI.Services @using ColorControl.UI.Components.Pages.Generic -@using NvAPIWrapper.Native.Display @using ColorControl.Shared.Common @using static ColorControl.UI.Components.Pages.Generic.StepsInput diff --git a/ColorControl.UI/Components/Pages/Samsung/SamsungServiceMenu.razor b/ColorControl.UI/Components/Pages/Samsung/SamsungServiceMenu.razor index 3ba85b4..d7e8744 100644 --- a/ColorControl.UI/Components/Pages/Samsung/SamsungServiceMenu.razor +++ b/ColorControl.UI/Components/Pages/Samsung/SamsungServiceMenu.razor @@ -102,8 +102,8 @@ SecondaryAction = FactoryMenuSecondStepEnterWithoutExecute; Fields = [ - AddField("Service Menu - Advanced", null, FieldType.Label, "If the service menu opened and you want to access the Advanced settings, click 'Next >' or click 'Skip' to skip"), - AddField("Advanced Unlock Type", AdvancedUnlockType.TV, subLabel: "Select the desired unlock type for the Advanced section. If the target is a TV choose TV, otherwise choose Monitor") + AddField("Service Menu - Advanced", null, FieldType.Label, "If the service menu opened and you want to access the Advanced settings, click 'Next >' or click 'Skip' to skip. You can also manually enter the unlock codes 0098 (for TV's) and 0038 (for monitors) while the 'Advanced' item is highlighted."), + AddField("Advanced Unlock Type", AdvancedUnlockType.TV, subLabel: "Select the desired unlock type for the Advanced section. If the target is a TV choose TV, otherwise choose Monitor") ]; StateHasChanged(); diff --git a/ColorControl.UI/Components/Pages/Samsung/SamsungSummary.razor b/ColorControl.UI/Components/Pages/Samsung/SamsungSummary.razor index 1617ca7..db67796 100644 --- a/ColorControl.UI/Components/Pages/Samsung/SamsungSummary.razor +++ b/ColorControl.UI/Components/Pages/Samsung/SamsungSummary.razor @@ -5,10 +5,12 @@ @using ColorControl.Shared.Contracts.NVIDIA @using ColorControl.Shared.Contracts.Samsung @using ColorControl.UI.Components.Pages.RemoteControl +@using ColorControl.UI.Pages.Generic @using ColorControl.UI.Services; @using ColorControl.UI.Components.Pages.Generic @using ColorControl.UI.Generics @using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage +@inherits SummaryComponentBase @rendermode Constants.RenderMode @@ -220,6 +222,13 @@ else private PresetOrder PresetOrder; protected override async Task OnInitializedAsync() + { + await base.OnInitializedAsync(); + + await Refresh(); + } + + protected override async Task Refresh() { Config = await _rpcClientService.CallAsync("SamsungService", "GetConfig"); await RefreshPresets(); diff --git a/ColorControl.UI/Constants.cs b/ColorControl.UI/Constants.cs index 0d3ab0c..eaf8fd4 100644 --- a/ColorControl.UI/Constants.cs +++ b/ColorControl.UI/Constants.cs @@ -12,7 +12,5 @@ public static class Constants public const string Light = "light"; public const string Dark = "dark"; - public static IComponentRenderMode RenderMode = new InteractiveServerRenderMode(prerender: false); - } \ No newline at end of file diff --git a/ColorControl.UI/Program.cs b/ColorControl.UI/Program.cs index 0b22c48..c29979d 100644 --- a/ColorControl.UI/Program.cs +++ b/ColorControl.UI/Program.cs @@ -1,32 +1,20 @@ -//using ColorControl.UI; +using ColorControl.Shared.Contracts; +using ColorControl.UI; +using ColorControl.UI.Services; +using System.Diagnostics; -//Blazor.Start(); +var arguments = args; -//var builder = WebApplication.CreateBuilder(args); +if (Debugger.IsAttached) +{ + var rpcServer = new RpcUiClientService(null); + var options = new RpcUiClientOptions + { + Timeout = 10000 + }; -//// Add services to the container. -//builder.Services.AddRazorComponents() -// .AddInteractiveServerComponents(); + var config = await rpcServer.CallWithOptionsAsync("OptionsService", "GetConfig", options); + arguments = ["", config.UseDarkMode.ToString(), config.UiPort.ToString(), config.UiAllowRemoteConnections.ToString()]; +} -//builder.Services.AddSingleton(); -//builder.Services.AddSingleton(); - -//var app = builder.Build(); - -//// Configure the HTTP request pipeline. -//if (!app.Environment.IsDevelopment()) -//{ -// app.UseExceptionHandler("/Error", createScopeForErrors: true); -// // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. -// app.UseHsts(); -//} - -//app.UseHttpsRedirection(); - -//app.UseStaticFiles(); -//app.UseAntiforgery(); - -//app.MapRazorComponents() -// .AddInteractiveServerRenderMode(); - -//app.Run(); +await Blazor.Start(arguments); diff --git a/ColorControl.UI/Properties/launchSettings.json b/ColorControl.UI/Properties/launchSettings.json index b74b9e8..1551d9e 100644 --- a/ColorControl.UI/Properties/launchSettings.json +++ b/ColorControl.UI/Properties/launchSettings.json @@ -1,13 +1,5 @@ { "$schema": "http://json.schemastore.org/launchsettings.json", - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:31433", - "sslPort": 44330 - } - }, "profiles": { "http": { "commandName": "Project", @@ -26,13 +18,6 @@ "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } - }, - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } } } } diff --git a/ColorControl.UI/Services/JSHelper.cs b/ColorControl.UI/Services/JSHelper.cs index 9fbc4b0..9c1562f 100644 --- a/ColorControl.UI/Services/JSHelper.cs +++ b/ColorControl.UI/Services/JSHelper.cs @@ -29,6 +29,11 @@ public class JSHelper(IJSRuntime jsRuntime) await InvokeVoidAsync("CloseModal", id); } + public async Task IsModalShown() + { + return await InvokeAsync("IsModalShown"); + } + public async Task ShowToast(string id) { await InvokeVoidAsync("ShowToast", id); diff --git a/ColorControl.UI/Services/RpcUiClientService.cs b/ColorControl.UI/Services/RpcUiClientService.cs index dd20dce..6867cfc 100644 --- a/ColorControl.UI/Services/RpcUiClientService.cs +++ b/ColorControl.UI/Services/RpcUiClientService.cs @@ -10,7 +10,7 @@ public class RpcUiClientOptions public int Timeout { get; set; } = PipeUtils.DefaultTimeout; } -public class RpcUiClientService(NotificationService notificationService) +public class RpcUiClientService(NotificationService? notificationService) { public string? LastErrorMessage { get; private set; } @@ -46,7 +46,7 @@ public class RpcUiClientService(NotificationService notificationService) return true; } - if (result?.ErrorMessages.Count > 0) + if (result?.ErrorMessages.Count > 0 && notificationService != null) { await notificationService.SendNotificationDirect(new NotificationDto(result.ErrorMessages.First(), Constants.Danger)); } @@ -74,7 +74,7 @@ public class RpcUiClientService(NotificationService notificationService) if (resultJson == null) { - notificationService.SendNotification(new NotificationDto("Unknown communication error", Constants.Danger)); + notificationService?.SendNotification(new NotificationDto("Unknown communication error", Constants.Danger)); return default; } @@ -85,7 +85,10 @@ public class RpcUiClientService(NotificationService notificationService) { LastErrorMessage = resultMessage?.ErrorMessage ?? "Unknown communication error"; - await notificationService.SendNotificationDirect(new NotificationDto(LastErrorMessage, Constants.Danger)); + if (notificationService != null) + { + await notificationService.SendNotificationDirect(new NotificationDto(LastErrorMessage, Constants.Danger)); + } return default; } diff --git a/ColorControl.UI/wwwroot/helper.js b/ColorControl.UI/wwwroot/helper.js index 77a91be..add8a7d 100644 --- a/ColorControl.UI/wwwroot/helper.js +++ b/ColorControl.UI/wwwroot/helper.js @@ -26,4 +26,8 @@ export function GetElementClassName(elementId) { export function NavigateTo(uri, timeout = 0) { setTimeout(() => window.location = uri, timeout); -} \ No newline at end of file +} + +export function IsModalShown() { + return document.getElementsByClassName("modal show").length > 0; +} diff --git a/ColorControl.sln b/ColorControl.sln deleted file mode 100644 index 9d4dbb5..0000000 --- a/ColorControl.sln +++ /dev/null @@ -1,111 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.32014.148 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ColorControl", "ColorControl\ColorControl.csproj", "{A6005D08-70F0-44CB-A384-9219EBA84F21}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nspector", "Nspector\Nspector.csproj", "{76797290-48F5-4A82-86C3-FAD25DAE4500}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NvAPIWrapper", "NvAPIWrapper\NvAPIWrapper.csproj", "{42E2B4A6-6857-4427-AEF1-DF4C7EF8CC7C}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "novideo_srgb", "novideo_srgb\novideo_srgb.csproj", "{A6A97834-7BE1-474A-B92F-A512DB1D5186}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NLogViewer", "NLogViewer\NLogViewer.csproj", "{D5E4D314-CFCD-4859-98FC-68F660AC7FB4}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shared", "Shared\Shared.csproj", "{8F38D6B0-82DA-4DD1-89EB-918D8A18AEB1}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LittleCms", "LittleCms\LittleCms.csproj", "{42D251AE-42AF-4C0D-B163-7C7A13C4A9A6}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MHC2Gen", "MHC2Gen\MHC2Gen.csproj", "{9FDF741F-0ECF-46DB-8671-AB11ACEB9F41}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ColorControl.UI", "ColorControl.UI\ColorControl.UI.csproj", "{85EA3079-BB73-4CE5-A72F-E56906187051}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Debug|x64 = Debug|x64 - Release|Any CPU = Release|Any CPU - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {A6005D08-70F0-44CB-A384-9219EBA84F21}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A6005D08-70F0-44CB-A384-9219EBA84F21}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A6005D08-70F0-44CB-A384-9219EBA84F21}.Debug|x64.ActiveCfg = Debug|Any CPU - {A6005D08-70F0-44CB-A384-9219EBA84F21}.Debug|x64.Build.0 = Debug|Any CPU - {A6005D08-70F0-44CB-A384-9219EBA84F21}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A6005D08-70F0-44CB-A384-9219EBA84F21}.Release|Any CPU.Build.0 = Release|Any CPU - {A6005D08-70F0-44CB-A384-9219EBA84F21}.Release|x64.ActiveCfg = Release|Any CPU - {A6005D08-70F0-44CB-A384-9219EBA84F21}.Release|x64.Build.0 = Release|Any CPU - {76797290-48F5-4A82-86C3-FAD25DAE4500}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {76797290-48F5-4A82-86C3-FAD25DAE4500}.Debug|Any CPU.Build.0 = Debug|Any CPU - {76797290-48F5-4A82-86C3-FAD25DAE4500}.Debug|x64.ActiveCfg = Debug|Any CPU - {76797290-48F5-4A82-86C3-FAD25DAE4500}.Debug|x64.Build.0 = Debug|Any CPU - {76797290-48F5-4A82-86C3-FAD25DAE4500}.Release|Any CPU.ActiveCfg = Release|Any CPU - {76797290-48F5-4A82-86C3-FAD25DAE4500}.Release|Any CPU.Build.0 = Release|Any CPU - {76797290-48F5-4A82-86C3-FAD25DAE4500}.Release|x64.ActiveCfg = Release|Any CPU - {76797290-48F5-4A82-86C3-FAD25DAE4500}.Release|x64.Build.0 = Release|Any CPU - {42E2B4A6-6857-4427-AEF1-DF4C7EF8CC7C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {42E2B4A6-6857-4427-AEF1-DF4C7EF8CC7C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {42E2B4A6-6857-4427-AEF1-DF4C7EF8CC7C}.Debug|x64.ActiveCfg = Debug|Any CPU - {42E2B4A6-6857-4427-AEF1-DF4C7EF8CC7C}.Debug|x64.Build.0 = Debug|Any CPU - {42E2B4A6-6857-4427-AEF1-DF4C7EF8CC7C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {42E2B4A6-6857-4427-AEF1-DF4C7EF8CC7C}.Release|Any CPU.Build.0 = Release|Any CPU - {42E2B4A6-6857-4427-AEF1-DF4C7EF8CC7C}.Release|x64.ActiveCfg = Release|Any CPU - {42E2B4A6-6857-4427-AEF1-DF4C7EF8CC7C}.Release|x64.Build.0 = Release|Any CPU - {A6A97834-7BE1-474A-B92F-A512DB1D5186}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A6A97834-7BE1-474A-B92F-A512DB1D5186}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A6A97834-7BE1-474A-B92F-A512DB1D5186}.Debug|x64.ActiveCfg = Debug|Any CPU - {A6A97834-7BE1-474A-B92F-A512DB1D5186}.Debug|x64.Build.0 = Debug|Any CPU - {A6A97834-7BE1-474A-B92F-A512DB1D5186}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A6A97834-7BE1-474A-B92F-A512DB1D5186}.Release|Any CPU.Build.0 = Release|Any CPU - {A6A97834-7BE1-474A-B92F-A512DB1D5186}.Release|x64.ActiveCfg = Release|Any CPU - {A6A97834-7BE1-474A-B92F-A512DB1D5186}.Release|x64.Build.0 = Release|Any CPU - {D5E4D314-CFCD-4859-98FC-68F660AC7FB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D5E4D314-CFCD-4859-98FC-68F660AC7FB4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D5E4D314-CFCD-4859-98FC-68F660AC7FB4}.Debug|x64.ActiveCfg = Debug|Any CPU - {D5E4D314-CFCD-4859-98FC-68F660AC7FB4}.Debug|x64.Build.0 = Debug|Any CPU - {D5E4D314-CFCD-4859-98FC-68F660AC7FB4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D5E4D314-CFCD-4859-98FC-68F660AC7FB4}.Release|Any CPU.Build.0 = Release|Any CPU - {D5E4D314-CFCD-4859-98FC-68F660AC7FB4}.Release|x64.ActiveCfg = Release|Any CPU - {D5E4D314-CFCD-4859-98FC-68F660AC7FB4}.Release|x64.Build.0 = Release|Any CPU - {8F38D6B0-82DA-4DD1-89EB-918D8A18AEB1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8F38D6B0-82DA-4DD1-89EB-918D8A18AEB1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8F38D6B0-82DA-4DD1-89EB-918D8A18AEB1}.Debug|x64.ActiveCfg = Debug|Any CPU - {8F38D6B0-82DA-4DD1-89EB-918D8A18AEB1}.Debug|x64.Build.0 = Debug|Any CPU - {8F38D6B0-82DA-4DD1-89EB-918D8A18AEB1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8F38D6B0-82DA-4DD1-89EB-918D8A18AEB1}.Release|Any CPU.Build.0 = Release|Any CPU - {8F38D6B0-82DA-4DD1-89EB-918D8A18AEB1}.Release|x64.ActiveCfg = Release|Any CPU - {8F38D6B0-82DA-4DD1-89EB-918D8A18AEB1}.Release|x64.Build.0 = Release|Any CPU - {42D251AE-42AF-4C0D-B163-7C7A13C4A9A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {42D251AE-42AF-4C0D-B163-7C7A13C4A9A6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {42D251AE-42AF-4C0D-B163-7C7A13C4A9A6}.Debug|x64.ActiveCfg = Debug|Any CPU - {42D251AE-42AF-4C0D-B163-7C7A13C4A9A6}.Debug|x64.Build.0 = Debug|Any CPU - {42D251AE-42AF-4C0D-B163-7C7A13C4A9A6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {42D251AE-42AF-4C0D-B163-7C7A13C4A9A6}.Release|Any CPU.Build.0 = Release|Any CPU - {42D251AE-42AF-4C0D-B163-7C7A13C4A9A6}.Release|x64.ActiveCfg = Release|Any CPU - {42D251AE-42AF-4C0D-B163-7C7A13C4A9A6}.Release|x64.Build.0 = Release|Any CPU - {9FDF741F-0ECF-46DB-8671-AB11ACEB9F41}.Debug|Any CPU.ActiveCfg = Debug|x64 - {9FDF741F-0ECF-46DB-8671-AB11ACEB9F41}.Debug|Any CPU.Build.0 = Debug|x64 - {9FDF741F-0ECF-46DB-8671-AB11ACEB9F41}.Debug|x64.ActiveCfg = Debug|x64 - {9FDF741F-0ECF-46DB-8671-AB11ACEB9F41}.Debug|x64.Build.0 = Debug|x64 - {9FDF741F-0ECF-46DB-8671-AB11ACEB9F41}.Release|Any CPU.ActiveCfg = Release|x64 - {9FDF741F-0ECF-46DB-8671-AB11ACEB9F41}.Release|Any CPU.Build.0 = Release|x64 - {9FDF741F-0ECF-46DB-8671-AB11ACEB9F41}.Release|x64.ActiveCfg = Release|x64 - {9FDF741F-0ECF-46DB-8671-AB11ACEB9F41}.Release|x64.Build.0 = Release|x64 - {85EA3079-BB73-4CE5-A72F-E56906187051}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {85EA3079-BB73-4CE5-A72F-E56906187051}.Debug|Any CPU.Build.0 = Debug|Any CPU - {85EA3079-BB73-4CE5-A72F-E56906187051}.Debug|x64.ActiveCfg = Debug|Any CPU - {85EA3079-BB73-4CE5-A72F-E56906187051}.Debug|x64.Build.0 = Debug|Any CPU - {85EA3079-BB73-4CE5-A72F-E56906187051}.Release|Any CPU.ActiveCfg = Release|Any CPU - {85EA3079-BB73-4CE5-A72F-E56906187051}.Release|Any CPU.Build.0 = Release|Any CPU - {85EA3079-BB73-4CE5-A72F-E56906187051}.Release|x64.ActiveCfg = Release|Any CPU - {85EA3079-BB73-4CE5-A72F-E56906187051}.Release|x64.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {34BA158F-AE57-4A7B-A372-11FEFBBC1F98} - EndGlobalSection -EndGlobal diff --git a/ColorControl.slnx b/ColorControl.slnx new file mode 100644 index 0000000..52e2424 --- /dev/null +++ b/ColorControl.slnx @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/ColorControl/BlazorUiManager.cs b/ColorControl/BlazorUiManager.cs new file mode 100644 index 0000000..f75dbe9 --- /dev/null +++ b/ColorControl/BlazorUiManager.cs @@ -0,0 +1,111 @@ +using ColorControl.Shared.Common; +using ColorControl.Shared.Contracts; +using ColorControl.Shared.Services; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Diagnostics; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace ColorControl; + +public static class BlazorUiManager +{ + private const string ImageName = "ColorControl.UI.exe"; + private const string ProcessName = "ColorControl.UI"; + private const bool DebugUi = true; + + private static bool FirsTime = true; + private static Mutex UiMutex; + private static string MutexId; + + public static bool IsRunning(Config config) + { + return Process.GetProcessesByName(ProcessName).Length > 0 && + (config.UiPort == 0 || config.CurrentUiPort == config.UiPort) && + config.CurrentUiAllowRemoteConnections == config.UiAllowRemoteConnections; + } + + public static async Task Start(Config config) + { + if ((!FirsTime || Debugger.IsAttached && DebugUi) && IsRunning(config)) + { + return false; + } + + FirsTime = false; + + await Stop(); + + var uiExe = Path.Combine(Environment.CurrentDirectory, ImageName); + if (!File.Exists(uiExe)) + { + uiExe = Path.Combine(Environment.CurrentDirectory.Replace("ColorControl\\bin", "ColorControl.UI\\bin"), ImageName); + + if (!File.Exists(uiExe)) + { + throw new InvalidOperationException("UI executable not found"); + } + } + + MutexId = $"Global\\{ProcessName}_{Guid.NewGuid()}"; + Utils.ExecuteOnMainThread(() => + { + UiMutex = new Mutex(false, MutexId); + UiMutex.WaitOne(); + }); + + var windowStyle = ProcessWindowStyle.Hidden; + + if (Debugger.IsAttached) + { + windowStyle = ProcessWindowStyle.Normal; + } + + var processStartInfo = new ProcessStartInfo(uiExe, [MutexId, config.UseDarkMode.ToString(), config.UiPort.ToString(), config.UiAllowRemoteConnections.ToString()]) + { + WindowStyle = windowStyle + }; + + Process.Start(processStartInfo); + + return true; + } + + public static async Task Stop() + { + if (UiMutex != null) + { + Utils.ExecuteOnMainThread(() => + { + UiMutex.ReleaseMutex(); + UiMutex.Close(); + UiMutex = null; + }); + return; + } + + var processes = Process.GetProcessesByName(ProcessName); + + if (processes.Length <= 0) + { + return; + } + + var winApi = Program.ServiceProvider.GetRequiredService(); + winApi.StopProcessByName(ProcessName); + } + + public static string GetCurrentUrl(Config config) + { + var port = GetCurrentPort(config); + + return $"http://localhost:{port}"; + } + + public static int GetCurrentPort(Config config = null) + { + return config?.CurrentUiPort ?? -1; + } +} \ No newline at end of file diff --git a/ColorControl/ColorControl.csproj b/ColorControl/ColorControl.csproj index ca0dc71..0841ee2 100644 --- a/ColorControl/ColorControl.csproj +++ b/ColorControl/ColorControl.csproj @@ -1,6 +1,6 @@  - net9.0-windows + net10.0-windows WinExe false publish\ @@ -11,8 +11,8 @@ Maassoft Maassoft 0 - 10.4.0.0 - 10.4.0.0 + 11.0.0.0 + 11.0.0.0 false true false @@ -72,6 +72,7 @@ UserControl + @@ -96,16 +97,14 @@ - - - - - - - + + + + + - - + + diff --git a/ColorControl/LgTv/LgTvConnectionCws.cs b/ColorControl/LgTv/LgTvConnectionCws.cs index 19f2b1a..154d737 100644 --- a/ColorControl/LgTv/LgTvConnectionCws.cs +++ b/ColorControl/LgTv/LgTvConnectionCws.cs @@ -199,6 +199,11 @@ namespace LgTv { try { + if (string.IsNullOrEmpty(message)) + { + throw new InvalidOperationException("Empty response received. Assuming connection closed."); + } + var obj = JsonConvert.DeserializeObject(message); var id = (string)obj.id; var type = (string)obj.type; @@ -217,7 +222,7 @@ namespace LgTv { if (id == "register_0") { - //taskCompletion.TrySetResult(obj.payload); + //taskCompletion.TrySetResult(null); return; } if (obj.type == "error") diff --git a/ColorControl/MainWorker.cs b/ColorControl/MainWorker.cs index 3bfa6b3..000be7c 100644 --- a/ColorControl/MainWorker.cs +++ b/ColorControl/MainWorker.cs @@ -177,6 +177,8 @@ internal class MainWorker private void StartScreenSaver() { + //NativeMethods.SendMessageW(-1, NativeConstants.WM_SYSCOMMAND, NativeConstants.SC_MONITORPOWER, (int)WinApi.MonitorState.OFF); + var screenSaver = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "scrnsave.scr"); Process.Start("explorer.exe", screenSaver); } diff --git a/ColorControl/Program.cs b/ColorControl/Program.cs index acff9e6..6bdff66 100644 --- a/ColorControl/Program.cs +++ b/ColorControl/Program.cs @@ -12,7 +12,6 @@ using ColorControl.Shared.Forms; using ColorControl.Shared.Native; using ColorControl.Shared.Services; using ColorControl.Svc; -using ColorControl.UI; using ColorControl.XForms; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -44,6 +43,7 @@ namespace ColorControl private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); private static Mutex _mutex; + public static string MutexId; public static MainForm _mainForm; private static LoggingRule _loggingRule; @@ -96,11 +96,11 @@ namespace ColorControl Logger.Debug($"Result of setting SetHighDpiMode: {result}"); } - var mutexId = $"Global\\{typeof(MainForm).GUID}"; + MutexId = $"Global\\{typeof(MainForm).GUID}"; var startUpParams = StartUpParams.Parse(args); - AppContext = new GlobalContext(Config, startUpParams, DataDir, _loggingRule, null, startTime, mutexId); + AppContext = new GlobalContext(Config, startUpParams, DataDir, _loggingRule, null, startTime, MutexId); var host = CreateHostBuilder().Build(); ServiceProvider = host.Services; @@ -168,6 +168,8 @@ namespace ColorControl var winApiAdminService = ServiceProvider.GetRequiredService(); winApiAdminService.StopService(); } + + await BlazorUiManager.Stop(); } catch (Exception ex) { @@ -233,31 +235,43 @@ namespace ColorControl public static async Task OpenNewUi() { - if (await StartUiServer()) - { - await Task.Delay(500); - } - - var winApi = AppContext.ServiceProvider.GetRequiredService(); - - winApi.StartProcess(Blazor.GetCurrentUrl()); + await OpenNewUi(false); } public static async Task OpenNewUiEmbedded() + { + await OpenNewUi(true); + } + + public static async Task OpenNewUi(bool embedded) { if (await StartUiServer()) { - await Task.Delay(500); + await Task.Delay(1000); } - BrowserWindow.CreateAndShow(Blazor.GetCurrentUrl()); + if (BlazorUiManager.GetCurrentPort(Config) <= 0) + { + await OpenMainForm(); + return; + } + + if (embedded) + { + BrowserWindow.CreateAndShow(BlazorUiManager.GetCurrentUrl(Config)); + } + else + { + var winApi = AppContext.ServiceProvider.GetRequiredService(); + winApi.StartProcess(BlazorUiManager.GetCurrentUrl(Config)); + } } public static async Task StartOrStopUiServer() { if (Config.UiType == UiType.WinForms) { - var _ = Task.Run(() => UI.Blazor.Stop()); + var _ = Task.Run(() => BlazorUiManager.Stop()); return true; } @@ -266,11 +280,6 @@ namespace ColorControl public static async Task StartUiServer() { - if (UI.Blazor.IsRunning(Config)) - { - return false; - } - var backgroundService = ServiceProvider.GetRequiredService(); if (backgroundService.PipeName != PipeUtils.MainPipe) @@ -280,9 +289,7 @@ namespace ColorControl await backgroundService.StartAsync(CancellationToken.None); } - var _ = Task.Run(() => UI.Blazor.Start(Config)); - - return true; + return await BlazorUiManager.Start(Config); } private static void InitLogger(bool runAsService, bool runElevated) diff --git a/ColorControl/Resources/LG_register_legacy.json b/ColorControl/Resources/LG_register_legacy.json new file mode 100644 index 0000000..bcd828d --- /dev/null +++ b/ColorControl/Resources/LG_register_legacy.json @@ -0,0 +1,77 @@ +{ + "type":"register", + "id":"register_0", + "payload":{ + "forcePairing":false, + "pairingType":"PROMPT", + "client-key":"CLIENTKEYGOESHERE", + "manifest":{ + "manifestVersion":1, + "appVersion":"1.1", + "signed":{ + "created":"20140509", + "appId":"com.lge.test", + "vendorId":"com.lge", + "localizedAppNames":{ + "":"LG Remote App", + "ko-KR":"리모컨 앱", + "zxx-XX":"ЛГ Rэмotэ AПП" + }, + "localizedVendorNames":{ + "":"LG Electronics" + }, + "permissions":[ + "TEST_SECURE", + "CONTROL_INPUT_TEXT", + "CONTROL_MOUSE_AND_KEYBOARD", + "READ_INSTALLED_APPS", + "READ_LGE_SDX", + "READ_NOTIFICATIONS", + "SEARCH", + "WRITE_SETTINGS", + "WRITE_NOTIFICATION_ALERT", + "CONTROL_POWER", + "READ_CURRENT_CHANNEL", + "READ_RUNNING_APPS", + "READ_UPDATE_INFO", + "UPDATE_FROM_REMOTE_APP", + "READ_LGE_TV_INPUT_EVENTS", + "READ_TV_CURRENT_TIME" + ], + "serial":"2f930e2d2cfe083771f68e4fe7bb07" + }, + "permissions":[ + "LAUNCH", + "LAUNCH_WEBAPP", + "APP_TO_APP", + "CLOSE", + "TEST_OPEN", + "TEST_PROTECTED", + "CONTROL_AUDIO", + "CONTROL_DISPLAY", + "CONTROL_INPUT_JOYSTICK", + "CONTROL_INPUT_MEDIA_RECORDING", + "CONTROL_INPUT_MEDIA_PLAYBACK", + "CONTROL_INPUT_TV", + "CONTROL_POWER", + "CONTROL_TV_SCREEN", + "READ_APP_STATUS", + "READ_CURRENT_CHANNEL", + "READ_INPUT_DEVICE_LIST", + "READ_NETWORK_STATE", + "READ_RUNNING_APPS", + "READ_TV_CHANNEL_LIST", + "WRITE_NOTIFICATION_TOAST", + "READ_POWER_STATE", + "READ_COUNTRY_INFO", + "READ_SETTINGS" + ], + "signatures":[ + { + "signatureVersion":1, + "signature":"eyJhbGdvcml0aG0iOiJSU0EtU0hBMjU2Iiwia2V5SWQiOiJ0ZXN0LXNpZ25pbmctY2VydCIsInNpZ25hdHVyZVZlcnNpb24iOjF9.hrVRgjCwXVvE2OOSpDZ58hR+59aFNwYDyjQgKk3auukd7pcegmE2CzPCa0bJ0ZsRAcKkCTJrWo5iDzNhMBWRyaMOv5zWSrthlf7G128qvIlpMT0YNY+n/FaOHE73uLrS/g7swl3/qH/BGFG2Hu4RlL48eb3lLKqTt2xKHdCs6Cd4RMfJPYnzgvI4BNrFUKsjkcu+WD4OO2A27Pq1n50cMchmcaXadJhGrOqH5YmHdOCj5NSHzJYrsW0HPlpuAx/ECMeIZYDh6RMqaFM2DXzdKX9NmmyqzJ3o/0lkk/N97gfVRLW5hA29yeAwaCViZNCP8iC9aO0q9fQojoa7NQnAtw==" + } + ] + } + } +} \ No newline at end of file diff --git a/ColorControl/Services/Common/GraphicsService.cs b/ColorControl/Services/Common/GraphicsService.cs index 01903ac..a26632a 100644 --- a/ColorControl/Services/Common/GraphicsService.cs +++ b/ColorControl/Services/Common/GraphicsService.cs @@ -91,6 +91,11 @@ abstract class GraphicsService : ServiceBase where T : PresetBase, new() currentDisplayConfig.Rotation = displayConfig.Rotation; } + if (displayConfig.Connectivity != DisplayConnectivity.Unchanged) + { + currentDisplayConfig.Connectivity = displayConfig.Connectivity; + } + return CCD.SetDisplayConfig(displayName, currentDisplayConfig, updateRegistry); } diff --git a/ColorControl/Services/Common/OptionsService.cs b/ColorControl/Services/Common/OptionsService.cs index 0538ad5..0067da4 100644 --- a/ColorControl/Services/Common/OptionsService.cs +++ b/ColorControl/Services/Common/OptionsService.cs @@ -2,7 +2,6 @@ using ColorControl.Shared.Contracts; using ColorControl.Shared.EventDispatcher; using ColorControl.Shared.Services; -using ColorControl.UI; using NLog; using System; using System.Collections.Generic; @@ -35,7 +34,7 @@ public class OptionsService public Config GetConfig() { _globalContext.Config.AutoStart = _winApiService.TaskExists(Program.TS_TASKNAME); - _globalContext.Config.CurrentUiPort = Blazor.GetCurrentPort(); + _globalContext.Config.CurrentUiPort = BlazorUiManager.GetCurrentPort(Program.Config); return _globalContext.Config; } @@ -51,6 +50,14 @@ public class OptionsService return true; } + public bool SetCurrentUiSettings(int port, bool allowRemoteConnections) + { + _globalContext.Config.CurrentUiPort = port; + _globalContext.Config.CurrentUiAllowRemoteConnections = allowRemoteConnections; + + return true; + } + public bool SaveSettings() { _serviceManager.Save(); diff --git a/ColorControl/Services/Common/UpdateManager.cs b/ColorControl/Services/Common/UpdateManager.cs index b328428..a2edc79 100644 --- a/ColorControl/Services/Common/UpdateManager.cs +++ b/ColorControl/Services/Common/UpdateManager.cs @@ -12,212 +12,212 @@ namespace ColorControl.Services.Common; public class UpdateManager { - private readonly GlobalContext _globalContext; - private readonly ServiceManager _serviceManager; - private readonly NotifyIconManager _notifyIconManager; - private readonly WinApiService _winApiService; - private readonly WinApiAdminService _winApiAdminService; - private readonly Config _config; + private readonly GlobalContext _globalContext; + private readonly ServiceManager _serviceManager; + private readonly NotifyIconManager _notifyIconManager; + private readonly WinApiService _winApiService; + private readonly WinApiAdminService _winApiAdminService; + private readonly Config _config; - public UpdateManager(GlobalContext globalContext, ServiceManager serviceManager, NotifyIconManager notifyIconManager, WinApiService winApiService, WinApiAdminService winApiAdminService) - { - _globalContext = globalContext; - _serviceManager = serviceManager; - _notifyIconManager = notifyIconManager; - _winApiService = winApiService; - _winApiAdminService = winApiAdminService; - _config = globalContext.Config; - } + public UpdateManager(GlobalContext globalContext, ServiceManager serviceManager, NotifyIconManager notifyIconManager, WinApiService winApiService, WinApiAdminService winApiAdminService) + { + _globalContext = globalContext; + _serviceManager = serviceManager; + _notifyIconManager = notifyIconManager; + _winApiService = winApiService; + _winApiAdminService = winApiAdminService; + _config = globalContext.Config; + } - private void trayIconBalloonTip_Clicked(object sender, EventArgs e) - { - if (_globalContext.UpdateInfo?.HtmlUrl != null) - { - _winApiAdminService.StartProcess(_globalContext.UpdateInfo?.HtmlUrl); - } - } + private void trayIconBalloonTip_Clicked(object sender, EventArgs e) + { + if (_globalContext.UpdateInfo?.HtmlUrl != null) + { + _winApiAdminService.StartProcess(_globalContext.UpdateInfo?.HtmlUrl); + } + } - public async Task CheckForUpdatesAndInstall() - { - var updateInfo = await CheckForUpdates(); + public async Task CheckForUpdatesAndInstall() + { + var updateInfo = await CheckForUpdates(); - if (!updateInfo.UpdateAvailable) - { - return; - } + if (!updateInfo.UpdateAvailable) + { + return; + } - _notifyIconManager.NotifyIcon.BalloonTipClicked += trayIconBalloonTip_Clicked; - var newVersion = updateInfo.NewVersionNumber; + _notifyIconManager.NotifyIcon.BalloonTipClicked += trayIconBalloonTip_Clicked; + var newVersion = updateInfo.NewVersionNumber; - if (!string.IsNullOrEmpty(updateInfo.DownloadUrl) && _winApiService.IsServiceRunning()) - { - if (_config.AutoInstallUpdates) - { - await InstallUpdate(); + if (!string.IsNullOrEmpty(updateInfo.DownloadUrl) && _winApiService.IsServiceRunning()) + { + if (_config.AutoInstallUpdates) + { + await InstallUpdate(); - return; - } + return; + } - if (_notifyIconManager.NotifyIcon.Visible) - { - _notifyIconManager.NotifyIcon.ShowBalloonTip(5000, "Update available", $"Version {newVersion} is available. Click on the Update-button to update", ToolTipIcon.Info); - } - else - { - MessageForms.InfoOk($"New version {newVersion} is available. Click on the Update-button to update", "Update available", $"https://github.com/Maassoft/ColorControl/releases/tag/v{newVersion}"); - } + if (_notifyIconManager.NotifyIcon.Visible) + { + _notifyIconManager.NotifyIcon.ShowBalloonTip(5000, "Update available", $"Version {newVersion} is available. Click on the Update-button to update", ToolTipIcon.Info); + } + else + { + MessageForms.InfoOk($"New version {newVersion} is available. Click on the Update-button to update", "Update available", $"https://github.com/Maassoft/ColorControl/releases/tag/v{newVersion}"); + } - return; - } + return; + } - if (_notifyIconManager.NotifyIcon.Visible) - { - _notifyIconManager.NotifyIcon.ShowBalloonTip(5000, "Update available", $"Version {newVersion} is available. Click to open the GitHub page", ToolTipIcon.Info); - } - else - { - MessageForms.InfoOk($"New version {newVersion} is available. Click on the Help-button to open the GitHub page.", "Update available", $"https://github.com/Maassoft/ColorControl/releases/tag/v{newVersion}"); - } - } + if (_notifyIconManager.NotifyIcon.Visible) + { + _notifyIconManager.NotifyIcon.ShowBalloonTip(5000, "Update available", $"Version {newVersion} is available. Click to open the GitHub page", ToolTipIcon.Info); + } + else + { + MessageForms.InfoOk($"New version {newVersion} is available. Click on the Help-button to open the GitHub page.", "Update available", $"https://github.com/Maassoft/ColorControl/releases/tag/v{newVersion}"); + } + } - public bool UpdateAvailable() => _globalContext.UpdateInfo?.UpdateAvailable == true; + public bool UpdateAvailable() => _globalContext.UpdateInfo?.UpdateAvailable == true; - public async Task CheckForUpdates() - { - if (_globalContext.UpdateInfo != null) - { - return _globalContext.UpdateInfo; - } + public async Task CheckForUpdates() + { + if (_globalContext.UpdateInfo != null) + { + return _globalContext.UpdateInfo; + } - //if (Debugger.IsAttached) - //{ - // return _globalContext.UpdateInfo = new UpdateInfoDto - // { - // UpdateAvailable = true, - // NewVersionNumber = "10.0.0.2", - // DownloadUrl = "http://testurl" - // }; - //} + //if (Debugger.IsAttached) + //{ + // return _globalContext.UpdateInfo = new UpdateInfoDto + // { + // UpdateAvailable = true, + // NewVersionNumber = "10.0.0.2", + // DownloadUrl = "http://testurl" + // }; + //} - if (Debugger.IsAttached) - { - return new UpdateInfoDto(); - } + if (Debugger.IsAttached) + { + return new UpdateInfoDto(); + } - var json = await Utils.GetRestJsonAsync("https://api.github.com/repos/maassoft/colorcontrol/releases/latest"); + var json = await Utils.GetRestJsonAsync("https://api.github.com/repos/maassoft/colorcontrol/releases/latest"); - if (json == null) - { - return new UpdateInfoDto(); - } + if (json == null) + { + return new UpdateInfoDto(); + } - _globalContext.UpdateInfo = GetUpdateInfo(json); + _globalContext.UpdateInfo = GetUpdateInfo(json); - return _globalContext.UpdateInfo; - } + return _globalContext.UpdateInfo; + } - private static UpdateInfoDto GetUpdateInfo(dynamic json) - { - var updateInfo = new UpdateInfoDto(); + private static UpdateInfoDto GetUpdateInfo(dynamic json) + { + var updateInfo = new UpdateInfoDto(); - if (json?.tag_name == null) - { - return updateInfo; - } + if (json?.tag_name == null) + { + return updateInfo; + } - var currentVersion = Application.ProductVersion; - var cvParts = currentVersion.Split("."); + var currentVersion = Application.ProductVersion; + var cvParts = currentVersion.Split("."); - var newVersion = (string)json.tag_name.Value.Substring(1); - var nvParts = newVersion.Split("."); + var newVersion = (string)json.tag_name.Value.Substring(1); + var nvParts = newVersion.Split("."); - bool CompareVersions() - { - var result = true; - var aNumberIsLarger = false; + bool CompareVersions() + { + var result = true; + var aNumberIsLarger = false; - for (var i = 0; i < nvParts.Length; i++) - { - var part = Utils.ParseInt(nvParts[i]); - var cvPart = Utils.ParseInt(cvParts[i]); + for (var i = 0; i < nvParts.Length; i++) + { + var part = Utils.ParseInt(nvParts[i]); + var cvPart = Utils.ParseInt(cvParts[i]); - if (part > cvPart) - { - aNumberIsLarger = true; - break; - } + if (part > cvPart) + { + aNumberIsLarger = true; + break; + } - if (part == cvPart) - { - continue; - } + if (part == cvPart) + { + continue; + } - result = false; - break; - } + result = false; + break; + } - return result && aNumberIsLarger; - } + return result && aNumberIsLarger; + } - updateInfo.NewVersionNumber = newVersion; - updateInfo.UpdateAvailable = nvParts.Length != cvParts.Length || CompareVersions(); + updateInfo.NewVersionNumber = newVersion; + updateInfo.UpdateAvailable = nvParts.Length != cvParts.Length || CompareVersions(); - updateInfo.HtmlUrl = json.html_url.Value; + updateInfo.HtmlUrl = json.html_url.Value; - if (json.assets != null) - { - var asset = json.assets[0]; - updateInfo.DownloadUrl = asset.browser_download_url.Value; - } + if (json.assets != null) + { + var asset = json.assets[0]; + updateInfo.DownloadUrl = asset.browser_download_url.Value; + } - return updateInfo; - } + return updateInfo; + } - public async Task InstallUpdate() - { - if (_globalContext.UpdateInfo?.DownloadUrl == null) - { - return false; - } + public async Task InstallUpdate() + { + if (_globalContext.UpdateInfo?.DownloadUrl == null) + { + return false; + } - if (Debugger.IsAttached) - { - await Task.Delay(5000); - return true; - } + if (Debugger.IsAttached) + { + await Task.Delay(5000); + return true; + } - var message = new SvcInstallUpdateMessage - { - DownloadUrl = _globalContext.UpdateInfo?.DownloadUrl, - ClientPath = new FileInfo(Application.ExecutablePath).Directory.FullName - }; + var message = new SvcInstallUpdateMessage + { + DownloadUrl = _globalContext.UpdateInfo?.DownloadUrl, + ClientPath = new FileInfo(Application.ExecutablePath).Directory.FullName + }; - var result = await PipeUtils.SendMessageAsync(message, 30000); + var result = await PipeUtils.SendMessageAsync(message, 30000); - if (result != null && !result.Result) - { - if (Program.IsMainFormOpened()) - { - MessageForms.ErrorOk($"Error while updating: {result.ErrorMessage}"); - } + if (result != null && !result.Result) + { + if (Program.IsMainFormOpened()) + { + MessageForms.ErrorOk($"Error while updating: {result.ErrorMessage}"); + } - return false; - } + return false; + } - await PipeUtils.SendMessageAsync(SvcMessageType.RestartAfterUpdate); + await PipeUtils.SendMessageAsync(SvcMessageType.RestartAfterUpdate); - if (Program.IsMainFormOpened() && MessageForms.QuestionYesNo("Update installed successfully. Do you want to restart the application?") == DialogResult.Yes) - { - Program.Restart(); - } + if (Program.IsMainFormOpened() && MessageForms.QuestionYesNo("Update installed successfully. Do you want to restart the application?") == DialogResult.Yes) + { + Program.Restart(); + } - return true; - } + return true; + } - public Task RestartAfterUpdate() - { - Program.Restart(); + public Task RestartAfterUpdate() + { + Program.Restart(); - return Task.FromResult(true); - } + return Task.FromResult(true); + } } diff --git a/ColorControl/Services/GameLauncher/GameService.cs b/ColorControl/Services/GameLauncher/GameService.cs index 4efd70f..74ce5a6 100644 --- a/ColorControl/Services/GameLauncher/GameService.cs +++ b/ColorControl/Services/GameLauncher/GameService.cs @@ -337,7 +337,7 @@ namespace ColorControl.Services.GameLauncher public string SelectPath() { - var fileInfo = Utils.SelectFile(); + var fileInfo = Utils.SelectFileFromNonUiThread(_globalContext.SynchronizationContext); if (fileInfo == null) { diff --git a/ColorControl/Services/LG/LgDevice.cs b/ColorControl/Services/LG/LgDevice.cs index f9ee021..a866941 100644 --- a/ColorControl/Services/LG/LgDevice.cs +++ b/ColorControl/Services/LG/LgDevice.cs @@ -107,6 +107,8 @@ namespace ColorControl.Services.LG public bool UseSecureConnection { get; set; } = true; + public bool UseNewHandshake { get; set; } + private List _actionsForGameBar; public List ActionsOnGameBar @@ -311,6 +313,7 @@ namespace ColorControl.Services.LG private void UpdateOptions(LgDeviceOptions options) { UseSecureConnection = options.UseSecureConnection; + UseNewHandshake = options.UseNewHandshake; TurnScreenOffOnScreenSaver = options.TurnScreenOffOnScreenSaver; TurnScreenOnAfterScreenSaver = options.TurnScreenOnAfterScreenSaver; ScreenSaverMinimalDuration = options.ScreenSaverMinimalDuration; @@ -501,7 +504,7 @@ namespace ColorControl.Services.LG try { await DisposeConnection(); - _lgTvApi = await LgTvApi.CreateLgTvApi(IpAddress, retries, UseSecureConnection); + _lgTvApi = await LgTvApi.CreateLgTvApi(IpAddress, retries, UseSecureConnection, UseNewHandshake); //Test(); //_lgTvApi.Test3(); diff --git a/ColorControl/Services/LG/LgPanel.Designer.cs b/ColorControl/Services/LG/LgPanel.Designer.cs index faa6bc7..30afb22 100644 --- a/ColorControl/Services/LG/LgPanel.Designer.cs +++ b/ColorControl/Services/LG/LgPanel.Designer.cs @@ -179,7 +179,7 @@ lblLgPresetConnectedDisplaysRegex.Location = new System.Drawing.Point(475, 404); lblLgPresetConnectedDisplaysRegex.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); lblLgPresetConnectedDisplaysRegex.Name = "lblLgPresetConnectedDisplaysRegex"; - lblLgPresetConnectedDisplaysRegex.Size = new System.Drawing.Size(149, 15); + lblLgPresetConnectedDisplaysRegex.Size = new System.Drawing.Size(148, 15); lblLgPresetConnectedDisplaysRegex.TabIndex = 67; lblLgPresetConnectedDisplaysRegex.Text = "Connected Displays Regex:"; // @@ -330,7 +330,7 @@ lblLgPresetExcludedProcesses.Location = new System.Drawing.Point(475, 370); lblLgPresetExcludedProcesses.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); lblLgPresetExcludedProcesses.Name = "lblLgPresetExcludedProcesses"; - lblLgPresetExcludedProcesses.Size = new System.Drawing.Size(112, 15); + lblLgPresetExcludedProcesses.Size = new System.Drawing.Size(111, 15); lblLgPresetExcludedProcesses.TabIndex = 52; lblLgPresetExcludedProcesses.Text = "Excluded processes:"; // @@ -395,7 +395,7 @@ lblLgPresetTrigger.Location = new System.Drawing.Point(475, 277); lblLgPresetTrigger.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); lblLgPresetTrigger.Name = "lblLgPresetTrigger"; - lblLgPresetTrigger.Size = new System.Drawing.Size(46, 15); + lblLgPresetTrigger.Size = new System.Drawing.Size(47, 15); lblLgPresetTrigger.TabIndex = 45; lblLgPresetTrigger.Text = "Trigger:"; // @@ -834,7 +834,7 @@ clbLgPower.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right; clbLgPower.ColumnWidth = 240; clbLgPower.FormattingEnabled = true; - clbLgPower.Items.AddRange(new object[] { "Power on after startup", "Power on after resume from standby", "Power off on shutdown", "Power off on standby", "Power off when screensaver activates", "Power on when screensaver deactivates", "Power on even after manual power off", "Allow triggers to be fired for this device", "Use Windows power settings to power on", "Use Windows power settings to power off", "Power off when locking the pc", "Power on when unlocking the pc", "Use secure connection" }); + clbLgPower.Items.AddRange(new object[] { "Power on after startup", "Power on after resume from standby", "Power off on shutdown", "Power off on standby", "Power off when screensaver activates", "Power on when screensaver deactivates", "Power on even after manual power off", "Allow triggers to be fired for this device", "Use Windows power settings to power on", "Use Windows power settings to power off", "Power off when locking the pc", "Power on when unlocking the pc", "Use secure connection", "Enable webOS 26 compatibility" }); clbLgPower.Location = new System.Drawing.Point(6, 70); clbLgPower.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); clbLgPower.MultiColumn = true; @@ -860,19 +860,19 @@ mnuLgSettings.ImageScalingSize = new System.Drawing.Size(20, 20); mnuLgSettings.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { miTestPowerOffOn, miNvSettings }); mnuLgSettings.Name = "mnuLgButtons"; - mnuLgSettings.Size = new System.Drawing.Size(168, 48); + mnuLgSettings.Size = new System.Drawing.Size(169, 48); // // miTestPowerOffOn // miTestPowerOffOn.Name = "miTestPowerOffOn"; - miTestPowerOffOn.Size = new System.Drawing.Size(167, 22); + miTestPowerOffOn.Size = new System.Drawing.Size(168, 22); miTestPowerOffOn.Text = "Test power off/on"; miTestPowerOffOn.Click += miTestPowerOffOn_Click; // // miNvSettings // miNvSettings.Name = "miNvSettings"; - miNvSettings.Size = new System.Drawing.Size(167, 22); + miNvSettings.Size = new System.Drawing.Size(168, 22); miNvSettings.Text = "Settings"; miNvSettings.Click += miNvSettings_Click; // diff --git a/ColorControl/Services/LG/LgPanel.cs b/ColorControl/Services/LG/LgPanel.cs index cebfe53..ca737fc 100644 --- a/ColorControl/Services/LG/LgPanel.cs +++ b/ColorControl/Services/LG/LgPanel.cs @@ -321,11 +321,11 @@ namespace ColorControl.Services.LG FormUtils.BuildComboBox(cbxLgPresetTrigger, PresetTriggerType.Reserved5); - if (!string.IsNullOrEmpty(_lgTabMessage)) - { - MessageForms.WarningOk(_lgTabMessage); - _lgTabMessage = null; - } + //if (!string.IsNullOrEmpty(_lgTabMessage)) + //{ + // MessageForms.WarningOk(_lgTabMessage); + // _lgTabMessage = null; + //} } private void FillLgDevices() @@ -349,16 +349,7 @@ namespace ColorControl.Services.LG if (!devices.Any()) { - var message = "It seems there's no LG TV available! Please make sure it's connected to the same network as this PC."; - - if (Visible /*tcMain.SelectedTab == tabLG*/) - { - MessageForms.WarningOk(message); - } - else - { - _lgTabMessage = message; - } + _lgTabMessage = "It seems there's no LG TV available! Please make sure it's connected to the same network as this PC."; } if (cbxLgApps.Items.Count == 0 && device != null) @@ -396,6 +387,7 @@ namespace ColorControl.Services.LG clbLgPower.SetItemChecked(10, device?.PowerOffAfterSessionLock ?? false); clbLgPower.SetItemChecked(11, device?.PowerOnAfterSessionUnlock ?? false); clbLgPower.SetItemChecked(12, device?.UseSecureConnection ?? false); + clbLgPower.SetItemChecked(13, device?.UseNewHandshake ?? false); } finally { @@ -674,6 +666,7 @@ You can also activate this option by using the Expert-button and selecting Wake- device.PowerOffAfterSessionLock = clbLgPower.GetItemChecked(10); device.PowerOnAfterSessionUnlock = clbLgPower.GetItemChecked(11); device.UseSecureConnection = clbLgPower.GetItemChecked(12); + device.UseNewHandshake = clbLgPower.GetItemChecked(13); if (e.Index == 12) { diff --git a/ColorControl/Services/LG/LgService.cs b/ColorControl/Services/LG/LgService.cs index 825c6dc..f9a8ebb 100644 --- a/ColorControl/Services/LG/LgService.cs +++ b/ColorControl/Services/LG/LgService.cs @@ -1174,7 +1174,8 @@ namespace ColorControl.Services.LG TriggersEnabled = d.TriggersEnabled, TurnScreenOffOnScreenSaver = d.TurnScreenOffOnScreenSaver, TurnScreenOnAfterScreenSaver = d.TurnScreenOnAfterScreenSaver, - UseSecureConnection = d.UseSecureConnection + UseSecureConnection = d.UseSecureConnection, + UseNewHandshake = d.UseNewHandshake, }, IsConnected = d.IsConnected(), IsSelected = d == SelectedDevice diff --git a/ColorControl/Services/NVIDIA/NvDisplayInfo.cs b/ColorControl/Services/NVIDIA/NvDisplayInfo.cs index cca371d..63efff9 100644 --- a/ColorControl/Services/NVIDIA/NvDisplayInfo.cs +++ b/ColorControl/Services/NVIDIA/NvDisplayInfo.cs @@ -15,7 +15,7 @@ namespace ColorControl.Services.NVIDIA public string Name { get; private set; } - public string DisplayId { get; private set; } + public string DisplayId { get; set; } public NvDisplayInfo(Display display, List values, string infoLine, string name = null) { diff --git a/ColorControl/Services/NVIDIA/NvPanel.cs b/ColorControl/Services/NVIDIA/NvPanel.cs index aa75160..7b75a9a 100644 --- a/ColorControl/Services/NVIDIA/NvPanel.cs +++ b/ColorControl/Services/NVIDIA/NvPanel.cs @@ -1214,7 +1214,7 @@ namespace ColorControl.Services.NVIDIA if (preset.IsDisplayPreset) { - _nvService.SetHDRState(preset.Display, !_nvService.IsHDREnabled()); + _nvService.SetHDRState(preset.Display, !NvService.IsHDREnabled(preset.Display)); UpdateDisplayInfoItems(); return; diff --git a/ColorControl/Services/NVIDIA/NvService.cs b/ColorControl/Services/NVIDIA/NvService.cs index 12aeadd..3d8d57a 100644 --- a/ColorControl/Services/NVIDIA/NvService.cs +++ b/ColorControl/Services/NVIDIA/NvService.cs @@ -235,7 +235,7 @@ namespace ColorControl.Services.NVIDIA } } - public Display GetCurrentDisplay(bool checkDisplays = true) + public Display GetCurrentDisplay(bool checkDisplays = true, bool useFirstIfNoneSet = true) { if (checkDisplays && !HasDisplaysAttached()) { @@ -243,7 +243,7 @@ namespace ColorControl.Services.NVIDIA return null; } - if (_currentDisplay == null) + if (_currentDisplay == null && useFirstIfNoneSet) { _currentDisplay = Display.GetDisplays()[0]; } @@ -396,7 +396,7 @@ namespace ColorControl.Services.NVIDIA var display = await WaitForDisplayAsync(preset); - if (display == null) + if (display == null && preset.DisplayConfig.Connectivity != DisplayConnectivity.Enabled) { var error = $"Cannot apply preset {preset.IdOrName} because the associated display is not active/found"; @@ -405,6 +405,9 @@ namespace ColorControl.Services.NVIDIA return GenericBoolResult.FromError(error); } + //ReadDDC(display); + //WriteDDC(display, 0, 0); + if (preset.DdcSettings.ApplyDdc) { var ddcResult = await ApplyDdcSettings(display, preset.DdcSettings); @@ -414,7 +417,7 @@ namespace ColorControl.Services.NVIDIA } } - var hdrEnabled = IsHDREnabled(); + var hdrEnabled = IsHDREnabled(display); var newHdrEnabled = preset.applyHDR && (preset.HDREnabled || (preset.toggleHDR && !hdrEnabled)); var applyHdr = preset.applyHDR && (preset.toggleHDR || preset.HDREnabled != hdrEnabled); @@ -427,11 +430,14 @@ namespace ColorControl.Services.NVIDIA if ((preset.DisplayConfig.ApplyRefreshRate && preset.DisplayConfig.RefreshRate.MilliValue < timing.Extra.FrequencyInMillihertz) || (preset.DisplayConfig.ApplyResolution && preset.DisplayConfig.Resolution.ActiveWidth < timing.HorizontalVisible)) { - SetMode(preset.DisplayConfig, true); + SetMode(preset.DisplayConfig, true, displayId: preset.DisplayId); } } - SetColorData(display, preset.colorData); + if (!SetColorData(display, preset.colorData)) + { + result.AddError("Could not apply color settings"); + } } if (preset.applyHDR) @@ -457,9 +463,9 @@ namespace ColorControl.Services.NVIDIA } } - if (preset.DisplayConfig.ApplyRefreshRate || preset.DisplayConfig.ApplyResolution) + if (preset.DisplayConfig.ApplyRefreshRate || preset.DisplayConfig.ApplyResolution || preset.DisplayConfig.IsPrimary != null || preset.DisplayConfig.Connectivity != DisplayConnectivity.Unchanged) { - if (!SetMode(preset.DisplayConfig, true)) + if (!SetMode(preset.DisplayConfig, true, displayId: preset.DisplayId)) { result.AddError(WinError.GetMessage()); } @@ -531,6 +537,8 @@ namespace ColorControl.Services.NVIDIA PresetApplied(); GetDisplayInfos(false); + _currentDisplay = null; + return result; } @@ -1068,15 +1076,15 @@ namespace ColorControl.Services.NVIDIA return SetMode(display.Name, resolution, refreshRate, updateRegistry); } - public bool SetMode(DisplayConfig displayConfig, bool updateRegistry = false, NvPreset preset = null) + public bool SetMode(DisplayConfig displayConfig, bool updateRegistry = false, NvPreset preset = null, string displayId = null) { - var display = preset == null ? GetCurrentDisplay() : GetPresetDisplay(preset); - if (display == null) + var display = preset == null ? GetCurrentDisplay(useFirstIfNoneSet: false) : GetPresetDisplay(preset); + if (display == null && displayId == null) { return false; } - return SetMode(display.Name, displayConfig, updateRegistry); + return SetMode(display?.Name ?? displayId, displayConfig, updateRegistry); } public List GetAvailableRefreshRatesV2(NvPreset preset = null) @@ -1141,9 +1149,8 @@ namespace ColorControl.Services.NVIDIA } } - public bool IsHDREnabled(Display currentDisplay = null) + public static bool IsHDREnabled(Display display) { - var display = currentDisplay ?? GetCurrentDisplay(); if (display == null) { return false; @@ -1325,29 +1332,54 @@ namespace ColorControl.Services.NVIDIA CCD.SetDisplayDefaultColorProfile(display.Name, name, _globalContext.Config.SetMinTmlAndMaxTml, IsHDREnabled(display)); } - //public void WriteDDC(Display display, byte vcpCode, uint value) - //{ - // if (display == null) - // { - // return; - // } + public void ReadDDC(Display display) + { + if (display == null) + { + return; + } - // byte i2cDeviceAddr = 0x37; + byte i2cDeviceAddr = 0x37; - // //short value = 8704; + //short value = 8704; - // //var data = new byte[] { 0x84, 0x03, 0x10, 0x00, 0x64, 0xDD }; - // //var data = new byte[] { 0x84, 0x03, 0x15, 0x00, 0x2D, 0xDD }; - // var value1 = (byte)(value >> 8); - // var value2 = (byte)(value & 0xFF); - // var data = new byte[] { 0x84, 0x03, vcpCode, value1, value2, 0xDD }; + //var data = new byte[] { 0x84, 0x03, 0x10, 0x00, 0x64, 0xDD }; + //var data = new byte[] { 0x84, 0x03, 0x15, 0x00, 0x2D, 0xDD }; - // I2CInfoV3.FillDDCCIChecksum((byte)(i2cDeviceAddr << 1), [0x51], data); + var info = new I2CInfoV2(display.Output.OutputId, true, i2cDeviceAddr, [0x51], 256); - // var info = new I2CInfoV2(display.Output.OutputId, true, i2cDeviceAddr, [0x51], data); + var data = display.DisplayDevice.PhysicalGPU.ReadI2C(info); - // display.DisplayDevice.PhysicalGPU.WriteI2C(info); - //} + File.WriteAllBytes($"d:\\ddc\\lg_data.dat", data); + } + + public void WriteDDC(Display display, byte vcpCode, uint value) + { + if (display == null) + { + return; + } + + // Switch input + vcpCode = 0xF4; + value = 0x91; + + byte i2cDeviceAddr = 0x37; + + //short value = 8704; + + //var data = new byte[] { 0x84, 0x03, 0x10, 0x00, 0x64, 0xDD }; + //var data = new byte[] { 0x84, 0x03, 0x15, 0x00, 0x2D, 0xDD }; + var value1 = (byte)(value >> 8); + var value2 = (byte)(value & 0xFF); + var data = new byte[] { 0x84, 0x03, vcpCode, value1, value2, 0xDD }; + + I2CInfoV3.FillDDCCIChecksum((byte)(i2cDeviceAddr << 1), [0x50], data); + + var info = new I2CInfoV2(display.Output.OutputId, true, i2cDeviceAddr, [0x50], data); + + display.DisplayDevice.PhysicalGPU.WriteI2C(info); + } public GenericResult GetVcpInfo(string displayId, byte vcpCode) { @@ -1518,6 +1550,16 @@ namespace ColorControl.Services.NVIDIA list.Add(displayInfo); } + //foreach (var display in WindowsDisplayAPI.UnAttachedDisplay.GetUnAttachedDisplays()) + //{ + // var displayInfo = new NvDisplayInfo(null, null, null, display.DeviceName) + // { + // DisplayId = CCD.GetDisplayIdByPath(display.DevicePath) + // }; + + // list.Add(displayInfo); + //} + return list; } @@ -1537,6 +1579,12 @@ namespace ColorControl.Services.NVIDIA foreach (var displayInfo in displayInfos) { var preset = GetPresetForDisplay(displayInfo, true, displayInfos.Count()); + + if (preset == null) + { + continue; + } + var values = preset.GetDisplayValues(_globalContext.Config); displayInfo.Values = values; @@ -1574,8 +1622,11 @@ namespace ColorControl.Services.NVIDIA foreach (var displayInfo in displayInfos) { var preset = GetPresetForDisplay(displayInfo, true, displayInfos.Count()); - preset.MonitorConnectionType = preset?.Display?.DisplayDevice?.ConnectionType ?? NvAPIWrapper.Native.GPU.MonitorConnectionType.Unknown; - list.Add(preset); + if (preset != null) + { + preset.MonitorConnectionType = preset?.Display?.DisplayDevice?.ConnectionType ?? NvAPIWrapper.Native.GPU.MonitorConnectionType.Unknown; + list.Add(preset); + } } return list; @@ -1604,6 +1655,11 @@ namespace ColorControl.Services.NVIDIA var display = displayInfo.Display; + if (display == null) + { + return new NvPreset { displayName = displayInfo.Name, DisplayId = displayInfo.DisplayId }; + } + var isPrimaryDisplay = displayCount == 1 || display.DisplayDevice.DisplayId == DisplayDevice.GetGDIPrimaryDisplayDevice()?.DisplayId; var preset = new NvPreset { Display = display, IsDisplayPreset = true, applyColorData = false, primaryDisplay = isPrimaryDisplay }; diff --git a/ColorControl/Services/Samsung/SamsungDevice.cs b/ColorControl/Services/Samsung/SamsungDevice.cs index b721f4b..1cfd424 100644 --- a/ColorControl/Services/Samsung/SamsungDevice.cs +++ b/ColorControl/Services/Samsung/SamsungDevice.cs @@ -813,7 +813,7 @@ namespace ColorControl.Services.Samsung new FieldDefinition { Label = "Service Menu - Advanced", - SubLabel = "If the service menu opened and you want to access the Advanced settings, click 'Next >' or click 'X' to skip", + SubLabel = "If the service menu opened and you want to access the Advanced settings, manually navigate to 'Advanced' first and then click 'Next >' or click 'X' to skip. You can also manually enter the unlock codes 0098 (for TV's) and 0038 (for monitors) while the 'Advanced' item is highlighted.", FieldType = FieldType.Label } }, okButtonText: "Next >"); diff --git a/ColorControl/Services/Samsung/SamsungPanel.cs b/ColorControl/Services/Samsung/SamsungPanel.cs index fd85d52..6098fb2 100644 --- a/ColorControl/Services/Samsung/SamsungPanel.cs +++ b/ColorControl/Services/Samsung/SamsungPanel.cs @@ -328,11 +328,11 @@ namespace ColorControl.Services.Samsung FormUtils.BuildComboBox(cbxSamsungPresetTrigger, PresetTriggerType.Reserved5); - if (!string.IsNullOrEmpty(_tabMessage)) - { - MessageForms.WarningOk(_tabMessage); - _tabMessage = null; - } + //if (!string.IsNullOrEmpty(_tabMessage)) + //{ + // MessageForms.WarningOk(_tabMessage); + // _tabMessage = null; + //} } private void FillSamsungDevices() @@ -361,16 +361,7 @@ namespace ColorControl.Services.Samsung if (!devices.Any()) { - var message = "It seems there's no Samsung TV available! Please make sure it's connected to the same network as this PC."; - - if (Visible) - { - MessageForms.WarningOk(message); - } - else - { - _tabMessage = message; - } + _tabMessage = "It seems there's no Samsung TV available! Please make sure it's connected to the same network as this PC."; } //if (cbxSamsungApps.Items.Count == 0 && device != null) diff --git a/ColorControl/Svc/ColorControlBackgroundService.cs b/ColorControl/Svc/ColorControlBackgroundService.cs index c0e76b1..15a8b87 100644 --- a/ColorControl/Svc/ColorControlBackgroundService.cs +++ b/ColorControl/Svc/ColorControlBackgroundService.cs @@ -88,9 +88,19 @@ namespace ColorControl.Svc { Logger.Error(ex, $"Error while handling message: {message}"); - var result = SvcResultMessage.FromResult(false, ex.Message); - var resultJson = JsonConvert.SerializeObject(result); - ss.WriteString(resultJson); + if (!ex.Message.Contains("Pipe is broken")) + { + try + { + var result = SvcResultMessage.FromResult(false, ex.Message); + var resultJson = JsonConvert.SerializeObject(result); + ss.WriteString(resultJson); + } + catch (Exception ex2) + { + Logger.Error(ex2, $"Error while sending error message: {ex.Message}"); + } + } } pipeServer.Close(); diff --git a/ColorControl/XForms/BrowserWindow.xaml b/ColorControl/XForms/BrowserWindow.xaml index 0dcfa69..2751c1b 100644 --- a/ColorControl/XForms/BrowserWindow.xaml +++ b/ColorControl/XForms/BrowserWindow.xaml @@ -16,6 +16,6 @@ d:DesignHeight="720" d:DesignWidth="1280" Loaded="Window_Loaded"> + Source="{Binding Url}" NavigationStarting="webView_NavigationStarting" NavigationCompleted="webView_NavigationCompleted"/> \ No newline at end of file diff --git a/ColorControl/XForms/BrowserWindow.xaml.cs b/ColorControl/XForms/BrowserWindow.xaml.cs index 8f6dfc3..6edebeb 100644 --- a/ColorControl/XForms/BrowserWindow.xaml.cs +++ b/ColorControl/XForms/BrowserWindow.xaml.cs @@ -1,6 +1,5 @@ using ColorControl.Shared.Common; using ColorControl.Shared.XForms; -using ColorControl.UI; using Microsoft.Extensions.DependencyInjection; using System; using System.ComponentModel; @@ -46,16 +45,22 @@ public partial class BrowserWindow : BaseWindow var reload = _window != null && _window._currentUrl != url; + //if (reload && _window != null) + //{ + // _window.Close(); + // _window = null; + //} + _window ??= Program.ServiceProvider.GetRequiredService(); + _window.Url = url; + _window._currentUrl = url; + if (reload) + { + _window.webView.Source = new Uri(url); + } if (show) { - _window.Url = url; - _window._currentUrl = url; - if (reload) - { - _window.webView.Source = new Uri(url); - } _window.WindowState = WindowState.Normal; _window.Show(); _window.Topmost = true; @@ -112,11 +117,23 @@ public partial class BrowserWindow : BaseWindow { e.Cancel = true; - var port = Blazor.GetCurrentPort(); + var port = BlazorUiManager.GetCurrentPort(Program.Config); var newUrl = e.Uri.Replace(":0/", $":{port}/"); CreateAndShow(newUrl); } } + + private void webView_NavigationCompleted(object sender, Microsoft.Web.WebView2.Core.CoreWebView2NavigationCompletedEventArgs e) + { + if (e.WebErrorStatus > 0) + { + var port = BlazorUiManager.GetCurrentPort(Program.Config); + + var newUrl = $"http://localhost:{port}"; + + CreateAndShow(newUrl, false); + } + } } \ No newline at end of file diff --git a/ColorControl/XForms/ColorProfileViewModel.cs b/ColorControl/XForms/ColorProfileViewModel.cs index ed8c4f7..47ae3fd 100644 --- a/ColorControl/XForms/ColorProfileViewModel.cs +++ b/ColorControl/XForms/ColorProfileViewModel.cs @@ -17,306 +17,310 @@ namespace ColorControl.XForms; public class CustomDisplay { - public Display Display { get; set; } + public Display Display { get; set; } - public string DisplayName => Display.DisplayName; - public string DevicePath => Display.DevicePath; - public bool IsHDRSupportedAndEnabled() - { - var advancedColor = CCD.GetAdvancedColorSupportedAndEnabled(DisplayName); + public string DisplayName => Display.DisplayName; + public string DevicePath => Display.DevicePath; + public bool IsHDRSupportedAndEnabled() + { + var advancedColor = CCD.GetAdvancedColorSupportedAndEnabled(DisplayName); - return advancedColor.isSupported && advancedColor.isEnabled; - } + return advancedColor.isSupported && advancedColor.isEnabled; + } - public CustomDisplay(Display display) - { - Display = display; - } + public CustomDisplay(Display display) + { + Display = display; + } - public override string ToString() - { - return $"{CCD.GetDisplayInfo(Display.DisplayName)} on {Display.Adapter.DeviceName}"; - } + public override string ToString() + { + return $"{CCD.GetDisplayInfo(Display.DisplayName)} on {Display.Adapter.DeviceName}"; + } } public class ColorPointModel : BaseViewModel { - private double _x; - public double X { get => _x; set { _x = value; OnPropertyChanged(); } } + private double _x; + public double X { get => _x; set { _x = value; OnPropertyChanged(); } } - private double _y; - public double Y { get => _y; set { _y = value; OnPropertyChanged(); } } + private double _y; + public double Y { get => _y; set { _y = value; OnPropertyChanged(); } } - public ColorPointModel() - { + public ColorPointModel() + { - } + } - public ColorPointModel(CIExy coord) - { - X = coord.x; - Y = coord.y; - } + public ColorPointModel(CIExy coord) + { + X = coord.x; + Y = coord.y; + } } internal class ColorProfileViewModel : BaseViewModel { - [StringLength(30)] - public string Description { get; set; } + [StringLength(30)] + public string Description { get; set; } - public ColorPointModel RedPoint { get; set; } = new ColorPointModel(RgbPrimaries.sRGB.Red); - public ColorPointModel GreenPoint { get; set; } = new ColorPointModel(RgbPrimaries.sRGB.Green); - public ColorPointModel BluePoint { get; set; } = new ColorPointModel(RgbPrimaries.sRGB.Blue); - public ColorPointModel WhitePoint { get; set; } = new ColorPointModel(RgbPrimaries.sRGB.White); - public Dictionary PrimariesSources { get; } = Utils.EnumToDictionary(); - public DisplayPrimariesSource PrimariesSource { get; set; } = DisplayPrimariesSource.EDID; - public Dictionary ColorGamuts { get; } = Utils.EnumToDictionary(); - public ColorGamut ColorGamut { get; set; } = ColorGamut.Native; - public Dictionary SDRTransferFunctions { get; } = Utils.EnumToDictionary(); - public SDRTransferFunction SDRTransferFunction { get; set; } = SDRTransferFunction.PurePower; - [Range(0.1, 10)] - public double CustomGamma { get; set; } = 2.20; - [Range(0, 10)] - public double MinCLL { get; set; } = 0; - [Range(11, 10000)] - public double MaxCLL { get; set; } = 1000; - [Range(0, 10)] - public double BlackLuminance { get; set; } = 0; - [Range(11, 10000)] - public double WhiteLuminance { get; set; } = 1000; - [Range(0, 10)] - public double SDRMinBrightness { get; set; } = 0; - [Range(11, 10000)] - public double SDRMaxBrightness { get; set; } = 100; - [Range(-50, 50)] - public double SDRBrightnessBoost { get; set; } + public ColorPointModel RedPoint { get; set; } = new ColorPointModel(RgbPrimaries.sRGB.Red); + public ColorPointModel GreenPoint { get; set; } = new ColorPointModel(RgbPrimaries.sRGB.Green); + public ColorPointModel BluePoint { get; set; } = new ColorPointModel(RgbPrimaries.sRGB.Blue); + public ColorPointModel WhitePoint { get; set; } = new ColorPointModel(RgbPrimaries.sRGB.White); + public Dictionary PrimariesSources { get; } = Utils.EnumToDictionary(); + public DisplayPrimariesSource PrimariesSource { get; set; } = DisplayPrimariesSource.EDID; + public Dictionary ColorGamuts { get; } = Utils.EnumToDictionary(); + public ColorGamut ColorGamut { get; set; } = ColorGamut.Native; + public Dictionary SDRTransferFunctions { get; } = Utils.EnumToDictionary(); + public SDRTransferFunction SDRTransferFunction { get; set; } = SDRTransferFunction.PurePower; + [Range(0.1, 10)] + public double CustomGamma { get; set; } = 2.20; + [Range(0, 10)] + public double MinCLL { get; set; } = 0; + [Range(11, 10000)] + public double MaxCLL { get; set; } = 1000; + [Range(0, 10)] + public double BlackLuminance { get; set; } = 0; + [Range(11, 10000)] + public double WhiteLuminance { get; set; } = 1000; + [Range(0, 10)] + public double SDRMinBrightness { get; set; } = 0; + [Range(11, 10000)] + public double SDRMaxBrightness { get; set; } = 100; + [Range(-50, 50)] + public double SDRBrightnessBoost { get; set; } + [Range(-200, 200)] + public double ShadowDetailBoost { get; set; } = 0; + [Range(0, 100)] + public double ShadowDetailRange { get; set; } = 0; - public CustomDisplay SelectedDisplay { get; set; } - public IEnumerable Displays { get; set; } + public CustomDisplay SelectedDisplay { get; set; } + public IEnumerable Displays { get; set; } - public string SelectedDisplayName => SelectedDisplay?.DisplayName; + public string SelectedDisplayName => SelectedDisplay?.DisplayName; - public ObservableCollection ExistingProfiles { get; set; } - public string SelectedExistingProfile { get; set; } = CreateANewProfile; - public string NewProfileName { get; set; } - public string ProfileName => SelectedExistingProfile == CreateANewProfile ? NewProfileName : SelectedExistingProfile; - public bool IsHDR { get; set; } = true; - public Dictionary SaveOptions { get; } = Utils.EnumToDictionary(); - public SaveOption SaveOption { get; set; } = SaveOption.InstallAndSetAsDefault; + public ObservableCollection ExistingProfiles { get; set; } + public string SelectedExistingProfile { get; set; } = CreateANewProfile; + public string NewProfileName { get; set; } + public string ProfileName => SelectedExistingProfile == CreateANewProfile ? NewProfileName : SelectedExistingProfile; + public bool IsHDR { get; set; } = true; + public Dictionary SaveOptions { get; } = Utils.EnumToDictionary(); + public SaveOption SaveOption { get; set; } = SaveOption.InstallAndSetAsDefault; - public bool SDRSettingsEnabled { get; set; } - public Visibility VisibilityHDRSettings => IsHDR ? Visibility.Visible : Visibility.Collapsed; - public bool IsLoadEnabled { get; set; } - public bool SetMinMaxTml { get; set; } = true; - public bool PrimariesEnabled { get; set; } = true; + public bool SDRSettingsEnabled { get; set; } + public Visibility VisibilityHDRSettings => IsHDR ? Visibility.Visible : Visibility.Collapsed; + public bool IsLoadEnabled { get; set; } + public bool SetMinMaxTml { get; set; } = true; + public bool PrimariesEnabled { get; set; } = true; - [Range(400, 10000)] - public double ToneMappingFromLuminance { get; set; } = 400; - [Range(400, 10000)] - public double ToneMappingToLuminance { get; set; } = 400; + [Range(400, 10000)] + public double ToneMappingFromLuminance { get; set; } = 400; + [Range(400, 10000)] + public double ToneMappingToLuminance { get; set; } = 400; - public bool ToneMappingSettingsEnabled { get; set; } + public bool ToneMappingSettingsEnabled { get; set; } - public bool BrightnessBoostSettingsEnabled { get; set; } + public bool BrightnessBoostSettingsEnabled { get; set; } - [Range(.04, 25)] - public double HdrBrightnessMultiplier { get; set; } = 1; + [Range(.04, 25)] + public double HdrBrightnessMultiplier { get; set; } = 1; - [Range(.04, 25)] - public double HdrGammaMultiplier { get; set; } = 1; + [Range(.04, 25)] + public double HdrGammaMultiplier { get; set; } = 1; - public override string this[string columnName] - { - get - { - var baseResult = base[columnName]; + public override string this[string columnName] + { + get + { + var baseResult = base[columnName]; - if (columnName == nameof(SelectedDisplay)) - { - UpdateDisplay(); - } - else if (columnName == nameof(SDRTransferFunction)) - { - if (SDRTransferFunction == SDRTransferFunction.PurePower) - { - SDRSettingsEnabled = true; - ToneMappingSettingsEnabled = false; - BrightnessBoostSettingsEnabled = true; - OnPropertyChanged(nameof(SDRSettingsEnabled)); - OnPropertyChanged(nameof(ToneMappingSettingsEnabled)); - OnPropertyChanged(nameof(BrightnessBoostSettingsEnabled)); - } - else if (SDRTransferFunction == SDRTransferFunction.ToneMappedPiecewise) - { + if (columnName == nameof(SelectedDisplay)) + { + UpdateDisplay(); + } + else if (columnName == nameof(SDRTransferFunction)) + { + if (SDRTransferFunction == SDRTransferFunction.PurePower) + { + SDRSettingsEnabled = true; + ToneMappingSettingsEnabled = false; + BrightnessBoostSettingsEnabled = true; + OnPropertyChanged(nameof(SDRSettingsEnabled)); + OnPropertyChanged(nameof(ToneMappingSettingsEnabled)); + OnPropertyChanged(nameof(BrightnessBoostSettingsEnabled)); + } + else if (SDRTransferFunction == SDRTransferFunction.ToneMappedPiecewise) + { - ToneMappingSettingsEnabled = true; - SDRSettingsEnabled = false; - BrightnessBoostSettingsEnabled = false; - OnPropertyChanged(nameof(ToneMappingSettingsEnabled)); - OnPropertyChanged(nameof(SDRSettingsEnabled)); - OnPropertyChanged(nameof(BrightnessBoostSettingsEnabled)); - } - else - { - ToneMappingSettingsEnabled = false; - SDRSettingsEnabled = false; - BrightnessBoostSettingsEnabled = true; - OnPropertyChanged(nameof(ToneMappingSettingsEnabled)); - OnPropertyChanged(nameof(SDRSettingsEnabled)); - OnPropertyChanged(nameof(BrightnessBoostSettingsEnabled)); - } + ToneMappingSettingsEnabled = true; + SDRSettingsEnabled = false; + BrightnessBoostSettingsEnabled = false; + OnPropertyChanged(nameof(ToneMappingSettingsEnabled)); + OnPropertyChanged(nameof(SDRSettingsEnabled)); + OnPropertyChanged(nameof(BrightnessBoostSettingsEnabled)); + } + else + { + ToneMappingSettingsEnabled = false; + SDRSettingsEnabled = false; + BrightnessBoostSettingsEnabled = true; + OnPropertyChanged(nameof(ToneMappingSettingsEnabled)); + OnPropertyChanged(nameof(SDRSettingsEnabled)); + OnPropertyChanged(nameof(BrightnessBoostSettingsEnabled)); + } - } - else if (columnName == nameof(SelectedExistingProfile)) - { - IsLoadEnabled = SelectedExistingProfile != CreateANewProfile; - OnPropertyChanged(nameof(IsLoadEnabled)); - } - else if (columnName == nameof(PrimariesSource)) - { - PrimariesEnabled = PrimariesSource == DisplayPrimariesSource.Custom; - OnPropertyChanged(nameof(PrimariesEnabled)); - UpdateDisplay(); - } + } + else if (columnName == nameof(SelectedExistingProfile)) + { + IsLoadEnabled = SelectedExistingProfile != CreateANewProfile; + OnPropertyChanged(nameof(IsLoadEnabled)); + } + else if (columnName == nameof(PrimariesSource)) + { + PrimariesEnabled = PrimariesSource == DisplayPrimariesSource.Custom; + OnPropertyChanged(nameof(PrimariesEnabled)); + UpdateDisplay(); + } - return baseResult; - } - } + return baseResult; + } + } - public override bool PreValidate() - { - return base.PreValidate() && Displays.Any(); - } + public override bool PreValidate() + { + return base.PreValidate() && Displays.Any(); + } - public const string CreateANewProfile = ""; + public const string CreateANewProfile = ""; - public ColorProfileViewModel(bool isHDR = true) - { - IsHDR = isHDR; + public ColorProfileViewModel(bool isHDR = true) + { + IsHDR = isHDR; - RefreshDisplays(); + RefreshDisplays(); - ExistingProfiles = new ObservableCollection { CreateANewProfile }; - NewProfileName = $"CC_{(isHDR ? "HDR" : "SDR")}_profile_{DateTime.Now:yyyyMMddHHmmss}.icm"; - Description = $"CC_{(isHDR ? "HDR" : "SDR")}"; + ExistingProfiles = new ObservableCollection { CreateANewProfile }; + NewProfileName = $"CC_{(isHDR ? "HDR" : "SDR")}_profile_{DateTime.Now:yyyyMMddHHmmss}.icm"; + Description = $"CC_{(isHDR ? "HDR" : "SDR")}"; - if (Displays.Any()) - { - SelectedDisplay = Displays.First(); + if (Displays.Any()) + { + SelectedDisplay = Displays.First(); - UpdateDisplay(); - } - } + UpdateDisplay(); + } + } - public void RefreshDisplays() - { - Displays = Display.GetDisplays().Select(d => new CustomDisplay(d)) - .Where(d => IsHDR == d.IsHDRSupportedAndEnabled()) - .ToList(); - } + public void RefreshDisplays() + { + Displays = Display.GetDisplays().Select(d => new CustomDisplay(d)) + .Where(d => IsHDR == d.IsHDRSupportedAndEnabled()) + .ToList(); + } - public void Update() - { - foreach (var property in GetType().GetProperties().Where(p => !new[] { "Display", "PrimariesSource" }.Any(s => p.Name.Contains(s)))) - { - OnPropertyChanged(property.Name); - } - } + public void Update() + { + foreach (var property in GetType().GetProperties().Where(p => !new[] { "Display", "PrimariesSource" }.Any(s => p.Name.Contains(s)))) + { + OnPropertyChanged(property.Name); + } + } - private void UpdateDisplay() - { - if (SelectedDisplay == null) - { - return; - } + private void UpdateDisplay() + { + if (SelectedDisplay == null) + { + return; + } - var colorParams = CCD.GetColorParams(SelectedDisplay.DisplayName); + var colorParams = CCD.GetColorParams(SelectedDisplay.DisplayName); - if (colorParams.MaxLuminance > 0) - { - if (PrimariesSource == DisplayPrimariesSource.Windows) - { - var divider = colorParams.RedPointX <= 1 << 10 ? 1 << 10 : 1 << 20; + if (colorParams.MaxLuminance > 0) + { + if (PrimariesSource == DisplayPrimariesSource.Windows) + { + var divider = colorParams.RedPointX <= 1 << 10 ? 1 << 10 : 1 << 20; - RedPoint.X = (double)colorParams.RedPointX / divider; - RedPoint.Y = (double)colorParams.RedPointY / divider; - GreenPoint.X = (double)colorParams.GreenPointX / divider; - GreenPoint.Y = (double)colorParams.GreenPointY / divider; - BluePoint.X = (double)colorParams.BluePointX / divider; - BluePoint.Y = (double)colorParams.BluePointY / divider; - WhitePoint.X = (double)colorParams.WhitePointX / divider; - WhitePoint.Y = (double)colorParams.WhitePointY / divider; - } + RedPoint.X = (double)colorParams.RedPointX / divider; + RedPoint.Y = (double)colorParams.RedPointY / divider; + GreenPoint.X = (double)colorParams.GreenPointX / divider; + GreenPoint.Y = (double)colorParams.GreenPointY / divider; + BluePoint.X = (double)colorParams.BluePointX / divider; + BluePoint.Y = (double)colorParams.BluePointY / divider; + WhitePoint.X = (double)colorParams.WhitePointX / divider; + WhitePoint.Y = (double)colorParams.WhitePointY / divider; + } - WhiteLuminance = (double)colorParams.MaxLuminance / 10000; - OnPropertyChanged(nameof(WhiteLuminance)); - BlackLuminance = (double)colorParams.MinLuminance / 10000; - OnPropertyChanged(nameof(BlackLuminance)); - MinCLL = BlackLuminance; - OnPropertyChanged(nameof(MinCLL)); - MaxCLL = WhiteLuminance; - OnPropertyChanged(nameof(MaxCLL)); - } + WhiteLuminance = (double)colorParams.MaxLuminance / 10000; + OnPropertyChanged(nameof(WhiteLuminance)); + BlackLuminance = (double)colorParams.MinLuminance / 10000; + OnPropertyChanged(nameof(BlackLuminance)); + MinCLL = BlackLuminance; + OnPropertyChanged(nameof(MinCLL)); + MaxCLL = WhiteLuminance; + OnPropertyChanged(nameof(MaxCLL)); + } - if (PrimariesSource == DisplayPrimariesSource.EDID) - { - GetEDID(); - } + if (PrimariesSource == DisplayPrimariesSource.EDID) + { + GetEDID(); + } - if (!CCD.GetUsePerUserDisplayProfiles(SelectedDisplay.DisplayName)) - { - if (MessageForms.QuestionYesNo("To be able to select/activate a color profile, user specific settings have to be enabled. Do you want to enable this?") == DialogResult.Yes) - { - CCD.SetUsePerUserDisplayProfiles(SelectedDisplay.DisplayName, true); - } - } + if (!CCD.GetUsePerUserDisplayProfiles(SelectedDisplay.DisplayName)) + { + if (MessageForms.QuestionYesNo("To be able to select/activate a color profile, user specific settings have to be enabled. Do you want to enable this?") == DialogResult.Yes) + { + CCD.SetUsePerUserDisplayProfiles(SelectedDisplay.DisplayName, true); + } + } - ExistingProfiles = new ObservableCollection { CreateANewProfile }; + ExistingProfiles = new ObservableCollection { CreateANewProfile }; - var profiles = CCD.GetDisplayColorProfiles(SelectedDisplay.DisplayName); + var profiles = CCD.GetDisplayColorProfiles(SelectedDisplay.DisplayName); - foreach (var profile in profiles) - { - ExistingProfiles.Add(profile); - } - } + foreach (var profile in profiles) + { + ExistingProfiles.Add(profile); + } + } - private void GetEDID() - { - if (SelectedDisplay == null) - { - return; - } + private void GetEDID() + { + if (SelectedDisplay == null) + { + return; + } - var path = SelectedDisplay.DevicePath; + var path = SelectedDisplay.DevicePath; - var edid = ColorProfileService.GetEDIDInternal(path); - var primaries = edid?.DisplayParameters?.ChromaticityCoordinates; + var edid = ColorProfileService.GetEDIDInternal(path); + var primaries = edid?.DisplayParameters?.ChromaticityCoordinates; - if (primaries == null) - { - return; - } + if (primaries == null) + { + return; + } - RedPoint.X = primaries.RedX; - RedPoint.Y = primaries.RedY; - GreenPoint.X = primaries.GreenX; - GreenPoint.Y = primaries.GreenY; - BluePoint.X = primaries.BlueX; - BluePoint.Y = primaries.BlueY; - WhitePoint.X = primaries.WhiteX; - WhitePoint.Y = primaries.WhiteY; - } + RedPoint.X = primaries.RedX; + RedPoint.Y = primaries.RedY; + GreenPoint.X = primaries.GreenX; + GreenPoint.Y = primaries.GreenY; + BluePoint.X = primaries.BlueX; + BluePoint.Y = primaries.BlueY; + WhitePoint.X = primaries.WhiteX; + WhitePoint.Y = primaries.WhiteY; + } - internal RgbPrimaries GetDevicePrimaries() - { - return new RgbPrimaries( - new CIExy { x = RedPoint.X, y = RedPoint.Y }, - new CIExy { x = GreenPoint.X, y = GreenPoint.Y }, - new CIExy { x = BluePoint.X, y = BluePoint.Y }, - new CIExy { x = WhitePoint.X, y = WhitePoint.Y }); - } + internal RgbPrimaries GetDevicePrimaries() + { + return new RgbPrimaries( + new CIExy { x = RedPoint.X, y = RedPoint.Y }, + new CIExy { x = GreenPoint.X, y = GreenPoint.Y }, + new CIExy { x = BluePoint.X, y = BluePoint.Y }, + new CIExy { x = WhitePoint.X, y = WhitePoint.Y }); + } } diff --git a/ColorControl/XForms/ColorProfileWindow.xaml b/ColorControl/XForms/ColorProfileWindow.xaml index ec35338..ab1fcde 100644 --- a/ColorControl/XForms/ColorProfileWindow.xaml +++ b/ColorControl/XForms/ColorProfileWindow.xaml @@ -52,8 +52,8 @@ - - + + @@ -74,11 +74,15 @@ @@ -94,7 +98,7 @@ - + diff --git a/ColorControl/XForms/ColorProfileWindow.xaml.cs b/ColorControl/XForms/ColorProfileWindow.xaml.cs index 79096df..77e15bf 100644 --- a/ColorControl/XForms/ColorProfileWindow.xaml.cs +++ b/ColorControl/XForms/ColorProfileWindow.xaml.cs @@ -113,6 +113,8 @@ namespace ColorControl.XForms SDRMaxBrightness = _viewModel.SDRMaxBrightness, SDRTransferFunction = _viewModel.SDRTransferFunction, SDRBrightnessBoost = _viewModel.SDRBrightnessBoost, + ShadowDetailBoost = _viewModel.ShadowDetailBoost, + ShadowDetailRange = _viewModel.ShadowDetailRange, ColorGamut = _viewModel.ColorGamut, Gamma = _viewModel.CustomGamma, DevicePrimaries = _viewModel.GetDevicePrimaries(), @@ -208,6 +210,8 @@ namespace ColorControl.XForms _viewModel.SDRMinBrightness = profileProperties.SDRMinBrightness; _viewModel.SDRMaxBrightness = profileProperties.SDRMaxBrightness; _viewModel.SDRBrightnessBoost = profileProperties.SDRBrightnessBoost; + _viewModel.ShadowDetailBoost = profileProperties.ShadowDetailBoost; + _viewModel.ShadowDetailRange = profileProperties.ShadowDetailRange; _viewModel.MinCLL = profileProperties.MinCLL; _viewModel.MaxCLL = profileProperties.MaxCLL; diff --git a/ColorControl/lgtv/LgTvApi.cs b/ColorControl/lgtv/LgTvApi.cs index 8b7e83e..709c0d7 100644 --- a/ColorControl/lgtv/LgTvApi.cs +++ b/ColorControl/lgtv/LgTvApi.cs @@ -24,19 +24,21 @@ namespace LgTv private string _ip; private string _currentPairKey; private string webSocketUri; + private string _registerJson; protected static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger(); - public static async Task CreateLgTvApi(string ip, int retries = 1, bool useSecureWs = true) + public static async Task CreateLgTvApi(string ip, int retries = 1, bool useSecureWs = true, bool useNewHandshake = false) { - var instance = new LgTvApi(ip, useSecureWs); + var instance = new LgTvApi(ip, useSecureWs, useNewHandshake); return await instance.Connect(retries); } - private LgTvApi(string ip, bool useSecureWs) + private LgTvApi(string ip, bool useSecureWs, bool useNewHandshake) { webSocketUri = useSecureWs ? $"wss://{ip}:3001" : $"ws://{ip}:3000"; + _registerJson = Utils.GetResourceFile(useNewHandshake ? "LG_register.json" : "LG_register_legacy.json"); _ip = ip; _connection = new LgTvApiCoreCws(); _keyStore = new ClientKeyStore(ip); @@ -68,26 +70,43 @@ namespace LgTv return _ip; } - public async Task MakeHandShake() + public async Task MakeHandShake() { - var registerJson = Utils.GetResourceFile("LG_register.json"); - _currentPairKey = _keyStore.GetClientKey(); - if (!string.IsNullOrWhiteSpace(_currentPairKey) && !_currentPairKey.All(k => k == '\0') && _keyStore.HasValidHandShake(registerJson)) + if (!string.IsNullOrWhiteSpace(_currentPairKey) && !_currentPairKey.All(k => k == '\0') && _keyStore.HasValidHandShake(_registerJson)) { - var key = registerJson.Replace("CLIENTKEYGOESHERE", _currentPairKey); - var conn = await _connection.SendCommandAsync(key); - _keyStore.SaveClientKey((string)conn.clientKey); - return; + var key = _registerJson.Replace("CLIENTKEYGOESHERE", _currentPairKey); + try + { + var conn = await _connection.SendCommandAsync(key); + ArgumentNullException.ThrowIfNull(conn); + _keyStore.SaveClientKey((string)conn.clientKey); + return true; + } + catch (Exception) + { + // Re-register below + } } - var registerJsonRemovedKey = registerJson.Replace("CLIENTKEYGOESHERE", string.Empty); - dynamic result = await _connection.SendCommandAsync(registerJsonRemovedKey); - _keyStore.SaveClientKey(result.clientKey); - _keyStore.SaveHandShake(registerJson); + var registerJsonRemovedKey = _registerJson.Replace("CLIENTKEYGOESHERE", string.Empty); + try + { + var result = await _connection.SendCommandAsync(registerJsonRemovedKey); + if (result?.clientKey == null) + { + throw new InvalidOperationException("No valid client key received"); + } + _keyStore.SaveClientKey(result.clientKey); + _keyStore.SaveHandShake(_registerJson); + return true; + } + catch (Exception) + { + return false; + } } - public async Task Connect() { var ctx = _connection.Connect(new Uri(webSocketUri)); diff --git a/LittleCms/LittleCms.csproj b/LittleCms/LittleCms.csproj index 99238f9..5ba45f5 100644 --- a/LittleCms/LittleCms.csproj +++ b/LittleCms/LittleCms.csproj @@ -1,7 +1,7 @@  - net9.0-windows + net10.0-windows enable True diff --git a/MHC2Gen/IccContext.cs b/MHC2Gen/IccContext.cs index f5c29be..b355172 100644 --- a/MHC2Gen/IccContext.cs +++ b/MHC2Gen/IccContext.cs @@ -121,7 +121,7 @@ namespace MHC2Gen var value = (double)i / lutSizeDiv; value = ApplyGain(gain, value, i, lutSizeDiv); - value = ApplyShadowDetailBoost(shadowDetailBoost, shadowDetailRange, value, i); + value = ApplyShadowDetailBoost(shadowDetailBoost, shadowDetailRange, value, i, false); RegammaLUT[c, i] = value * amplifier; } @@ -140,14 +140,14 @@ namespace MHC2Gen return value; } - public static double ApplyShadowDetailBoost(double boost, double range, double value, int lutIndex) + public static double ApplyShadowDetailBoost(double boost, double range, double value, int lutIndex, bool piecewiseAverage = true) { if (boost != 0 && lutIndex < range) { var correctedBoost = (boost * (range - lutIndex)) / range; - // Average between sSRGB and Piecewise gamma - if (true) + // Average between sRGB and Piecewise gamma + if (piecewiseAverage) { var piecewiseValue = (double)lutIndex / 1023; diff --git a/MHC2Gen/MHC2Gen.csproj b/MHC2Gen/MHC2Gen.csproj index 6791b28..b710837 100644 --- a/MHC2Gen/MHC2Gen.csproj +++ b/MHC2Gen/MHC2Gen.csproj @@ -1,7 +1,7 @@  - net9.0-windows + net10.0-windows enable x64 true diff --git a/NLogViewer/NLogViewer.csproj b/NLogViewer/NLogViewer.csproj index dc80ac5..0ddc82c 100644 --- a/NLogViewer/NLogViewer.csproj +++ b/NLogViewer/NLogViewer.csproj @@ -1,7 +1,7 @@  - net9.0-windows + net10.0-windows true DJ true @@ -18,8 +18,8 @@ - - + + diff --git a/Nspector/Nspector.csproj b/Nspector/Nspector.csproj index 38b431e..34414d9 100644 --- a/Nspector/Nspector.csproj +++ b/Nspector/Nspector.csproj @@ -1,7 +1,7 @@  - net9.0-windows + net10.0-windows enable true enable @@ -13,10 +13,6 @@ $(MSBuildThisFileDirectory)=.\ - - - - diff --git a/Nspector/nspector/CustomSettingNames.xml b/Nspector/nspector/CustomSettingNames.xml index 80c27d1..a8aa210 100644 --- a/Nspector/nspector/CustomSettingNames.xml +++ b/Nspector/nspector/CustomSettingNames.xml @@ -7776,23 +7776,23 @@ 0x00000000 - Enabled (Low Quality) (0x06) + Enabled via driver (No Debanding) (0x06) 0x00000006 - Enabled (Medium Quality) (0x0A) + Enabled via driver (Medium Debanding) (0x0A) 0x0000000A - Enabled (VeryHigh Quality) (0x02) + Enabled via driver (VeryHigh Debanding) (0x02) 0x00000002 - Enable + Indicator (0x03) + Enabled + Indicator (VeryHigh) (0x03) 0x00000003 - Enable + Indicator + Debug (0x23) + Enabled + Indicator + Debug (VeryHigh) (0x23) 0x00000023 @@ -7906,6 +7906,26 @@ 8 - Extra 0 + + N/A + 0x00000000 + + + Preset A + 0x00000001 + + + Preset B + 0x00000002 + + + Preset C + 0x00000003 + + + Preset D + 0x00000004 + Preset E 0x00000005 @@ -7914,6 +7934,18 @@ Preset F 0x00000006 + + Preset G (unused) + 0x00000007 + + + Preset H (unused) + 0x00000008 + + + Preset I (unused) + 0x00000009 + Preset J 0x0000000A @@ -7922,6 +7954,103 @@ Preset K 0x0000000B + + Preset L + 0x0000000C + + + Preset M + 0x0000000D + + + Preset N (unused) + 0x0000000E + + + Preset O (unused) + 0x0000000F + + + Always use latest + 0x00FFFFFF + + + + + + DLSS-RR - Forced Preset Letter + 0x10E41DF7 + 5 - Common + 0 + + + N/A + 0x00000000 + + + Preset A + 0x00000001 + + + Preset B + 0x00000002 + + + Preset C + 0x00000003 + + + Preset D + 0x00000004 + + + Preset E + 0x00000005 + + + Preset F (unused) + 0x00000006 + + + Preset G (unused) + 0x00000007 + + + Preset H (unused) + 0x00000008 + + + Preset I (unused) + 0x00000009 + + + Preset J (unused) + 0x0000000A + + + Preset K (unused) + 0x0000000B + + + Preset L (unused) + 0x0000000C + + + Preset M (unused) + 0x0000000D + + + Preset N (unused) + 0x0000000E + + + Preset O (unused) + 0x0000000F + + + Always use latest + 0x00FFFFFF + diff --git a/NvAPIWrapper/NvAPIWrapper.csproj b/NvAPIWrapper/NvAPIWrapper.csproj index a8f6ad1..69d26e2 100644 --- a/NvAPIWrapper/NvAPIWrapper.csproj +++ b/NvAPIWrapper/NvAPIWrapper.csproj @@ -1,7 +1,7 @@  - net9.0-windows + net10.0-windows 0.8.1.106 falahati.net NvAPIWrapper is a .Net wrapper for NVIDIA public API diff --git a/README.md b/README.md index 0663035..50b6c76 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,8 @@ Easily change NVIDIA and AMD display settings, control LG and Samsung tv's, Game Just extract the .zip file in a folder of your preference. Run ColorControl.exe to start the application. Requires .NET 9 with the following runtimes: -* .NET Desktop Runtime 9 -* .NET ASP.NET Core Runtime 9 +* .NET Desktop Runtime 10 +* .NET ASP.NET Core Runtime 10 ColorControl stores its settings in the following folder: * C:\Users\username\AppData\Roaming\Maassoft\ColorControl diff --git a/Shared/Common/GlobalContext.cs b/Shared/Common/GlobalContext.cs index 6728be3..7f00418 100644 --- a/Shared/Common/GlobalContext.cs +++ b/Shared/Common/GlobalContext.cs @@ -21,6 +21,7 @@ namespace ColorControl.Shared.Common public DateTime StartTime { get; private set; } public string MutexId { get; private set; } public nint MainHandle { get; set; } + public int MainThreadId { get; private set; } public IServiceProvider ServiceProvider { get; set; } public string ApplicationTitle { get; private set; } @@ -37,6 +38,7 @@ namespace ColorControl.Shared.Common ServiceProvider = serviceProvider; StartTime = startTime; MutexId = mutexId; + MainThreadId = Environment.CurrentManagedThreadId; CurrentContext = this; diff --git a/Shared/Common/Utils.cs b/Shared/Common/Utils.cs index 258dcc2..833d97a 100644 --- a/Shared/Common/Utils.cs +++ b/Shared/Common/Utils.cs @@ -50,46 +50,6 @@ These methods are available: The best and suggested method to provide this is via a Windows Service. Only when installing the service a User Account Control window may popup."; - public static Bitmap SubPixelShift(Bitmap bitmap) - { - Bitmap bitmap2 = (Bitmap)bitmap.Clone(); - - int shift = -1; - bool shiftRed = true; - bool shiftGreen = true; - bool shiftBlue = false; - - for (int i = 0; i < bitmap.Width; i++) - { - for (int j = 0; j < bitmap.Height; j++) - { - Color pixel = bitmap.GetPixel(i, j); - - if (shift > 0 && i < bitmap.Width - shift) - { - Color pixel2 = bitmap2.GetPixel(i + shift, j); - - Color pixel3 = Color.FromArgb(shiftRed ? pixel.R : pixel2.R, shiftGreen ? pixel.G : pixel2.G, shiftBlue ? pixel.B : pixel2.B); - - bitmap2.SetPixel(i + shift, j, pixel3); - - } - else if (i + shift >= 0) - { - Color pixel2 = bitmap2.GetPixel(i + shift, j); - - Color pixel3 = Color.FromArgb(shiftRed ? pixel.R : pixel2.R, shiftGreen ? pixel.G : pixel2.G, shiftBlue ? pixel.B : pixel2.B); - - bitmap2.SetPixel(i + shift, j, pixel3); - - } - } - } - - return bitmap2; - //bitmap2.Save("d:\\ss_shifted.bmp"); - } - public static string GetDataPath(string subDir = "") { var path = Directory.GetParent(Application.UserAppDataPath).FullName; @@ -465,22 +425,77 @@ The best and suggested method to provide this is via a Windows Service. Only whe public static FileInfo SelectFile(string ext = "*.exe", string filter = "Application EXE Name|*.exe|Application Absolute Path|*.exe") { - var openDialog = new System.Windows.Forms.OpenFileDialog(); - openDialog.DefaultExt = ext; - openDialog.Filter = filter; + var openDialog = new OpenFileDialog + { + DefaultExt = ext, + Filter = filter + }; if (openDialog.ShowDialog() == DialogResult.OK) { return new FileInfo(openDialog.FileName); - //if (openDialog.FilterIndex == 2) - // applicationName = openDialog.FileName; - - //return applicationName; } return null; } + public static FileInfo SelectFileFromNonUiThread(SynchronizationContext synchronizationContext, string ext = "*.exe", string filter = "Application EXE Name|*.exe|Application Absolute Path|*.exe") + { + var completionSource = new TaskCompletionSource(); + + var workerThread = new Thread(() => + { + // Post back to the main thread + synchronizationContext?.Post(_ => + { + var openDialog = new OpenFileDialog + { + DefaultExt = ext, + Filter = filter + }; + + if (openDialog.ShowDialog() == DialogResult.OK) + { + completionSource.SetResult(new FileInfo(openDialog.FileName)); + } + else + { + completionSource.SetResult(null); + } + }, null); + }); + + workerThread.Start(); + + completionSource.Task.Wait(); + return completionSource.Task.Result; + } + + public static void ExecuteOnMainThread(Action action) + { + if (GlobalContext.CurrentContext.MainThreadId == Environment.CurrentManagedThreadId) + { + action(); + return; + } + + var completionSource = new TaskCompletionSource(); + + var workerThread = new Thread(() => + { + // Post back to the main thread + GlobalContext.CurrentContext.SynchronizationContext?.Post(_ => + { + action(); + completionSource.SetResult(); + }, null); + }); + + workerThread.Start(); + + completionSource.Task.Wait(); + } + public static bool NormEquals(this string str1, string str2) { return str1.Trim().Replace(" ", string.Empty).Equals(str2.Trim().Replace(" ", string.Empty), StringComparison.OrdinalIgnoreCase); diff --git a/Shared/Contracts/Config.cs b/Shared/Contracts/Config.cs index 0027692..43094ec 100644 --- a/Shared/Contracts/Config.cs +++ b/Shared/Contracts/Config.cs @@ -61,9 +61,11 @@ namespace ColorControl.Shared.Contracts public bool DisableErrorPopupWhenApplyingPreset { get; set; } public UiType UiType { get; set; } public int UiPort { get; set; } + public bool UiAllowRemoteConnections { get; set; } [JsonIgnore] public int CurrentUiPort { get; set; } - public bool UiAllowRemoteConnections { get; set; } + [JsonIgnore] + public bool CurrentUiAllowRemoteConnections { get; set; } public Config() { @@ -83,7 +85,7 @@ namespace ColorControl.Shared.Contracts ElevationMethod = ElevationMethod.None; ElevationMethodAsked = false; ProcessMonitorPollingInterval = 1000; - UiType = UiType.WebEmbedded; + UiType = UiType.WinForms; UiPort = 0; // Let .NET decide UiAllowRemoteConnections = false; LgPresetsSortState = new ListViewSortState(); diff --git a/Shared/Contracts/DisplayConfig.cs b/Shared/Contracts/DisplayConfig.cs index 68467ea..4cd34e4 100644 --- a/Shared/Contracts/DisplayConfig.cs +++ b/Shared/Contracts/DisplayConfig.cs @@ -12,6 +12,7 @@ public class DisplayConfig public DisplayConfigScaling Scaling { get; set; } public DisplayConfigRotation Rotation { get; set; } public bool? IsPrimary { get; set; } + public DisplayConnectivity Connectivity { get; set; } public DisplayConfig() { @@ -30,6 +31,7 @@ public class DisplayConfig Scaling = displayConfig.Scaling; Rotation = displayConfig.Rotation; IsPrimary = displayConfig.IsPrimary; + Connectivity = displayConfig.Connectivity; } public string GetResolutionDesc() diff --git a/Shared/Contracts/DisplayEnums.cs b/Shared/Contracts/DisplayEnums.cs new file mode 100644 index 0000000..59969ae --- /dev/null +++ b/Shared/Contracts/DisplayEnums.cs @@ -0,0 +1,8 @@ +namespace ColorControl.Shared.Contracts; + +public enum DisplayConnectivity +{ + Unchanged = 0, + Enabled = 1, + Disabled = 2 +} \ No newline at end of file diff --git a/Shared/Contracts/LG/LgDeviceOptions.cs b/Shared/Contracts/LG/LgDeviceOptions.cs index ebc27fb..0b7a16d 100644 --- a/Shared/Contracts/LG/LgDeviceOptions.cs +++ b/Shared/Contracts/LG/LgDeviceOptions.cs @@ -21,5 +21,5 @@ public class LgDeviceOptions public int HDMIPortNumber { get; set; } public bool UseSecureConnection { get; set; } = true; -} - + public bool UseNewHandshake { get; set; } +} \ No newline at end of file diff --git a/Shared/Contracts/NVIDIA/NvPreset.cs b/Shared/Contracts/NVIDIA/NvPreset.cs index a90acec..25e06f8 100644 --- a/Shared/Contracts/NVIDIA/NvPreset.cs +++ b/Shared/Contracts/NVIDIA/NvPreset.cs @@ -149,7 +149,8 @@ namespace ColorControl.Shared.Contracts.NVIDIA applyDithering = keepChanges && applyDithering || (ditheringEnabled != currentSettings.ditheringEnabled || ditheringMode != currentSettings.ditheringMode || ditheringBits != currentSettings.ditheringBits); applyHDR = keepChanges && applyHDR || (HDREnabled != currentSettings.HDREnabled || toggleHDR || SDRBrightness != currentSettings.SDRBrightness || HdrSettings.OutputMode != currentSettings.HdrSettings.OutputMode); 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.Scaling != currentSettings.DisplayConfig.Scaling || DisplayConfig.Rotation != currentSettings.DisplayConfig.Rotation || DisplayConfig.IsPrimary != null && DisplayConfig.IsPrimary != currentSettings.DisplayConfig.IsPrimary || + DisplayConfig.Connectivity != DisplayConnectivity.Unchanged); DisplayConfig.ApplyRefreshRate = keepChanges && DisplayConfig.ApplyRefreshRate || !DisplayConfig.RefreshRate.Equals(currentSettings.DisplayConfig.RefreshRate); applyOther = keepChanges && applyOther || (scaling != currentSettings.scaling || ColorProfileSettings.ProfileName != currentSettings.ColorProfileSettings.ProfileName); applyDriverSettings = keepChanges && applyDriverSettings || driverSettings.Any(s => !currentSettings.driverSettings.Any(o => o.Key == s.Key && o.Value == s.Value)); @@ -216,11 +217,8 @@ namespace ColorControl.Shared.Contracts.NVIDIA MonitorConnectionType = preset.MonitorConnectionType; - var trigger = preset.Triggers.FirstOrDefault(); - if (trigger != null) - { - UpdateTrigger(trigger.Trigger, trigger.Conditions, trigger.IncludedProcessesAsString, trigger.ExcludedProcessesAsString, trigger.ConnectedDisplaysRegex); - } + UpdateTriggers(preset.Triggers); + Steps.Clear(); Steps.AddRange(preset.Steps); } diff --git a/Shared/Contracts/Presets/PresetBase.cs b/Shared/Contracts/Presets/PresetBase.cs index a549066..c8247ed 100644 --- a/Shared/Contracts/Presets/PresetBase.cs +++ b/Shared/Contracts/Presets/PresetBase.cs @@ -166,6 +166,19 @@ public class PresetTrigger { return processes.Contains("*") ? "all processes" : string.Join(", ", processes); } + + internal void Update(PresetTrigger updatedTrigger) + { + Trigger = updatedTrigger.Trigger; + Conditions = updatedTrigger.Conditions; + + IncludedProcesses ??= []; + ExcludedProcesses ??= []; + Utils.ParseWords(IncludedProcesses, updatedTrigger.IncludedProcessesAsString); + Utils.ParseWords(ExcludedProcesses, updatedTrigger.ExcludedProcessesAsString); + + ConnectedDisplaysRegex = updatedTrigger.ConnectedDisplaysRegex; + } } public class PresetTriggerContext @@ -282,16 +295,20 @@ public abstract class PresetBase trigger.ConnectedDisplaysRegex = connectedDisplaysRegex; } - public PresetTrigger AddTrigger() + public void UpdateTriggers(List updatedTriggers) { - if (!Triggers.Any()) - { - Triggers.Add(new PresetTrigger()); - } + Triggers.Clear(); - return Triggers.First(); + foreach (var updatedTrigger in updatedTriggers) + { + var newTrigger = new PresetTrigger(); + newTrigger.Update(updatedTrigger); + + Triggers.Add(newTrigger); + } } + public void SetSteps(List steps) { Steps = steps; diff --git a/Shared/Contracts/Samsung/SamsungPresets.cs b/Shared/Contracts/Samsung/SamsungPresets.cs index 94ef75d..f49555f 100644 --- a/Shared/Contracts/Samsung/SamsungPresets.cs +++ b/Shared/Contracts/Samsung/SamsungPresets.cs @@ -2,17 +2,17 @@ public static class SamsungFactoryMenuPresets { - public static readonly SamsungPreset Preset1 = new("ServiceMenuStep1", null, ["KEY_INFO", "KEY_FACTORY:2000"]); - public static readonly SamsungPreset PresetAdvanced = new("ServiceMenuAdvanced", null, ["KEY_UP", "KEY_0", "KEY_0", "KEY_9", "KEY_8"]); - public static readonly SamsungPreset PresetAdvancedMonitor = new("ServiceMenuAdvancedMonitor", null, ["KEY_UP", "KEY_0", "KEY_0", "KEY_3", "KEY_8"]); - public static readonly SamsungPreset Exit = new("ServiceMenuStep3", null, ["KEY_FACTORY:1500", "KEY_FACTORY"]); + public static readonly SamsungPreset Preset1 = new("ServiceMenuStep1", null, ["KEY_INFO:600", "KEY_FACTORY:3000"]); + public static readonly SamsungPreset PresetAdvanced = new("ServiceMenuAdvanced", null, ["KEY_0:800", "KEY_0:800", "KEY_9:800", "KEY_8:800"]); + public static readonly SamsungPreset PresetAdvancedMonitor = new("ServiceMenuAdvancedMonitor", null, ["KEY_0:800", "KEY_0:800", "KEY_3:800", "KEY_8:800"]); + public static readonly SamsungPreset Exit = new("ServiceMenuStep3", null, ["KEY_FACTORY:2500", "KEY_FACTORY"]); public static readonly SamsungPreset KeyFactory = new("ServiceMenuKeyFactory", null, ["KEY_FACTORY"]); } public static class SamsungHospitalityMenuPresets { - public static readonly SamsungPreset Preset1 = new("ServiceMenuStep1", null, ["KEY_MUTE:600", "KEY_1:600", "KEY_1:600", "KEY_9:600", "KEY_ENTER:2000"]); - public static readonly SamsungPreset Preset2 = new("ServiceMenuStep2", null, ["KEY_1", "KEY_2", "KEY_3", "KEY_4", "KEY_UP"]); + public static readonly SamsungPreset Preset1 = new("ServiceMenuStep1", null, ["KEY_MUTE:800", "KEY_1:800", "KEY_1:800", "KEY_9:800", "KEY_ENTER:3000"]); + public static readonly SamsungPreset Preset2 = new("ServiceMenuStep2", null, ["KEY_1:800", "KEY_2:800", "KEY_3:800", "KEY_4:800", "KEY_UP"]); public static readonly SamsungPreset Preset3 = new("ServiceMenuStep3", null, ["KEY_VOLUP:5100:Press", "KEY_VOLUP:500:Release"]); } diff --git a/Shared/Native/CCD.cs b/Shared/Native/CCD.cs index ab959c9..283a33e 100644 --- a/Shared/Native/CCD.cs +++ b/Shared/Native/CCD.cs @@ -175,6 +175,49 @@ namespace ColorControl.Shared.Native var sourceIndex = pathsArray[pathIndex].sourceInfo.modeInfoIdx; var targetIndex = pathsArray[pathIndex].targetInfo.modeInfoIdx; + if (displayConfig.Connectivity == DisplayConnectivity.Disabled) + { + var newPaths = pathsArray.Where((p, i) => i != pathIndex).ToArray(); + var newModes = modesArray.Where((m, i) => i != sourceIndex && i != targetIndex).ToArray(); + + for (var i = 0; i < newPaths.Length; i++) + { + var sourceDiff = 0U; + var targetDiff = 0U; + + if (newPaths[i].sourceInfo.modeInfoIdx > sourceIndex) + { + sourceDiff++; + } + if (newPaths[i].sourceInfo.modeInfoIdx > targetIndex) + { + sourceDiff++; + } + if (newPaths[i].targetInfo.modeInfoIdx > sourceIndex) + { + targetDiff++; + } + if (newPaths[i].targetInfo.modeInfoIdx > targetIndex) + { + targetDiff++; + } + + newPaths[i].sourceInfo.modeInfoIdx -= sourceDiff; + newPaths[i].targetInfo.modeInfoIdx -= targetDiff; + } + + var flags = SdcFlags.Apply | SdcFlags.UseSuppliedDisplayConfig | SdcFlags.AllowChanges; + + if (updateRegistry) + { + flags |= SdcFlags.SaveToDatabase; + } + + err = NativeMethods.SetDisplayConfig(pathCount - 1, newPaths, modeCount - 2, newModes, flags); + + return err == 0; + } + var resolution = displayConfig.Resolution; var refreshRate = displayConfig.RefreshRate; @@ -322,7 +365,6 @@ namespace ColorControl.Shared.Native return NativeMethods.UninstallColorProfileW(null, name, true); } - private static bool MinRequiredVersion = true; public static bool AddDisplayColorProfile(string displayName, string profileName, bool setAsDefault = true, bool isHdrColorProfile = false) @@ -1061,6 +1103,31 @@ namespace ColorControl.Shared.Native return true; } + if (displayName.StartsWith("\\\\")) + { + return MatchDisplayNameByDeviceName(path, displayName); + } + + // get display name + var info = new DISPLAYCONFIG_TARGET_DEVICE_NAME(); + info.header.type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME; + info.header.size = Marshal.SizeOf(); + info.header.adapterId = path.targetInfo.adapterId; + info.header.id = path.targetInfo.id; + + var err = NativeMethods.DisplayConfigGetDeviceInfo(ref info); + if (err != NativeConstants.ERROR_SUCCESS) + { + return false; + } + + var deviceName = CCD.GetDisplayIdByPath(info.monitorDevicePath); + + return deviceName == displayName; + } + + private static bool MatchDisplayNameByDeviceName(DisplayConfigPathInfo path, string deviceName) + { // get display name var info = new DISPLAYCONFIG_SOURCE_DEVICE_NAME(); info.header.type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME; @@ -1074,13 +1141,7 @@ namespace ColorControl.Shared.Native return false; } - var deviceName = info.viewGdiDeviceName; - if (!EqualDisplayNames(deviceName, displayName)) - { - return false; - } - - return true; + return EqualDisplayNames(deviceName, info.viewGdiDeviceName); } private static uint GetSDRWhiteLevelForDisplayConfig(DisplayConfigModeInfo displayConfigModeInfo) diff --git a/Shared/Services/WinApiAdminService.cs b/Shared/Services/WinApiAdminService.cs index 029b273..e183cf1 100644 --- a/Shared/Services/WinApiAdminService.cs +++ b/Shared/Services/WinApiAdminService.cs @@ -166,6 +166,29 @@ namespace ColorControl.Shared.Services return true; } + public bool StopProcessByName(string name) + { + if (!_winApiService.IsAdministrator()) + { + return _rpcService.Call(nameof(StopProcessByName), name); + } + + var processes = Process.GetProcessesByName(name); + var result = false; + + foreach (var item in processes) + { + try + { + item.Kill(); + result = true; + } + catch { } + } + + return result; + } + public bool SetProcessAffinity(int processId, uint affinityMask) { if (!_winApiService.IsAdministrator()) diff --git a/Shared/Shared.csproj b/Shared/Shared.csproj index c768d6d..374d80c 100644 --- a/Shared/Shared.csproj +++ b/Shared/Shared.csproj @@ -1,7 +1,7 @@  - net9.0-windows + net10.0-windows enable disable true @@ -25,15 +25,14 @@ - - - - - + + + + - - - + + + diff --git a/novideo_srgb/MainViewModel.cs b/novideo_srgb/MainViewModel.cs index 9d2370e..d42c636 100644 --- a/novideo_srgb/MainViewModel.cs +++ b/novideo_srgb/MainViewModel.cs @@ -47,7 +47,7 @@ namespace novideo_srgb try { - var hdrActive = hdrPaths.Contains(path); + var hdrActive = hdrPaths?.Contains(path) == true; var settings = config?.FirstOrDefault(x => (string?)x.Attribute("path") == path); MonitorData monitor; diff --git a/novideo_srgb/novideo_srgb.csproj b/novideo_srgb/novideo_srgb.csproj index 5840556..bc343d4 100644 --- a/novideo_srgb/novideo_srgb.csproj +++ b/novideo_srgb/novideo_srgb.csproj @@ -1,7 +1,7 @@  - net9.0-windows + net10.0-windows enable enable Properties @@ -16,13 +16,8 @@ - - - - - + -