fix some Nvidia issues, improve color profiles, add GPU info to new UI

This commit is contained in:
Vincent Maas committed 2024-09-22 15:24:54 +02:00
1 parent f42a46e53f
commit 899e49c2d9
30 files changed
+1997 -1604

No files matched your search

@@ -116,7 +116,7 @@ else
<button class="btn btn-primary btn-sm" data-bs-toggle="modal" data-bs-target="#presetModal" @onclick="() => PresetOnEditClick(preset)" @onclick:preventDefault @onclick:stopPropagation>Edit</button>
</span>
<div class="d-lg-none" @onclick:preventDefault @onclick:stopPropagation>
<button type="button" class="btn btn-outline-secondary" data-bs-toggle="dropdown" aria-expanded="false">
<button type="button" class="btn btn-sm btn-outline-secondary" data-bs-toggle="dropdown" aria-expanded="false">
<i class="bi bi-three-dots-vertical"></i>
</button>
<ul class="dropdown-menu">
@@ -261,7 +261,7 @@
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary" @onclick="InstallOnClick" disabled="@(ColorProfile == null)">Install and set as default</button>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" @onclick="() => IsVisible = false">Close</button>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" @onclick="CloseOnClick">Close</button>
<button type="submit" class="btn btn-primary" @onclick="ApplyClick" disabled="@(ColorProfile == null)">Save</button>
</div>
</div>
@@ -305,7 +305,7 @@
}
else
{
ColorProfile = await _rpcClientService.CallAsync<ColorProfileDto>("ColorProfileService", "GetColorProfile", ColorProfileName);
ColorProfile = await _rpcClientService.CallAsync<ColorProfileDto>("ColorProfileService", "GetColorProfile", ColorProfileName, DisplayInfo?.IsHdrSupportedAndEnabled ?? false);
}
if (ColorProfile != null)
@@ -390,6 +390,16 @@
IsInstalled = true;
}
private async Task CloseOnClick()
{
IsVisible = false;
if (ColorProfile != null && AfterApply != null)
{
await AfterApply.Invoke(ColorProfile);
}
}
private void ModalOnFocus(FocusEventArgs e)
{
if (!IsVisible)
@@ -210,7 +210,7 @@ else
return;
}
var result = await _rpcClientService.CallAsync<bool>("ColorProfileService", "SetDisplayDefaultColorProfile", SelectedDisplay.DeviceName, colorProfile);
var result = await _rpcClientService.CallAsync<bool>("ColorProfileService", "SetDisplayDefaultColorProfile", SelectedDisplay.DeviceName, colorProfile, Type.Missing, SelectedDisplay.IsHdrSupportedAndEnabled);
if (result)
{
SelectedDisplay.DefaultColorProfile = colorProfile;
@@ -250,7 +250,7 @@ else
return;
}
await _rpcClientService.CallAsync<bool>("ColorProfileService", "RemoveDisplayColorProfile", SelectedDisplay.DeviceName, SelectedColorProfileName);
await _rpcClientService.CallAsync<bool>("ColorProfileService", "RemoveDisplayColorProfile", SelectedDisplay.DeviceName, SelectedColorProfileName, SelectedDisplay.IsHdrSupportedAndEnabled);
SelectedColorProfileName = null;
@@ -265,7 +265,7 @@ else
return;
}
await _rpcClientService.CallAsync<bool>("ColorProfileService", "AddDisplayColorProfile", SelectedDisplay.DeviceName, SelectedColorProfileName, false);
await _rpcClientService.CallAsync<bool>("ColorProfileService", "AddDisplayColorProfile", SelectedDisplay.DeviceName, SelectedColorProfileName, false, SelectedDisplay.IsHdrSupportedAndEnabled);
SelectedColorProfileName = null;
@@ -21,113 +21,125 @@
</div>
<div class="modal-body">
<form class="row g-1 needs-validation @WasValidated" novalidate>
@if (Preset == null)
{
<div>Loading...</div>
}
else
{
<div class="mb-2">
<label class="form-label" for="name">Name</label>
<input class="form-control" id="name" type="text" @bind="Preset.name" required />
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" @bind="Preset.ShowInQuickAccess" id="showInQuickAccess">
<label class="form-check-label" for="showInQuickAccess">
Show in Quick Access
</label>
</div>
<div class="mb-2">
<label class="form-label" for="path">File/URI</label>
<div class="input-group mb-2">
<input class="form-control" id="path" type="text" @bind="Preset.Path" required />
<button type="button" class="btn btn-primary" @onclick="SelectFileOnClick" disabled="@SelectingFile">
<span class="@(SelectingFile ? "spinner-border spinner-border-sm" : "")" aria-hidden="true"></span>
<span role="status">Select...</span>
</button>
@if (Preset == null)
{
<div>Loading...</div>
}
else
{
if (RecentApps != null)
{
<div class="mb-2">
<label class="form-label" for="recentApp">Recent app</label>
<select class="form-select" id="recentApp" @bind="RecentAppFilename" @bind:after="RecentAppSelected">
@foreach (var app in RecentApps)
{
<option value="@app.Filename" title="@app.Path">@app.FriendlyName</option>
}
</select>
</div>
}
<div class="mb-2">
<label class="form-label" for="name">Name</label>
<input class="form-control" id="name" type="text" @bind="Preset.name" required />
</div>
<div id="selectFileHelp" class="form-text">
Selecting a file opens a file dialog outside of the browser on the system where the ColorControl application is running.
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" @bind="Preset.ShowInQuickAccess" id="showInQuickAccess">
<label class="form-check-label" for="showInQuickAccess">
Show in Quick Access
</label>
</div>
</div>
<div class="mb-2">
<label class="form-label" for="parameters">Parameters</label>
<input class="form-control" id="parameters" type="text" @bind="Preset.Parameters" />
</div>
<div class="accordion accordion-flush" id="presetAccordion">
<div class="accordion-item">
<h2 class="accordion-header">
<button class="accordion-button collapsed py-2" type="button" data-bs-toggle="collapse" data-bs-target="#advancedSettings">
Advanced settings
<div class="mb-2">
<label class="form-label" for="path">File/URI</label>
<div class="input-group mb-2">
<input class="form-control" id="path" type="text" @bind="Preset.Path" required />
<button type="button" class="btn btn-primary" @onclick="SelectFileOnClick" disabled="@SelectingFile">
<span class="@(SelectingFile ? "spinner-border spinner-border-sm" : "")" aria-hidden="true"></span>
<span role="status">Select...</span>
</button>
</h2>
<div id="advancedSettings" class="accordion-collapse collapse" data-bs-parent="#presetAccordion">
<div class="accordion-body">
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" @bind="Preset.RunAsAdministrator" id="runAsAdministrator">
<label class="form-check-label" for="runAsAdministrator">
Run as administrator
</label>
</div>
<FlagsInput Label="Process affinity" Labels="CpuAffinityLabels" @bind-Value="Preset.ProcessAffinityMask"></FlagsInput>
<div class="mb-2">
<label class="form-label" for="priority">Process priority</label>
<select class="form-select" id="priority" @bind="Preset.GameProcessPriorityClass">
@foreach (var priority in Enum.GetValues<GamePriorityClass>())
{
<option value="@priority.ToString()">@priority.GetDescription()</option>
}
</select>
</div>
<div id="selectFileHelp" class="form-text">
Selecting a file opens a file dialog outside of the browser on the system where the ColorControl application is running.
</div>
</div>
<div class="mb-2">
<label class="form-label" for="parameters">Parameters</label>
<input class="form-control" id="parameters" type="text" @bind="Preset.Parameters" />
</div>
<div class="accordion accordion-flush" id="presetAccordion">
<div class="accordion-item">
<h2 class="accordion-header">
<button class="accordion-button collapsed py-2" type="button" data-bs-toggle="collapse" data-bs-target="#advancedSettings">
Advanced settings
</button>
</h2>
<div id="advancedSettings" class="accordion-collapse collapse" data-bs-parent="#presetAccordion">
<div class="accordion-body">
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" @bind="Preset.RunAsAdministrator" id="runAsAdministrator">
<label class="form-check-label" for="runAsAdministrator">
Run as administrator
</label>
</div>
<FlagsInput Label="Process affinity" Labels="CpuAffinityLabels" @bind-Value="Preset.ProcessAffinityMask"></FlagsInput>
<div class="mb-2">
<label class="form-label" for="priority">Process priority</label>
<select class="form-select" id="priority" @bind="Preset.GameProcessPriorityClass">
@foreach (var priority in Enum.GetValues<GamePriorityClass>())
{
<option value="@priority.ToString()">@priority.GetDescription()</option>
}
</select>
</div>
</div>
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header">
<button class="accordion-button collapsed py-2" type="button" data-bs-toggle="collapse" data-bs-target="#autoApplySettings">
Auto-apply settings
</button>
</h2>
<div id="autoApplySettings" class="accordion-collapse collapse" data-bs-parent="#presetAccordion">
<div class="accordion-body">
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" @bind="Preset.AutoSettings.AllowAutoApply" id="autoApply">
<label class="form-check-label" for="autoApply">
Automatically execute preset when process starts
</label>
</div>
<div class="mb-2">
<label class="form-label" for="autoApplyAction">Auto-apply action</label>
<select class="form-select" id="priority" @bind="Preset.AutoSettings.ProcessAutoAction">
@foreach (var action in Enum.GetValues<ProcessAutoAction>())
{
<option value="@action.ToString()">@action.GetDescription()</option>
}
</select>
<div class="accordion-item">
<h2 class="accordion-header">
<button class="accordion-button collapsed py-2" type="button" data-bs-toggle="collapse" data-bs-target="#autoApplySettings">
Auto-apply settings
</button>
</h2>
<div id="autoApplySettings" class="accordion-collapse collapse" data-bs-parent="#presetAccordion">
<div class="accordion-body">
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" @bind="Preset.AutoSettings.AllowAutoApply" id="autoApply">
<label class="form-check-label" for="autoApply">
Automatically execute preset when process starts
</label>
</div>
<div class="mb-2">
<label class="form-label" for="autoApplyAction">Auto-apply action</label>
<select class="form-select" id="priority" @bind="Preset.AutoSettings.ProcessAutoAction">
@foreach (var action in Enum.GetValues<ProcessAutoAction>())
{
<option value="@action.ToString()">@action.GetDescription()</option>
}
</select>
</div>
</div>
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header">
<button class="accordion-button collapsed py-2" type="button" data-bs-toggle="collapse" data-bs-target="#steps">
Steps
</button>
</h2>
<div id="steps" class="accordion-collapse collapse" data-bs-parent="#presetAccordion">
<div class="accordion-body">
<StepsInput Label="Pre-launch" @bind-Steps="Preset.PreLaunchSteps" TPreset="GamePreset"></StepsInput>
<StepsInput Label="Post-launch" @bind-Steps="Preset.PostLaunchSteps" TPreset="GamePreset"></StepsInput>
<StepsInput Label="Finalize" @bind-Steps="Preset.FinalizeSteps" TPreset="GamePreset"></StepsInput>
<div class="accordion-item">
<h2 class="accordion-header">
<button class="accordion-button collapsed py-2" type="button" data-bs-toggle="collapse" data-bs-target="#steps">
Steps
</button>
</h2>
<div id="steps" class="accordion-collapse collapse" data-bs-parent="#presetAccordion">
<div class="accordion-body">
<StepsInput Label="Pre-launch" @bind-Steps="Preset.PreLaunchSteps" TPreset="GamePreset"></StepsInput>
<StepsInput Label="Post-launch" @bind-Steps="Preset.PostLaunchSteps" TPreset="GamePreset"></StepsInput>
<StepsInput Label="Finalize" @bind-Steps="Preset.FinalizeSteps" TPreset="GamePreset"></StepsInput>
</div>
</div>
</div>
</div>
</div>
}
}
</form>
</div>
<div class="modal-footer">
@@ -148,6 +160,8 @@
public Func<GamePreset, Task>? AfterApply { get; set; }
public List<string> CpuAffinityLabels = Enumerable.Range(0, Environment.ProcessorCount).Select(i => $"CPU #{i}").ToList();
private List<GameApp>? RecentApps;
private string RecentAppFilename = "";
public bool SelectingFile { get; set; }
@@ -162,6 +176,21 @@
}
Preset = PresetParam.CloneWithId();
if (Preset.id == 0)
{
RecentApps = await _rpcClientService.CallAsync<List<GameApp>>("GameService", "GetMruApps", true);
RecentAppFilename = "";
if (RecentApps != null)
{
RecentApps.Insert(0, new GameApp { Filename = "", FriendlyName = "Choose a recent app to fill values" });
}
}
else
{
RecentApps = null;
}
}
private async Task ApplyClick(MouseEventArgs e)
@@ -183,7 +212,7 @@
{
await AfterApply.Invoke(Preset);
}
IsVisible = false;
}
@@ -224,6 +253,22 @@
}
}
private void RecentAppSelected()
{
if (RecentApps == null || Preset == null)
{
return;
}
var app = RecentApps.FirstOrDefault(a => a.Filename == RecentAppFilename);
if (app != null)
{
Preset.name = app.FriendlyName;
Preset.Path = app.Path;
}
}
private void ModalOnFocus(FocusEventArgs e)
{
if (!IsVisible)
@@ -76,7 +76,7 @@ else
<button class="btn btn-primary btn-sm" data-bs-toggle="modal" data-bs-target="#presetModal" @onclick="() => PresetOnEditClick(preset)" @onclick:preventDefault @onclick:stopPropagation>Edit</button>
</span>
<div class="d-lg-none" @onclick:preventDefault @onclick:stopPropagation>
<button type="button" class="btn btn-outline-secondary" data-bs-toggle="dropdown" aria-expanded="false">
<button type="button" class="btn btn-sm btn-outline-secondary" data-bs-toggle="dropdown" aria-expanded="false">
<i class="bi bi-three-dots-vertical"></i>
</button>
<ul class="dropdown-menu">
@@ -122,6 +122,8 @@
<button type="button" class="btn btn-outline-primary dropdown-toggle text-break text-wrap" data-bs-toggle="dropdown" aria-expanded="false" data-bs-auto-close="outside">@step.Raw</button>
<form class="dropdown-menu p-4 dropdown-menu-end" style="width: 200px">
<div class="mb-2">
<button type="button" class="btn btn-primary btn-sm" data-bs-dismiss="dropdown" title="Move left" disabled="@(stepIndex == 0)" @onclick="() => MoveLeftOnClick(stepIndex)">&lt;</button>
<button type="button" class="btn btn-primary btn-sm" data-bs-dismiss="dropdown" title="Move right" disabled="@(stepIndex == PresetSteps.Count - 1)" @onclick="() => MoveRightOnClick(stepIndex)">&gt;</button>
<button type="button" class="btn btn-primary btn-sm" data-bs-dismiss="dropdown" @onclick="() => RemoveOnClick(stepIndex)">Remove</button>
</div>
<div class="mb-2">
@@ -260,6 +262,32 @@
await EmitSteps();
}
private async Task MoveLeftOnClick(int index)
{
if (PresetSteps.Count > index && index > 0)
{
var step = PresetSteps[index];
PresetSteps.RemoveAt(index);
PresetSteps.Insert(index - 1, step);
}
await EmitSteps();
}
private async Task MoveRightOnClick(int index)
{
if (PresetSteps.Count > index + 1)
{
var step = PresetSteps[index];
PresetSteps.RemoveAt(index);
PresetSteps.Insert(index + 1, step);
}
await EmitSteps();
}
private async Task AfterDelayChanged()
{
await EmitSteps();
@@ -178,7 +178,7 @@ else
<button class="btn btn-primary btn-sm" data-bs-toggle="modal" data-bs-target="#presetModal" @onclick="() => PresetOnEditClick(preset)" @onclick:preventDefault @onclick:stopPropagation>Edit</button>
</span>
<div class="d-lg-none" @onclick:preventDefault @onclick:stopPropagation>
<button type="button" class="btn btn-outline-secondary" data-bs-toggle="dropdown" aria-expanded="false">
<button type="button" class="btn btn-sm btn-outline-secondary" data-bs-toggle="dropdown" aria-expanded="false">
<i class="bi bi-three-dots-vertical"></i>
</button>
<ul class="dropdown-menu">
@@ -96,6 +96,39 @@ else
</div>
}
<h2>Display Adapters</h2>
@if (GpuInfos == null)
{
<div>Loading...</div>
}
else
{
<div class="row mb-3">
@if (!GpuInfos.Any())
{
<span>No display adapters found</span>
}
@foreach (var gpuInfo in GpuInfos)
{
<div class="col-lg-6 mb-3">
<div class="card h-100">
<div class="card-header d-flex align-items-baseline">
<span>
@gpuInfo.Name
</span>
</div>
<div class="card-body">
<small class="text-body">GPU: @gpuInfo.GpuFrequencyInKhz.ToUnitString() @@ @gpuInfo.VoltageInMv mV, @Utils.ToUnitString(values: [gpuInfo.GpuTemperature, gpuInfo.HotSpotTemperature])</small>
<small class="text-body">Memory: @gpuInfo.GpuFrequencyInKhz.ToUnitString(), @Utils.ToUnitString(values: [gpuInfo.MemoryTemperature])</small>
<small class="text-muted">Power: @(gpuInfo.PowerInWatts)W</small>
</div>
</div>
</div>
}
</div>
}
@if (Presets == null)
{
<div>Loading...</div>
@@ -142,7 +175,7 @@ else
<button class="btn btn-primary btn-sm" data-bs-toggle="modal" data-bs-target="#presetModal" @onclick="() => PresetOnEditClick(preset)" @onclick:preventDefault @onclick:stopPropagation>Edit</button>
</span>
<div class="d-lg-none" @onclick:preventDefault @onclick:stopPropagation>
<button type="button" class="btn btn-outline-secondary" data-bs-toggle="dropdown" aria-expanded="false">
<button type="button" class="btn btn-sm btn-outline-secondary" data-bs-toggle="dropdown" aria-expanded="false">
<i class="bi bi-three-dots-vertical"></i>
</button>
<ul class="dropdown-menu">
@@ -207,6 +240,7 @@ else
@code {
private List<NvPreset>? Presets;
private List<NvPreset>? DisplayPresets;
private List<NvGpuInfoDto>? GpuInfos;
private NvPreset? CurrentPreset;
private NvPreset? CurrentDriverSettingsPreset;
@@ -218,6 +252,7 @@ else
{
await RefreshPresets();
DisplayPresets = await _rpcClientService.CallAsync<List<NvPreset>>("NvService", "GetDisplayPresets");
GpuInfos = await _rpcClientService.CallAsync<List<NvGpuInfoDto>>("NvService", "GetGpuInfos");
}
protected override async Task OnAfterRenderAsync(bool firstTime)
@@ -176,7 +176,7 @@ else
<button class="btn btn-primary btn-sm" data-bs-toggle="modal" data-bs-target="#presetModal" @onclick="() => PresetOnEditClick(preset)" @onclick:preventDefault @onclick:stopPropagation>Edit</button>
</span>
<div class="d-lg-none" @onclick:preventDefault @onclick:stopPropagation>
<button type="button" class="btn btn-outline-secondary" data-bs-toggle="dropdown" aria-expanded="false">
<button type="button" class="btn btn-sm btn-outline-secondary" data-bs-toggle="dropdown" aria-expanded="false">
<i class="bi bi-three-dots-vertical"></i>
</button>
<ul class="dropdown-menu">
+2 -2
View File
@@ -18,8 +18,8 @@
<PublisherName>Maassoft</PublisherName>
<Company>Maassoft</Company>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>10.0.1.0</ApplicationVersion>
<Version>10.0.1.0</Version>
<ApplicationVersion>10.0.2.0</ApplicationVersion>
<Version>10.0.2.0</Version>
<UseApplicationTrust>false</UseApplicationTrust>
<PublishWizardCompleted>true</PublishWizardCompleted>
<BootstrapperEnabled>false</BootstrapperEnabled>
+331 -329
View File
@@ -21,340 +21,342 @@ using System.Windows.Forms;
namespace ColorControl
{
public partial class MainForm : Form
{
private static bool SystemShutdown = false;
private static bool EndSession = false;
public partial class MainForm : Form
{
private static bool SystemShutdown = false;
private static bool EndSession = false;
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private readonly ServiceManager _serviceManager;
private readonly IServiceProvider _serviceProvider;
private readonly ElevationService _elevationService;
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private readonly ServiceManager _serviceManager;
private readonly IServiceProvider _serviceProvider;
private readonly ElevationService _elevationService;
private NvPanel _nvPanel;
private NvPanel _nvPanel;
private readonly KeyboardShortcutDispatcher _keyboardShortcutDispatcher;
private readonly UpdateManager _updateManager;
private readonly WindowMessageDispatcher _windowMessageDispatcher;
private Config _config;
private readonly KeyboardShortcutDispatcher _keyboardShortcutDispatcher;
private readonly UpdateManager _updateManager;
private readonly WindowMessageDispatcher _windowMessageDispatcher;
private Config _config;
private LgPanel _lgPanel;
private SamsungPanel _samsungPanel;
private LgPanel _lgPanel;
private SamsungPanel _samsungPanel;
private AmdPanel _amdPanel;
private bool _skipResize;
private AmdPanel _amdPanel;
private bool _skipResize;
private GamePanel _gamePanel;
public MainForm(GlobalContext globalContext, ServiceManager serviceManager, IServiceProvider serviceProvider, ElevationService elevationService,
KeyboardShortcutDispatcher keyboardShortcutDispatcher, UpdateManager updateManager, WindowMessageDispatcher windowMessageDispatcher)
{
InitializeComponent();
private GamePanel _gamePanel;
Icon = Resources.AppIcon;
_serviceManager = serviceManager;
_serviceProvider = serviceProvider;
_elevationService = elevationService;
_keyboardShortcutDispatcher = keyboardShortcutDispatcher;
_updateManager = updateManager;
_windowMessageDispatcher = windowMessageDispatcher;
_config = Program.Config;
Text = globalContext.ApplicationTitleAdmin;
LoadConfig();
MessageForms.MainForm = this;
InitModules();
Task.Run(AfterInitialized);
if (_config.UseDarkMode)
{
SetTheme(_config.UseDarkMode);
}
}
private void InitModules()
{
var _ = tcMain.Handle;
_nvPanel = InitPanel<NvPanel>("NVIDIA controller");
_amdPanel = InitPanel<AmdPanel>("AMD controller");
_lgPanel = InitPanel<LgPanel>("LG controller");
_samsungPanel = InitPanel<SamsungPanel>("Samsung controller");
_gamePanel = InitPanel<GamePanel>("Game launcher");
tcMain.SelectedIndex = 0;
}
private T InitPanel<T>(string displayName) where T : UserControl, IModulePanel
{
var module = _config.Modules.FirstOrDefault(m => m.IsActive && m.DisplayName == displayName);
if (module == null)
{
return default;
}
try
{
var panel = _serviceProvider.GetRequiredService<T>();
panel.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
panel.Init();
var tabPage = new TabPage(module.DisplayName);
tcMain.TabPages.Insert(tcMain.TabPages.Count - 2, tabPage);
tabPage.Controls.Add(panel);
panel.Size = tabPage.ClientSize;
panel.BackColor = SystemColors.Window;
//Logger.Debug($"Panel {panel.GetType().Name}, size: {panel.Size.Width}x{panel.Size.Height}");
return panel;
}
catch (Exception ex)
{
Logger.Debug($"Error creating panel {typeof(T).Name}: {ex.ToLogString()}");
return null;
}
}
public void OpenForm()
{
Show();
WindowState = FormWindowState.Normal;
Activate();
}
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
if (Program.UserExit)
{
return;
}
if (!(SystemShutdown || EndSession) && _config.MinimizeOnClose)
{
e.Cancel = true;
WindowState = FormWindowState.Minimized;
Program.UserExit = false;
return;
}
GlobalSave();
if (SystemShutdown)
{
Logger.Debug($"MainForm_FormClosing: SystemShutdown");
}
Program.Exit();
}
private void GlobalSave()
{
_nvPanel?.Save();
_amdPanel?.Save();
_lgPanel?.Save();
_gamePanel?.Save();
_samsungPanel?.Save();
if (WindowState != FormWindowState.Minimized)
{
_config.FormWidth = Width;
_config.FormHeight = Height;
}
}
protected override void WndProc(ref Message m)
{
if (m.Msg == NativeConstants.WM_QUERYENDSESSION)
{
SystemShutdown = true;
EndSession = true;
_windowMessageDispatcher.DispatchEvent(WindowMessageDispatcher.Event_WindowMessageQueryEndSession, new WindowMessageEventArgs(m));
}
else if (m.Msg == Utils.WM_BRINGTOFRONT)
{
Logger.Debug("WM_BRINGTOFRONT message received, opening form");
OpenForm();
}
base.WndProc(ref m);
}
private void MainForm_Resize(object sender, EventArgs e)
{
if (_skipResize)
{
return;
}
if (WindowState == FormWindowState.Minimized)
{
if (_config.MinimizeToTray)
{
Hide();
}
}
else if (WindowState == FormWindowState.Normal && _config != null)
{
_config.FormWidth = Width;
_config.FormHeight = Height;
}
}
private void LoadConfig()
{
_skipResize = true;
try
{
Width = _config.FormWidth;
Height = _config.FormHeight;
}
finally
{
_skipResize = false;
}
}
private void MainForm_Shown(object sender, EventArgs e)
{
InitSelectedTab();
_elevationService.CheckElevationMethod();
}
private void tabControl1_SelectedIndexChanged(object sender, EventArgs e)
{
InitSelectedTab();
}
private void InitSelectedTab()
{
if (tcMain.SelectedTab == tabInfo)
{
InitInfoTab();
}
else if (tcMain.SelectedTab == tabOptions)
{
InitOptionsTab();
}
else if (tcMain.SelectedTab?.Controls.Count > 0 && tcMain.SelectedTab.Controls[0] is IModulePanel panel)
{
panel.UpdateInfo();
}
}
private void InitOptionsTab()
{
if (tabOptions.Controls.Count > 0)
{
return;
}
var control = _serviceProvider.GetRequiredService<OptionsPanel>();
control.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
tabOptions.Controls.Add(control);
control.Size = tabInfo.ClientSize;
}
private void InitInfoTab()
{
if (tabInfo.Controls.Count > 0)
{
return;
}
var control = _serviceProvider.GetRequiredService<InfoPanel>();
control.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
tabInfo.Controls.Add(control);
control.Size = tabInfo.ClientSize;
//control.BackColor = SystemColors.Window;
}
private void MainForm_Activated(object sender, EventArgs e)
{
if (tcMain.SelectedTab?.Controls.Count > 0 && tcMain.SelectedTab.Controls[0] is IModulePanel panel)
{
panel.UpdateInfo();
}
}
private async Task AfterInitialized()
{
if (_nvPanel != null)
{
await _nvPanel.AfterInitialized();
}
if (_amdPanel != null)
{
await _amdPanel.AfterInitialized();
}
}
private void MainForm_Deactivate(object sender, EventArgs e)
{
GlobalSave();
}
private void MainForm_ResizeBegin(object sender, EventArgs e)
{
SuspendLayout();
}
private void MainForm_ResizeEnd(object sender, EventArgs e)
{
ResumeLayout(true);
}
private async void MainForm_Click(object sender, EventArgs e)
{
_serviceManager.NvService?.TestResolution();
}
public void SetTheme(bool toDark)
{
this.UpdateTheme(toDark);
InitSelectedTab();
}
private async void btnUpdate_Click(object sender, EventArgs e)
{
await _updateManager.InstallUpdate();
}
internal void CloseForRestart()
{
Hide();
}
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if ((keyData == (Keys.Control | Keys.PageUp) || keyData == (Keys.Control | Keys.PageDown)) && KeyboardShortcutDispatcher.IsShortcutControlFocused())
{
var control = this.FindFocusedControl() as TextBox;
if (control != null)
{
var keyEvent = new KeyEventArgs(keyData);
control.Text = KeyboardShortcutDispatcher.FormatKeyboardShortcut(keyEvent);
}
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
}
public MainForm(GlobalContext globalContext, ServiceManager serviceManager, IServiceProvider serviceProvider, ElevationService elevationService,
KeyboardShortcutDispatcher keyboardShortcutDispatcher, UpdateManager updateManager, WindowMessageDispatcher windowMessageDispatcher)
{
InitializeComponent();
Icon = Resources.AppIcon;
_serviceManager = serviceManager;
_serviceProvider = serviceProvider;
_elevationService = elevationService;
_keyboardShortcutDispatcher = keyboardShortcutDispatcher;
_updateManager = updateManager;
_windowMessageDispatcher = windowMessageDispatcher;
_config = Program.Config;
Text = globalContext.ApplicationTitleAdmin;
LoadConfig();
MessageForms.MainForm = this;
InitModules();
Task.Run(AfterInitialized);
if (_config.UseDarkMode)
{
SetTheme(_config.UseDarkMode);
}
}
private void InitModules()
{
var _ = tcMain.Handle;
_nvPanel = InitPanel<NvPanel>("NVIDIA controller");
_amdPanel = InitPanel<AmdPanel>("AMD controller");
_lgPanel = InitPanel<LgPanel>("LG controller");
_samsungPanel = InitPanel<SamsungPanel>("Samsung controller");
_gamePanel = InitPanel<GamePanel>("Game launcher");
tcMain.SelectedIndex = 0;
}
private T InitPanel<T>(string displayName) where T : UserControl, IModulePanel
{
var module = _config.Modules.FirstOrDefault(m => m.IsActive && m.DisplayName == displayName);
if (module == null)
{
return default;
}
try
{
var panel = _serviceProvider.GetRequiredService<T>();
panel.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
panel.Init();
var tabPage = new TabPage(module.DisplayName);
tcMain.TabPages.Insert(tcMain.TabPages.Count - 2, tabPage);
tabPage.Controls.Add(panel);
panel.Size = tabPage.ClientSize;
panel.BackColor = SystemColors.Window;
//Logger.Debug($"Panel {panel.GetType().Name}, size: {panel.Size.Width}x{panel.Size.Height}");
return panel;
}
catch (Exception ex)
{
Logger.Debug($"Error creating panel {typeof(T).Name}: {ex.ToLogString()}");
return null;
}
}
public void OpenForm()
{
Show();
WindowState = FormWindowState.Normal;
Activate();
btnUpdate.Visible = _updateManager.UpdateAvailable();
}
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
if (Program.UserExit)
{
return;
}
if (!(SystemShutdown || EndSession) && _config.MinimizeOnClose)
{
e.Cancel = true;
WindowState = FormWindowState.Minimized;
Program.UserExit = false;
return;
}
GlobalSave();
if (SystemShutdown)
{
Logger.Debug($"MainForm_FormClosing: SystemShutdown");
}
Program.Exit();
}
private void GlobalSave()
{
_nvPanel?.Save();
_amdPanel?.Save();
_lgPanel?.Save();
_gamePanel?.Save();
_samsungPanel?.Save();
if (WindowState != FormWindowState.Minimized)
{
_config.FormWidth = Width;
_config.FormHeight = Height;
}
}
protected override void WndProc(ref Message m)
{
if (m.Msg == NativeConstants.WM_QUERYENDSESSION)
{
SystemShutdown = true;
EndSession = true;
_windowMessageDispatcher.DispatchEvent(WindowMessageDispatcher.Event_WindowMessageQueryEndSession, new WindowMessageEventArgs(m));
}
else if (m.Msg == Utils.WM_BRINGTOFRONT)
{
Logger.Debug("WM_BRINGTOFRONT message received, opening form");
OpenForm();
}
base.WndProc(ref m);
}
private void MainForm_Resize(object sender, EventArgs e)
{
if (_skipResize)
{
return;
}
if (WindowState == FormWindowState.Minimized)
{
if (_config.MinimizeToTray)
{
Hide();
}
}
else if (WindowState == FormWindowState.Normal && _config != null)
{
_config.FormWidth = Width;
_config.FormHeight = Height;
}
}
private void LoadConfig()
{
_skipResize = true;
try
{
Width = _config.FormWidth;
Height = _config.FormHeight;
}
finally
{
_skipResize = false;
}
}
private void MainForm_Shown(object sender, EventArgs e)
{
InitSelectedTab();
_elevationService.CheckElevationMethod();
}
private void tabControl1_SelectedIndexChanged(object sender, EventArgs e)
{
InitSelectedTab();
}
private void InitSelectedTab()
{
if (tcMain.SelectedTab == tabInfo)
{
InitInfoTab();
}
else if (tcMain.SelectedTab == tabOptions)
{
InitOptionsTab();
}
else if (tcMain.SelectedTab?.Controls.Count > 0 && tcMain.SelectedTab.Controls[0] is IModulePanel panel)
{
panel.UpdateInfo();
}
}
private void InitOptionsTab()
{
if (tabOptions.Controls.Count > 0)
{
return;
}
var control = _serviceProvider.GetRequiredService<OptionsPanel>();
control.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
tabOptions.Controls.Add(control);
control.Size = tabInfo.ClientSize;
}
private void InitInfoTab()
{
if (tabInfo.Controls.Count > 0)
{
return;
}
var control = _serviceProvider.GetRequiredService<InfoPanel>();
control.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
tabInfo.Controls.Add(control);
control.Size = tabInfo.ClientSize;
//control.BackColor = SystemColors.Window;
}
private void MainForm_Activated(object sender, EventArgs e)
{
if (tcMain.SelectedTab?.Controls.Count > 0 && tcMain.SelectedTab.Controls[0] is IModulePanel panel)
{
panel.UpdateInfo();
}
}
private async Task AfterInitialized()
{
if (_nvPanel != null)
{
await _nvPanel.AfterInitialized();
}
if (_amdPanel != null)
{
await _amdPanel.AfterInitialized();
}
}
private void MainForm_Deactivate(object sender, EventArgs e)
{
GlobalSave();
}
private void MainForm_ResizeBegin(object sender, EventArgs e)
{
SuspendLayout();
}
private void MainForm_ResizeEnd(object sender, EventArgs e)
{
ResumeLayout(true);
}
private async void MainForm_Click(object sender, EventArgs e)
{
_serviceManager.NvService?.TestResolution();
}
public void SetTheme(bool toDark)
{
this.UpdateTheme(toDark);
InitSelectedTab();
}
private async void btnUpdate_Click(object sender, EventArgs e)
{
await _updateManager.InstallUpdate();
}
internal void CloseForRestart()
{
Hide();
}
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if ((keyData == (Keys.Control | Keys.PageUp) || keyData == (Keys.Control | Keys.PageDown)) && KeyboardShortcutDispatcher.IsShortcutControlFocused())
{
var control = this.FindFocusedControl() as TextBox;
if (control != null)
{
var keyEvent = new KeyEventArgs(keyData);
control.Text = KeyboardShortcutDispatcher.FormatKeyboardShortcut(keyEvent);
}
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
}
}
+1
View File
@@ -342,6 +342,7 @@ namespace ColorControl.Services.AMD
var preset = GetSelectedAmdPreset();
var newPreset = preset.Clone();
newPreset.IsDisplayPreset = false;
AddOrUpdateItemAmd(newPreset);
}
+6
View File
@@ -37,6 +37,12 @@ namespace ColorControl.Services.AMD
LoadConfig();
}
protected override void AfterPresetsLoaded()
{
// Force disable display preset on presets
_presets.ForEach(p => p.IsDisplayPreset = false);
}
public static async Task<bool> ExecutePresetAsync(string idOrName)
{
try
@@ -15,329 +15,329 @@ namespace ColorControl.Services.Common;
public class ColorProfileService
{
private readonly GlobalContext _globalContext;
private readonly RpcClientService _rpcClientService;
private readonly WinApiService _winApiService;
private readonly ServiceManager _serviceManager;
private readonly WinApiAdminService _winApiAdminService;
private readonly GlobalContext _globalContext;
private readonly RpcClientService _rpcClientService;
private readonly WinApiService _winApiService;
private readonly ServiceManager _serviceManager;
private readonly WinApiAdminService _winApiAdminService;
public ColorProfileService(GlobalContext globalContext, RpcClientService rpcClientService, WinApiService winApiService, ServiceManager serviceManager, WinApiAdminService winApiAdminService)
{
_globalContext = globalContext;
_rpcClientService = rpcClientService;
_winApiService = winApiService;
_serviceManager = serviceManager;
_winApiAdminService = winApiAdminService;
public ColorProfileService(GlobalContext globalContext, RpcClientService rpcClientService, WinApiService winApiService, ServiceManager serviceManager, WinApiAdminService winApiAdminService)
{
_globalContext = globalContext;
_rpcClientService = rpcClientService;
_winApiService = winApiService;
_serviceManager = serviceManager;
_winApiAdminService = winApiAdminService;
_rpcClientService.Name = nameof(ColorProfileService);
}
_rpcClientService.Name = nameof(ColorProfileService);
}
public bool InstallColorProfile(string profileName)
{
return CCD.InstallColorProfile(profileName);
}
public bool InstallColorProfile(string profileName)
{
return CCD.InstallColorProfile(profileName);
}
public bool UninstallColorProfile(string profileName)
{
return CCD.UninstallColorProfile(profileName);
}
public bool UninstallColorProfile(string profileName)
{
return CCD.UninstallColorProfile(profileName);
}
public bool AddDisplayColorProfile(string displayName, string profileName, bool setAsDefault = true)
{
return CCD.AddDisplayColorProfile(displayName, profileName, setAsDefault);
}
public bool AddDisplayColorProfile(string displayName, string profileName, bool setAsDefault = true, bool isHdrColorProfile = false)
{
return CCD.AddDisplayColorProfile(displayName, profileName, setAsDefault, isHdrColorProfile);
}
public bool RemoveDisplayColorProfile(string displayName, string profileName)
{
return CCD.RemoveDisplayColorProfile(displayName, profileName);
}
public bool RemoveDisplayColorProfile(string displayName, string profileName, bool isHdrColorProfile = false)
{
return CCD.RemoveDisplayColorProfile(displayName, profileName, isHdrColorProfile);
}
public bool SetDisplayDefaultColorProfile(string displayName, string profileName, bool fixMaxTML = true)
{
return CCD.SetDisplayDefaultColorProfile(displayName, profileName, fixMaxTML);
}
public bool SetDisplayDefaultColorProfile(string displayName, string profileName, bool fixMaxTML = true, bool isHdrColorProfile = false)
{
return CCD.SetDisplayDefaultColorProfile(displayName, profileName, fixMaxTML, isHdrColorProfile);
}
public string GetDisplayDefaultColorProfile(string displayName, COLORPROFILESUBTYPE profileSubType = COLORPROFILESUBTYPE.CPST_STANDARD_DISPLAY_COLOR_MODE)
{
return CCD.GetDisplayDefaultColorProfile(displayName, profileSubType);
}
public string GetDisplayDefaultColorProfile(string displayName, bool isHdrColorProfile)
{
return CCD.GetDisplayDefaultColorProfile(displayName, isHdrColorProfile);
}
public List<string> GetDisplayColorProfiles(string displayName)
{
if (displayName != null && !displayName.StartsWith("\\\\"))
{
displayName = GetDisplayNameByDisplayId(displayName);
}
public List<string> GetDisplayColorProfiles(string displayName)
{
if (displayName != null && !displayName.StartsWith("\\\\"))
{
displayName = GetDisplayNameByDisplayId(displayName);
}
return CCD.GetDisplayColorProfiles(displayName);
}
return CCD.GetDisplayColorProfiles(displayName);
}
public List<string> GetAllColorProfileNames()
{
if (!_winApiService.IsAdministrator())
{
return _rpcClientService.Call<List<string>>("GetAllColorProfileNames");
}
public List<string> GetAllColorProfileNames()
{
if (!_winApiService.IsAdministrator())
{
return _rpcClientService.Call<List<string>>("GetAllColorProfileNames");
}
return CCD.GetAllColorProfileNames();
}
return CCD.GetAllColorProfileNames();
}
private string GetDisplayNameByDisplayId(string displayName)
{
var deviceName = default(string);
private string GetDisplayNameByDisplayId(string displayName)
{
var deviceName = default(string);
Display.GetDisplays().FirstOrDefault(d =>
{
var ccdDisplayInfo = CCD.GetDisplayInfo(d.DisplayName);
Display.GetDisplays().FirstOrDefault(d =>
{
var ccdDisplayInfo = CCD.GetDisplayInfo(d.DisplayName);
if (ccdDisplayInfo.DisplayId == displayName)
{
deviceName = ccdDisplayInfo.DisplayName;
if (ccdDisplayInfo.DisplayId == displayName)
{
deviceName = ccdDisplayInfo.DisplayName;
return true;
}
return false;
});
return true;
}
return false;
});
return deviceName;
}
return deviceName;
}
public bool GetUsePerUserDisplayProfiles(string displayName)
{
return CCD.GetUsePerUserDisplayProfiles(displayName);
}
public bool GetUsePerUserDisplayProfiles(string displayName)
{
return CCD.GetUsePerUserDisplayProfiles(displayName);
}
public bool SetUsePerUserDisplayProfiles(string displayName, bool usePerUserProfiles)
{
return CCD.SetUsePerUserDisplayProfiles(displayName, usePerUserProfiles);
}
public bool SetUsePerUserDisplayProfiles(string displayName, bool usePerUserProfiles)
{
return CCD.SetUsePerUserDisplayProfiles(displayName, usePerUserProfiles);
}
public bool DeleteColorProfile(string name)
{
return CCD.UninstallColorProfile(name);
}
public bool DeleteColorProfile(string name)
{
return CCD.UninstallColorProfile(name);
}
public ColorProfileDto GetColorProfile(string name)
{
var data = MHC2Wrapper.LoadProfile(name, true);
public ColorProfileDto GetColorProfile(string name, bool isHdrProfile = true)
{
var data = MHC2Wrapper.LoadProfile(name, isHdrProfile);
return new ColorProfileDto
{
Name = name,
HasExtraInfo = data.HasExtraInfo,
BlackLuminance = data.BlackLuminance,
ColorGamut = data.ColorGamut,
Description = data.Description,
DevicePrimaries = new RgbPrimariesDto(data.DevicePrimaries),
Gamma = data.Gamma,
IsHDRProfile = data.IsHDRProfile,
MaxCLL = data.MaxCLL,
MinCLL = data.MinCLL,
SDRBrightnessBoost = data.SDRBrightnessBoost,
SDRMaxBrightness = data.SDRMaxBrightness,
SDRMinBrightness = data.SDRMinBrightness,
SDRTransferFunction = data.SDRTransferFunction,
ShadowDetailBoost = data.ShadowDetailBoost,
WhiteLuminance = data.WhiteLuminance,
};
}
return new ColorProfileDto
{
Name = name,
HasExtraInfo = data.HasExtraInfo,
BlackLuminance = data.BlackLuminance,
ColorGamut = data.ColorGamut,
Description = data.Description,
DevicePrimaries = new RgbPrimariesDto(data.DevicePrimaries),
Gamma = data.Gamma,
IsHDRProfile = data.IsHDRProfile,
MaxCLL = data.MaxCLL,
MinCLL = data.MinCLL,
SDRBrightnessBoost = data.SDRBrightnessBoost,
SDRMaxBrightness = data.SDRMaxBrightness,
SDRMinBrightness = data.SDRMinBrightness,
SDRTransferFunction = data.SDRTransferFunction,
ShadowDetailBoost = data.ShadowDetailBoost,
WhiteLuminance = data.WhiteLuminance,
};
}
public bool UpdateColorProfile(ColorProfileDto colorProfile, string displayName = null)
{
var command = new GenerateProfileCommand
{
Description = colorProfile.Description,
IsHDRProfile = colorProfile.IsHDRProfile,
MinCLL = colorProfile.MinCLL,
MaxCLL = colorProfile.MaxCLL,
BlackLuminance = colorProfile.BlackLuminance,
WhiteLuminance = colorProfile.WhiteLuminance,
SDRMinBrightness = colorProfile.SDRMinBrightness,
SDRMaxBrightness = colorProfile.SDRMaxBrightness,
SDRTransferFunction = colorProfile.SDRTransferFunction,
SDRBrightnessBoost = colorProfile.SDRBrightnessBoost,
ShadowDetailBoost = colorProfile.ShadowDetailBoost,
ColorGamut = colorProfile.ColorGamut,
Gamma = colorProfile.Gamma,
DevicePrimaries = colorProfile.DevicePrimaries.ToInternal(),
};
public bool UpdateColorProfile(ColorProfileDto colorProfile, string displayName = null)
{
var command = new GenerateProfileCommand
{
Description = colorProfile.Description,
IsHDRProfile = colorProfile.IsHDRProfile,
MinCLL = colorProfile.MinCLL,
MaxCLL = colorProfile.MaxCLL,
BlackLuminance = colorProfile.BlackLuminance,
WhiteLuminance = colorProfile.WhiteLuminance,
SDRMinBrightness = colorProfile.SDRMinBrightness,
SDRMaxBrightness = colorProfile.SDRMaxBrightness,
SDRTransferFunction = colorProfile.SDRTransferFunction,
SDRBrightnessBoost = colorProfile.SDRBrightnessBoost,
ShadowDetailBoost = colorProfile.ShadowDetailBoost,
ColorGamut = colorProfile.ColorGamut,
Gamma = colorProfile.Gamma,
DevicePrimaries = colorProfile.DevicePrimaries.ToInternal(),
};
var bytes = MHC2Wrapper.GenerateSdrAcmProfile(command);
var bytes = MHC2Wrapper.GenerateSdrAcmProfile(command);
var tempFilename = Path.GetFullPath(colorProfile.Name, Path.GetTempPath());
var tempFilename = Path.GetFullPath(colorProfile.Name, Path.GetTempPath());
if (File.Exists(tempFilename))
{
File.Delete(tempFilename);
}
if (File.Exists(tempFilename))
{
File.Delete(tempFilename);
}
File.WriteAllBytes(tempFilename, bytes);
File.WriteAllBytes(tempFilename, bytes);
_winApiAdminService.UninstallColorProfile(tempFilename);
_winApiAdminService.UninstallColorProfile(tempFilename);
var result = CCD.InstallColorProfile(tempFilename);
var result = CCD.InstallColorProfile(tempFilename);
if (result && displayName != null)
{
CCD.AddDisplayColorProfile(displayName, colorProfile.Name, false);
}
if (result && displayName != null)
{
CCD.AddDisplayColorProfile(displayName, colorProfile.Name, false, command.IsHDRProfile);
}
return result;
}
return result;
}
public bool InstallAndActivateColorProfile(ColorProfileDto colorProfile, string displayName)
{
var installed = UpdateColorProfile(colorProfile);
public bool InstallAndActivateColorProfile(ColorProfileDto colorProfile, string displayName)
{
var installed = UpdateColorProfile(colorProfile);
if (!installed)
{
return false;
}
if (!installed)
{
return false;
}
var profileName = colorProfile.Name;
var profileName = colorProfile.Name;
return CCD.SetDisplayDefaultColorProfile(displayName, profileName, true);
}
return CCD.SetDisplayDefaultColorProfile(displayName, profileName, _globalContext.Config.SetMinTmlAndMaxTml, colorProfile.IsHDRProfile);
}
public List<DisplayInfoDto> GetDisplayInfos(bool? onlyHdrEnabled = null)
{
return Display.GetDisplays().Select(d =>
{
var ccdDisplayInfo = CCD.GetDisplayInfo(d.DisplayName);
var advancedColor = CCD.GetAdvancedColorSupportedAndEnabled(d.DisplayName);
var colorParams = CCD.GetColorParams(d.DisplayName);
public List<DisplayInfoDto> GetDisplayInfos(bool? onlyHdrEnabled = null)
{
return Display.GetDisplays().Select(d =>
{
var ccdDisplayInfo = CCD.GetDisplayInfo(d.DisplayName);
var advancedColor = CCD.GetAdvancedColorSupportedAndEnabled(d.DisplayName);
var colorParams = CCD.GetColorParams(d.DisplayName);
var displayColors = new List<DisplayColorInfo>
{
new DisplayColorInfo
{
DisplayPrimariesSource = MHC2Gen.DisplayPrimariesSource.Custom,
CustomName = "sRGB",
RgbPrimaries = new RgbPrimariesDto(RgbPrimaries.sRGB),
BlackLuminance = 0,
WhiteLuminance = 100,
MinCLL = 0,
MaxCLL = 100
}
};
var displayColors = new List<DisplayColorInfo>
{
new DisplayColorInfo
{
DisplayPrimariesSource = MHC2Gen.DisplayPrimariesSource.Custom,
CustomName = "sRGB",
RgbPrimaries = new RgbPrimariesDto(RgbPrimaries.sRGB),
BlackLuminance = 0,
WhiteLuminance = 100,
MinCLL = 0,
MaxCLL = 100
}
};
if (!colorParams.Equals(default(ColorParams)))
{
displayColors.Add(new DisplayColorInfo
{
DisplayPrimariesSource = MHC2Gen.DisplayPrimariesSource.Windows,
RgbPrimaries = ColorParamsToRgbPrimaries(colorParams),
BlackLuminance = (double)colorParams.MinLuminance / 10000,
WhiteLuminance = (double)colorParams.MaxLuminance / 10000,
MinCLL = (double)colorParams.MinLuminance / 10000,
MaxCLL = (double)colorParams.MaxLuminance / 10000
});
}
if (!colorParams.Equals(default(ColorParams)))
{
displayColors.Add(new DisplayColorInfo
{
DisplayPrimariesSource = MHC2Gen.DisplayPrimariesSource.Windows,
RgbPrimaries = ColorParamsToRgbPrimaries(colorParams),
BlackLuminance = (double)colorParams.MinLuminance / 10000,
WhiteLuminance = (double)colorParams.MaxLuminance / 10000,
MinCLL = (double)colorParams.MinLuminance / 10000,
MaxCLL = (double)colorParams.MaxLuminance / 10000
});
}
var edid = GetEDIDInternal(d.DevicePath);
if (edid != null)
{
displayColors.Add(new DisplayColorInfo
{
DisplayPrimariesSource = MHC2Gen.DisplayPrimariesSource.EDID,
RgbPrimaries = EdidToRgbPrimaries(edid),
BlackLuminance = (double)colorParams.MinLuminance / 10000,
WhiteLuminance = (double)colorParams.MaxLuminance / 10000,
MinCLL = (double)colorParams.MinLuminance / 10000,
MaxCLL = (double)colorParams.MaxLuminance / 10000
});
}
var edid = GetEDIDInternal(d.DevicePath);
if (edid != null)
{
displayColors.Add(new DisplayColorInfo
{
DisplayPrimariesSource = MHC2Gen.DisplayPrimariesSource.EDID,
RgbPrimaries = EdidToRgbPrimaries(edid),
BlackLuminance = (double)colorParams.MinLuminance / 10000,
WhiteLuminance = (double)colorParams.MaxLuminance / 10000,
MinCLL = (double)colorParams.MinLuminance / 10000,
MaxCLL = (double)colorParams.MaxLuminance / 10000
});
}
return new DisplayInfoDto
{
DisplayName = ccdDisplayInfo.ExtendedName,
DevicePath = ccdDisplayInfo.DevicePath,
DisplayId = ccdDisplayInfo.DisplayId,
IsActive = true,
DeviceName = d.DisplayName,
AdapterName = d.Adapter.DeviceName,
IsAdvancedColorEnabled = advancedColor.isEnabled,
IsAdvancedColorSupported = advancedColor.isSupported,
DisplayColors = displayColors,
ColorProfiles = GetDisplayColorProfiles(d.DisplayName),
DefaultColorProfile = GetDisplayDefaultColorProfile(d.DisplayName, advancedColor.isEnabled ? COLORPROFILESUBTYPE.CPST_EXTENDED_DISPLAY_COLOR_MODE : COLORPROFILESUBTYPE.CPST_STANDARD_DISPLAY_COLOR_MODE)
};
})
.Where(d => !onlyHdrEnabled.HasValue || onlyHdrEnabled == d.IsHdrSupportedAndEnabled)
.ToList();
}
return new DisplayInfoDto
{
DisplayName = ccdDisplayInfo.ExtendedName,
DevicePath = ccdDisplayInfo.DevicePath,
DisplayId = ccdDisplayInfo.DisplayId,
IsActive = true,
DeviceName = d.DisplayName,
AdapterName = d.Adapter.DeviceName,
IsAdvancedColorEnabled = advancedColor.isEnabled,
IsAdvancedColorSupported = advancedColor.isSupported,
DisplayColors = displayColors,
ColorProfiles = GetDisplayColorProfiles(d.DisplayName),
DefaultColorProfile = GetDisplayDefaultColorProfile(d.DisplayName, advancedColor.isEnabled)
};
})
.Where(d => !onlyHdrEnabled.HasValue || onlyHdrEnabled == d.IsHdrSupportedAndEnabled)
.ToList();
}
public RgbPrimariesDto ColorParamsToRgbPrimaries(ColorParams colorParams)
{
var divider = colorParams.RedPointX <= 1 << 10 ? 1 << 10 : 1 << 20;
public RgbPrimariesDto ColorParamsToRgbPrimaries(ColorParams colorParams)
{
var divider = colorParams.RedPointX <= 1 << 10 ? 1 << 10 : 1 << 20;
return new RgbPrimariesDto
{
Red = new ColorPoint
{
X = (double)colorParams.RedPointX / divider,
Y = (double)colorParams.RedPointY / divider
},
Green = new ColorPoint
{
X = (double)colorParams.GreenPointX / divider,
Y = (double)colorParams.GreenPointY / divider
},
Blue = new ColorPoint
{
X = (double)colorParams.BluePointX / divider,
Y = (double)colorParams.BluePointY / divider
},
White = new ColorPoint
{
X = (double)colorParams.WhitePointX / divider,
Y = (double)colorParams.WhitePointY / divider
}
};
}
return new RgbPrimariesDto
{
Red = new ColorPoint
{
X = (double)colorParams.RedPointX / divider,
Y = (double)colorParams.RedPointY / divider
},
Green = new ColorPoint
{
X = (double)colorParams.GreenPointX / divider,
Y = (double)colorParams.GreenPointY / divider
},
Blue = new ColorPoint
{
X = (double)colorParams.BluePointX / divider,
Y = (double)colorParams.BluePointY / divider
},
White = new ColorPoint
{
X = (double)colorParams.WhitePointX / divider,
Y = (double)colorParams.WhitePointY / divider
}
};
}
public RgbPrimariesDto EdidToRgbPrimaries(EDID edid)
{
var coords = edid.DisplayParameters.ChromaticityCoordinates;
public RgbPrimariesDto EdidToRgbPrimaries(EDID edid)
{
var coords = edid.DisplayParameters.ChromaticityCoordinates;
return new RgbPrimariesDto
{
Red = new ColorPoint
{
X = coords.RedX,
Y = coords.RedY
},
Green = new ColorPoint
{
X = coords.GreenX,
Y = coords.GreenY
},
Blue = new ColorPoint
{
X = coords.BlueX,
Y = coords.BlueY
},
White = new ColorPoint
{
X = coords.WhiteX,
Y = coords.WhiteY
}
};
}
return new RgbPrimariesDto
{
Red = new ColorPoint
{
X = coords.RedX,
Y = coords.RedY
},
Green = new ColorPoint
{
X = coords.GreenX,
Y = coords.GreenY
},
Blue = new ColorPoint
{
X = coords.BlueX,
Y = coords.BlueY
},
White = new ColorPoint
{
X = coords.WhiteX,
Y = coords.WhiteY
}
};
}
public static EDID GetEDIDInternal(string path)
{
try
{
var registryPath = "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Enum\\DISPLAY\\";
registryPath += string.Join("\\", path.Split('#').Skip(1).Take(2));
return new EDID((byte[])Registry.GetValue(registryPath + "\\Device Parameters", "EDID", null));
}
catch
{
return null;
}
}
public static EDID GetEDIDInternal(string path)
{
try
{
var registryPath = "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Enum\\DISPLAY\\";
registryPath += string.Join("\\", path.Split('#').Skip(1).Take(2));
return new EDID((byte[])Registry.GetValue(registryPath + "\\Device Parameters", "EDID", null));
}
catch
{
return null;
}
}
}
+114 -92
View File
@@ -3,136 +3,158 @@ using ColorControl.Shared.Contracts;
using ColorControl.Shared.Forms;
using ColorControl.Shared.Native;
using NWin32;
using NWin32.NativeTypes;
using Shared.Native;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
namespace ColorControl.Services.Common
{
abstract class GraphicsService<T> : ServiceBase<T> where T : PresetBase, new()
{
private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
abstract class GraphicsService<T> : ServiceBase<T> where T : PresetBase, new()
{
private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
private int _lastSetSDRBrightness = -1;
private int _lastReadSDRBrightness = -1;
private int _lastSetSDRBrightness = -1;
private int _lastReadSDRBrightness = -1;
public GraphicsService(GlobalContext globalContext) : base(globalContext)
{
}
public GraphicsService(GlobalContext globalContext) : base(globalContext)
{
}
~GraphicsService()
{
Uninitialize();
}
~GraphicsService()
{
Uninitialize();
}
public abstract bool HasDisplaysAttached(bool reinitialize = false);
public abstract bool HasDisplaysAttached(bool reinitialize = false);
public bool SetMode(string displayName, VirtualResolution resolution = null, Rational refreshRate = null, bool updateRegistry = false)
{
var displayConfig = CCD.GetDisplayConfig(displayName);
public bool SetMode(string displayName, VirtualResolution resolution = null, Rational refreshRate = null, bool updateRegistry = false)
{
var displayConfig = CCD.GetDisplayConfig(displayName);
if (refreshRate != null)
{
displayConfig.ApplyRefreshRate = true;
displayConfig.RefreshRate = refreshRate;
}
if (refreshRate != null)
{
displayConfig.ApplyRefreshRate = true;
displayConfig.RefreshRate = refreshRate;
}
if (resolution != null)
{
displayConfig.ApplyResolution = true;
displayConfig.Resolution = resolution;
}
if (resolution != null)
{
displayConfig.ApplyResolution = true;
displayConfig.Resolution = resolution;
}
return SetMode(displayName, displayConfig, updateRegistry);
}
return SetMode(displayName, displayConfig, updateRegistry);
}
public bool SetMode(string displayName, DisplayConfig displayConfig, bool updateRegistry = false)
{
var currentDisplayConfig = CCD.GetDisplayConfig(displayName);
public bool SetMode(string displayName, DisplayConfig displayConfig, bool updateRegistry = false)
{
var currentDisplayConfig = CCD.GetDisplayConfig(displayName);
if (displayConfig.ApplyRefreshRate)
{
currentDisplayConfig.RefreshRate = displayConfig.RefreshRate;
}
if (displayConfig.ApplyRefreshRate)
{
currentDisplayConfig.RefreshRate = displayConfig.RefreshRate;
}
if (displayConfig.ApplyResolution)
{
currentDisplayConfig.Resolution = displayConfig.Resolution;
}
if (displayConfig.ApplyResolution)
{
currentDisplayConfig.Resolution = displayConfig.Resolution;
}
if (displayConfig.Scaling != CCD.DisplayConfigScaling.Zero)
{
currentDisplayConfig.Scaling = displayConfig.Scaling;
}
if (displayConfig.Scaling != CCD.DisplayConfigScaling.Zero)
{
currentDisplayConfig.Scaling = displayConfig.Scaling;
}
if (displayConfig.Rotation != CCD.DisplayConfigRotation.Zero)
{
currentDisplayConfig.Rotation = displayConfig.Rotation;
}
if (displayConfig.Rotation != CCD.DisplayConfigRotation.Zero)
{
currentDisplayConfig.Rotation = displayConfig.Rotation;
}
return CCD.SetDisplayConfig(displayName, currentDisplayConfig, updateRegistry);
}
return CCD.SetDisplayConfig(displayName, currentDisplayConfig, updateRegistry);
}
public void SetSDRBrightness(string displayName, int brightnessPercent)
{
var hmon = FormUtils.GetMonitorForDisplayName(displayName);
public void SetSDRBrightness(string displayName, int brightnessPercent)
{
var hmon = FormUtils.GetMonitorForDisplayName(displayName);
if (hmon == IntPtr.Zero)
{
hmon = NativeMethods.MonitorFromWindow(0, 1);
}
if (hmon == IntPtr.Zero)
{
hmon = NativeMethods.MonitorFromWindow(0, 1);
}
var brightness = 1 + (double)brightnessPercent / 20;
var brightness = 1 + (double)brightnessPercent / 20;
WinApi.DwmpSDRToHDRBoostPtr(hmon, brightness);
WinApi.DwmpSDRToHDRBoostPtr(hmon, brightness);
_lastSetSDRBrightness = brightnessPercent;
}
_lastSetSDRBrightness = brightnessPercent;
}
public int GetSDRBrightness(string displayName)
{
var whiteLevel = CCD.GetSDRWhiteLevel(displayName);
public int GetSDRBrightness(string displayName)
{
var whiteLevel = CCD.GetSDRWhiteLevel(displayName);
if (whiteLevel >= 1000)
{
var newBrightnessPercent = (int)(whiteLevel - 1000) / 50;
if (whiteLevel >= 1000)
{
var newBrightnessPercent = (int)(whiteLevel - 1000) / 50;
if (_lastSetSDRBrightness >= 0 && newBrightnessPercent == _lastReadSDRBrightness)
{
return _lastSetSDRBrightness;
}
if (_lastSetSDRBrightness >= 0 && newBrightnessPercent == _lastReadSDRBrightness)
{
return _lastSetSDRBrightness;
}
_lastReadSDRBrightness = newBrightnessPercent;
_lastReadSDRBrightness = newBrightnessPercent;
return newBrightnessPercent;
}
return newBrightnessPercent;
}
return 0;
}
return 0;
}
protected List<Rational> GetAvailableRefreshRatesV2(string displayName, int horizontal, int vertical)
{
var dxWrapper = new DXWrapper();
protected List<Rational> GetAvailableRefreshRatesV2(string displayName, int horizontal, int vertical)
{
var dxWrapper = new DXWrapper();
var modes = dxWrapper.GetModes(displayName, (uint)horizontal, (uint)vertical);
var modes = dxWrapper.GetModes(displayName, (uint)horizontal, (uint)vertical);
var refreshRates = modes.Select(m => m.RefreshRate).DistinctBy(r => r.ToString())
.Select(r => new Rational(r.Numerator, r.Denominator));
var refreshRates = modes.Select(m => m.RefreshRate).DistinctBy(r => r.ToString())
.Select(r => new Rational(r.Numerator, r.Denominator));
return refreshRates.ToList();
}
return refreshRates.ToList();
}
protected List<VirtualResolution> GetAvailableResolutionsInternalV2(string displayName, Rational refreshRate = null)
{
var dxWrapper = new DXWrapper();
protected List<VirtualResolution> GetAvailableResolutionsInternalV2(string displayName, Rational refreshRate = null)
{
var dxWrapper = new DXWrapper();
var modes = dxWrapper.GetModes(displayName);
var modes = dxWrapper.GetModes(displayName);
var refreshRates = modes.DistinctBy(m => $"{m.Resolution.width}x{m.Resolution.height}")
.Select(m => new VirtualResolution(m.Resolution.width, m.Resolution.height));
var refreshRates = modes.DistinctBy(m => $"{m.Resolution.width}x{m.Resolution.height}")
.Select(m => new VirtualResolution(m.Resolution.width, m.Resolution.height));
return refreshRates.ToList();
}
}
return refreshRates.ToList();
}
protected bool SetMonitorScaling()
{
var devMode = new DEVMODEW();
devMode.dmSize = (ushort)Marshal.SizeOf<DEVMODEW>();
devMode.dmFields = NativeConstants.DM_LOGPIXELS;
devMode.dmLogPixels = 96 * 96 / 100;
var ptr = Marshal.AllocHGlobal(Marshal.SizeOf<DEVMODEW>());
Marshal.StructureToPtr(devMode, ptr, false);
if (NativeMethods.ChangeDisplaySettingsExW(null, ptr, 0, 0, 0) == NativeConstants.DISP_CHANGE_SUCCESSFUL)
{
var result = NativeMethods.SystemParametersInfoW(0x009F, uint.MaxValue - 6, 0, NativeConstants.SPIF_SENDCHANGE | NativeConstants.SPIF_UPDATEINIFILE);
}
return true;
}
}
}
@@ -279,6 +279,13 @@ namespace ColorControl.Services.Common
{
_presets = new List<T>();
}
AfterPresetsLoaded();
}
protected virtual void AfterPresetsLoaded()
{
}
protected void SavePresets()
+167 -165
View File
@@ -12,212 +12,214 @@ 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;
private string _downloadUrl;
private string _downloadUrl;
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 async Task<UpdateInfoDto> CheckForUpdates()
{
if (_globalContext.UpdateInfo != null)
{
return _globalContext.UpdateInfo;
}
public bool UpdateAvailable() => _globalContext.UpdateInfo?.UpdateAvailable == true;
//if (Debugger.IsAttached)
//{
// return _globalContext.UpdateInfo = new UpdateInfoDto
// {
// UpdateAvailable = true,
// NewVersionNumber = "10.0.0.2",
// DownloadUrl = "http://testurl"
// };
//}
public async Task<UpdateInfoDto> CheckForUpdates()
{
if (_globalContext.UpdateInfo != null)
{
return _globalContext.UpdateInfo;
}
if (Debugger.IsAttached)
{
return new UpdateInfoDto();
}
//if (Debugger.IsAttached)
//{
// return _globalContext.UpdateInfo = new UpdateInfoDto
// {
// UpdateAvailable = true,
// NewVersionNumber = "10.0.0.2",
// DownloadUrl = "http://testurl"
// };
//}
var json = await Utils.GetRestJsonAsync("https://api.github.com/repos/maassoft/colorcontrol/releases/latest");
if (Debugger.IsAttached)
{
return new UpdateInfoDto();
}
if (json == null)
{
return new UpdateInfoDto();
}
var json = await Utils.GetRestJsonAsync("https://api.github.com/repos/maassoft/colorcontrol/releases/latest");
_globalContext.UpdateInfo = GetUpdateInfo(json);
if (json == null)
{
return new UpdateInfoDto();
}
return _globalContext.UpdateInfo;
}
_globalContext.UpdateInfo = GetUpdateInfo(json);
private static UpdateInfoDto GetUpdateInfo(dynamic json)
{
var updateInfo = new UpdateInfoDto();
return _globalContext.UpdateInfo;
}
if (json?.tag_name == null)
{
return updateInfo;
}
private static UpdateInfoDto GetUpdateInfo(dynamic json)
{
var updateInfo = new UpdateInfoDto();
var currentVersion = Application.ProductVersion;
var cvParts = currentVersion.Split(".");
if (json?.tag_name == null)
{
return updateInfo;
}
var newVersion = (string)json.tag_name.Value.Substring(1);
var nvParts = newVersion.Split(".");
var currentVersion = Application.ProductVersion;
var cvParts = currentVersion.Split(".");
bool CompareVersions()
{
var result = true;
var aNumberIsLarger = false;
var newVersion = (string)json.tag_name.Value.Substring(1);
var nvParts = newVersion.Split(".");
for (var i = 0; i < nvParts.Length; i++)
{
var part = Utils.ParseInt(nvParts[i]);
var cvPart = Utils.ParseInt(cvParts[i]);
bool CompareVersions()
{
var result = true;
var aNumberIsLarger = false;
if (part > cvPart)
{
aNumberIsLarger = true;
break;
}
for (var i = 0; i < nvParts.Length; i++)
{
var part = Utils.ParseInt(nvParts[i]);
var cvPart = Utils.ParseInt(cvParts[i]);
if (part == cvPart)
{
continue;
}
if (part > cvPart)
{
aNumberIsLarger = true;
break;
}
result = false;
break;
}
if (part == cvPart)
{
continue;
}
return result && aNumberIsLarger;
}
result = false;
break;
}
updateInfo.NewVersionNumber = newVersion;
updateInfo.UpdateAvailable = nvParts.Length != cvParts.Length || CompareVersions();
return result && aNumberIsLarger;
}
updateInfo.HtmlUrl = json.html_url.Value;
updateInfo.NewVersionNumber = newVersion;
updateInfo.UpdateAvailable = nvParts.Length != cvParts.Length || CompareVersions();
if (json.assets != null)
{
var asset = json.assets[0];
updateInfo.DownloadUrl = asset.browser_download_url.Value;
}
updateInfo.HtmlUrl = json.html_url.Value;
return updateInfo;
}
if (json.assets != null)
{
var asset = json.assets[0];
updateInfo.DownloadUrl = asset.browser_download_url.Value;
}
public async Task<bool> InstallUpdate()
{
if (_globalContext.UpdateInfo?.DownloadUrl == null)
{
return false;
}
return updateInfo;
}
if (Debugger.IsAttached)
{
await Task.Delay(5000);
return true;
}
public async Task<bool> InstallUpdate()
{
if (_globalContext.UpdateInfo?.DownloadUrl == null)
{
return false;
}
var message = new SvcInstallUpdateMessage
{
DownloadUrl = _globalContext.UpdateInfo?.DownloadUrl,
ClientPath = new FileInfo(Application.ExecutablePath).Directory.FullName
};
if (Debugger.IsAttached)
{
await Task.Delay(5000);
return true;
}
var result = await PipeUtils.SendMessageAsync(message, 30000);
var message = new SvcInstallUpdateMessage
{
DownloadUrl = _globalContext.UpdateInfo?.DownloadUrl,
ClientPath = new FileInfo(Application.ExecutablePath).Directory.FullName
};
if (result != null && !result.Result)
{
if (Program.IsMainFormOpened())
{
MessageForms.ErrorOk($"Error while updating: {result.ErrorMessage}");
}
var result = await PipeUtils.SendMessageAsync(message, 30000);
return false;
}
if (result != null && !result.Result)
{
if (Program.IsMainFormOpened())
{
MessageForms.ErrorOk($"Error while updating: {result.ErrorMessage}");
}
await PipeUtils.SendMessageAsync(SvcMessageType.RestartAfterUpdate);
return false;
}
if (Program.IsMainFormOpened() && MessageForms.QuestionYesNo("Update installed successfully. Do you want to restart the application?") == DialogResult.Yes)
{
Program.Restart();
}
await PipeUtils.SendMessageAsync(SvcMessageType.RestartAfterUpdate);
return true;
}
if (Program.IsMainFormOpened() && MessageForms.QuestionYesNo("Update installed successfully. Do you want to restart the application?") == DialogResult.Yes)
{
Program.Restart();
}
public async Task<bool> RestartAfterUpdate()
{
Program.Restart();
return true;
}
return true;
}
public async Task<bool> RestartAfterUpdate()
{
Program.Restart();
return true;
}
}
@@ -3,6 +3,7 @@ using ColorControl.Shared.Common;
using ColorControl.Shared.Contracts.Game;
using ColorControl.Shared.EventDispatcher;
using ColorControl.Shared.Services;
using Microsoft.Win32;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
@@ -330,5 +331,54 @@ namespace ColorControl.Services.GameLauncher
return fileInfo.FullName;
}
public List<GameApp> GetMruApps(bool skipExistingPresets = false)
{
var key = Registry.ClassesRoot.OpenSubKey(@"Local Settings\Software\Microsoft\Windows\Shell\MuiCache");
if (key == null)
{
return new List<GameApp>();
}
var names = key.GetValueNames();
var apps = new List<GameApp>();
var winFolder = Environment.GetFolderPath(Environment.SpecialFolder.Windows);
foreach (var name in names)
{
var parts = name.Split('.');
if (parts.Last() != "FriendlyAppName")
{
continue;
}
var path = name.Replace("." + parts.Last(), "");
if (skipExistingPresets && _presets.Any(p => p.Path.Equals(path, StringComparison.OrdinalIgnoreCase)))
{
continue;
}
if (!path.StartsWith(winFolder) && Path.Exists(path))
{
var friendlyName = key.GetValue(name)?.ToString();
var app = new GameApp
{
Path = path,
Filename = Path.GetFileName(path),
FriendlyName = friendlyName
};
apps.Add(app);
}
}
apps = apps.DistinctBy(a => a.Path).OrderBy(a => a.FriendlyName).ToList();
return apps;
}
}
}
+62 -27
View File
@@ -15,13 +15,6 @@ using static NvAPIWrapper.Native.GPU.Structures.PrivateClockBoostLockV2;
namespace ColorControl.Services.NVIDIA
{
public enum NvThermalSensorType
{
Gpu = 0,
HotSpot = 1,
Memory = 3
}
public class NvGpuInfo
{
private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
@@ -42,6 +35,14 @@ namespace ColorControl.Services.NVIDIA
public string PCIIdentifier { get; private set; }
public uint GpuFrequencyInKhz { get; private set; }
public uint MemoryFrequencyInKhz { get; private set; }
public uint VoltageInMv { get; private set; }
public double PowerInWatts { get; private set; }
public double? GpuTemperature { get; private set; }
public double? HotSpotTemperature { get; private set; }
public double? MemoryTemperature { get; private set; }
public static readonly PublicClockDomain[] Domains = new[] { PublicClockDomain.Graphics, PublicClockDomain.Memory };
@@ -56,17 +57,10 @@ namespace ColorControl.Services.NVIDIA
var gpu = gpus.FirstOrDefault(g => g.BusInformation.PCIIdentifiers.ToString() == pciId);
return GetGpuInfo(gpu);
return new NvGpuInfo(gpu);
}
public static NvGpuInfo GetGpuInfo(PhysicalGPU gpu)
{
var gpuInfo = new NvGpuInfo(gpu);
return gpuInfo;
}
private NvGpuInfo(PhysicalGPU gpu)
public NvGpuInfo(PhysicalGPU gpu)
{
GPU = gpu;
PCIIdentifier = GPU.BusInformation.PCIIdentifiers.ToString();
@@ -101,6 +95,32 @@ namespace ColorControl.Services.NVIDIA
SetSupportedOcTypes();
}
public NvGpuInfoDto ToDto()
{
Refresh();
return new NvGpuInfoDto
{
PCIIdentifier = PCIIdentifier,
Name = GPU.FullName,
ClockBoostLocks = ClockBoostLocks,
CurveV1 = CurveV1,
CurveV3 = CurveV3,
DefaultPowerInMilliWatts = DefaultPowerInMilliWatts,
VoltageInMv = VoltageInMv,
PowerInWatts = Math.Round(PowerInWatts, 1),
GpuFrequencyInKhz = GpuFrequencyInKhz,
MemoryFrequencyInKhz = MemoryFrequencyInKhz,
GpuTemperature = GpuTemperature,
HotSpotTemperature = HotSpotTemperature,
MemoryTemperature = MemoryTemperature,
MaxPowerInMilliWatts = MaxPowerInMilliWatts,
MinPowerInMilliWatts = MinPowerInMilliWatts,
StockGraphicsClock = StockGraphicsClock,
StockMemoryClock = StockMemoryClock
};
}
private void ReadMinMaxPower()
{
if (NvidiaML.IsAvailable || NvidiaML.Initialize())
@@ -288,30 +308,42 @@ namespace ColorControl.Services.NVIDIA
GPUApi.ClientPowerPoliciesSetStatus(GPU.Handle, status);
}
public override string ToString()
public void Refresh()
{
var gpuVoltage = GPUApi.GetCurrentVoltage(GPU.Handle).ValueInMicroVolt;
GpuFrequencyInKhz = GPU.CurrentClockFrequencies.GraphicsClock.Frequency;
MemoryFrequencyInKhz = GPU.CurrentClockFrequencies.MemoryClock.Frequency;
VoltageInMv = GPUApi.GetCurrentVoltage(GPU.Handle).ValueInMicroVolt / 1000;
PowerInWatts = GetPowerUsageInMilliWatts() / 1000.0;
var temps = GetTemperatures();
var power = GetPowerUsageInMilliWatts();
GpuTemperature = temps.TryGetValue(NvThermalSensorType.Gpu, out var gpuTemp) ? gpuTemp : null;
HotSpotTemperature = temps.TryGetValue(NvThermalSensorType.HotSpot, out var hotSpotTemp) ? hotSpotTemp : null;
MemoryTemperature = temps.TryGetValue(NvThermalSensorType.Memory, out var memoryTemp) ? memoryTemp : null;
}
public override string ToString()
{
Refresh();
var sb = new StringBuilder();
sb.Append($"GPU: {GPU.CurrentClockFrequencies.GraphicsClock.Frequency.ToUnitString()} @ {gpuVoltage / 1000} mV, {temps[NvThermalSensorType.Gpu]}°");
sb.Append($"GPU: {GpuFrequencyInKhz.ToUnitString()} @ {VoltageInMv} mV, {GpuTemperature}°");
if (temps.TryGetValue(NvThermalSensorType.HotSpot, out var hotSpotTemp))
if (HotSpotTemperature.HasValue)
{
sb.Append($"/{hotSpotTemp}°");
sb.Append($"/{HotSpotTemperature}°");
}
sb.Append($", Mem: {GPU.CurrentClockFrequencies.MemoryClock.Frequency.ToUnitString()}");
sb.Append($", Mem: {MemoryFrequencyInKhz.ToUnitString()}");
if (temps.TryGetValue(NvThermalSensorType.Memory, out var memoryTemp))
if (MemoryTemperature.HasValue)
{
sb.Append($", {memoryTemp}°");
sb.Append($", {MemoryTemperature}°");
}
sb.Append($", Pwr: {Math.Round(power / 1000.0, 1)}W");
sb.Append($", Pwr: {Math.Round(PowerInWatts, 1)}W");
return sb.ToString();
}
@@ -335,7 +367,10 @@ namespace ColorControl.Services.NVIDIA
catch (Exception)
{
var gpuThermal = GPU.ThermalInformation.ThermalSensors.FirstOrDefault(s => s.Target == ThermalSettingsTarget.GPU);
temperatures.Add(NvThermalSensorType.Gpu, gpuThermal.CurrentTemperature);
if (gpuThermal != null)
{
temperatures.Add(NvThermalSensorType.Gpu, gpuThermal.CurrentTemperature);
}
}
return temperatures;
+3 -2
View File
@@ -257,6 +257,7 @@ namespace ColorControl.Services.NVIDIA
}
var newPreset = preset.Clone();
newPreset.IsDisplayPreset = false;
AddOrUpdateItem(newPreset);
}
@@ -1594,7 +1595,7 @@ namespace ColorControl.Services.NVIDIA
return;
}
var gpuInfo = NvGpuInfo.GetGpuInfo(gpu);
var gpuInfo = new NvGpuInfo(gpu);
var currentSettings = gpuInfo.GetOverclockSettings();
var newSettings = AskNvOcSettings(gpuInfo, currentSettings);
@@ -1798,7 +1799,7 @@ namespace ColorControl.Services.NVIDIA
return;
}
var gpuInfo = NvGpuInfo.GetGpuInfo(gpu);
var gpuInfo = new NvGpuInfo(gpu);
var ocSettings = gpuInfo.GetOverclockSettings();
edtNvGpuInfo.Text = gpuInfo.ToString();
+45 -31
View File
@@ -32,7 +32,6 @@ using System.Security.Principal;
using System.Threading;
using System.Threading.Tasks;
using static ColorControl.Shared.Contracts.NVIDIA.NvHdrSettings;
using static ColorControl.Shared.Native.CCD;
namespace ColorControl.Services.NVIDIA
{
@@ -158,6 +157,12 @@ namespace ColorControl.Services.NVIDIA
LoadPresets();
}
protected override void AfterPresetsLoaded()
{
// Force disable display preset on presets
_presets.ForEach(p => p.IsDisplayPreset = false);
}
public override void InstallEventHandlers()
{
SetShortcuts(SHORTCUTID_NVQA, Config.QuickAccessShortcut);
@@ -419,7 +424,7 @@ namespace ColorControl.Services.NVIDIA
{
if (preset.ColorProfileSettings.ProfileName != null)
{
CCD.SetDisplayDefaultColorProfile(display.Name, preset.ColorProfileSettings.ProfileName, _globalContext.Config.SetMinTmlAndMaxTml);
CCD.SetDisplayDefaultColorProfile(display.Name, preset.ColorProfileSettings.ProfileName, _globalContext.Config.SetMinTmlAndMaxTml, newHdrEnabled);
}
if (preset.scaling.HasValue)
@@ -462,6 +467,9 @@ namespace ColorControl.Services.NVIDIA
result = ApplyOverclocking(preset.ocSettings);
}
//SetMonitorScaling();
//CCD.SetScaling(100);
_lastAppliedPreset = preset;
preset.IsStartupPreset = false;
@@ -627,13 +635,27 @@ namespace ColorControl.Services.NVIDIA
public void SetHDRState(Display display, bool enabled)
{
if (!enabled && Hdr10OutputModeForced.HasValue)
{
SetOutputMode(NV_DISPLAY_OUTPUT_MODE.NV_DISPLAY_OUTPUT_MODE_SDR, display);
Hdr10OutputModeForced = null;
}
CCD.SetHDRState(enabled, display.Name);
if (!enabled)
{
if (Hdr10OutputModeForced.HasValue)
{
SetOutputMode(NV_DISPLAY_OUTPUT_MODE.NV_DISPLAY_OUTPUT_MODE_SDR, display);
Hdr10OutputModeForced = null;
}
// Sometimes HDR doesn't turn off properly via CCD. Force it using NvApi.
Logger.Swallow(() =>
{
var hdrColorData = display.DisplayDevice.HDRColorData;
if (hdrColorData != null && hdrColorData.HDRMode != ColorDataHDRMode.Off)
{
hdrColorData.HDRMode = ColorDataHDRMode.Off;
display.DisplayDevice.SetHDRColorData(hdrColorData);
}
});
}
}
public void SetDigitalVibranceLevel(Display display, int level)
@@ -1206,7 +1228,7 @@ namespace ColorControl.Services.NVIDIA
public void SetColorProfile(Display display, string name)
{
CCD.SetDisplayDefaultColorProfile(display.Name, name, _globalContext.Config.SetMinTmlAndMaxTml);
CCD.SetDisplayDefaultColorProfile(display.Name, name, _globalContext.Config.SetMinTmlAndMaxTml, IsHDREnabled(display));
}
public void TestResolution()
@@ -1348,6 +1370,15 @@ namespace ColorControl.Services.NVIDIA
return gpus;
}
public List<NvGpuInfoDto> GetGpuInfos()
{
var gpus = GetGPUs();
var infos = gpus.Select(g => new NvGpuInfo(g));
var dtos = infos.Select(i => i.ToDto()).ToList();
return dtos;
}
public List<NvDisplayInfo> GetSimpleDisplayInfos()
{
var displays = GetDisplays();
@@ -1457,7 +1488,7 @@ namespace ColorControl.Services.NVIDIA
preset.HdmiInfoFrameSettings = GetHdmiSettings(display);
preset.SDRBrightness = GetSDRBrightness(display.Name);
preset.scaling = GetScaling(display);
preset.ColorProfileSettings.ProfileName = CCD.GetDisplayDefaultColorProfile(display.Name, preset.HDREnabled ? COLORPROFILESUBTYPE.CPST_EXTENDED_DISPLAY_COLOR_MODE : COLORPROFILESUBTYPE.CPST_STANDARD_DISPLAY_COLOR_MODE);
preset.ColorProfileSettings.ProfileName = CCD.GetDisplayDefaultColorProfile(display.Name, preset.HDREnabled);
preset.DisplayConfig = CCD.GetDisplayConfig(display.Name);
@@ -1482,7 +1513,7 @@ namespace ColorControl.Services.NVIDIA
foreach (var gpu in gpus)
{
var gpuInfo = NvGpuInfo.GetGpuInfo(gpu);
var gpuInfo = new NvGpuInfo(gpu);
var settings = gpuInfo.GetOverclockSettings();
@@ -1620,30 +1651,13 @@ namespace ColorControl.Services.NVIDIA
private List<string> GetProfileNamesOfMru()
{
var key = Registry.ClassesRoot.OpenSubKey(@"Local Settings\Software\Microsoft\Windows\Shell\MuiCache");
if (key == null)
if (_serviceManager.GameService == null)
{
return new List<string>();
}
var names = key.GetValueNames();
var appNames = new List<string>();
var winFolder = Environment.GetFolderPath(Environment.SpecialFolder.Windows);
foreach (var name in names)
{
var parts = name.Split('.');
var path = name.Replace("." + parts.Last(), "");
if (!path.StartsWith(winFolder) && Path.Exists(path))
{
appNames.Add(Path.GetFileName(path));
}
}
appNames = appNames.Distinct().ToList();
var apps = _serviceManager.GameService.GetMruApps();
var appNames = apps.Select(a => a.Filename).ToList();
var profiles = DrsServiceLocator.SettingService.GetProfileNamesByApps(appNames);
@@ -158,7 +158,7 @@ namespace ColorControl.XForms
var profileName = Path.GetFileName(tempFilename);
if (CCD.SetDisplayDefaultColorProfile(displayName, profileName, _viewModel.SetMinMaxTml))
if (CCD.SetDisplayDefaultColorProfile(displayName, profileName, _viewModel.SetMinMaxTml, _viewModel.IsHDR))
{
if (!_viewModel.ExistingProfiles.Contains(profileName))
{
+5 -5
View File
@@ -1,7 +1,7 @@
using System;
using NvAPIWrapper.Native.Display;
using NvAPIWrapper.Native.Display;
using NvAPIWrapper.Native.Display.Structures;
using NvAPIWrapper.Native.Interfaces.Display;
using System;
namespace NvAPIWrapper.Display
{
@@ -70,7 +70,7 @@ namespace NvAPIWrapper.Display
public ColorDataDynamicRange? DynamicRange { get; }
/// <inheritdoc />
public ColorDataHDRMode HDRMode { get; }
public ColorDataHDRMode HDRMode { get; set; }
/// <inheritdoc />
public MasteringDisplayColorData MasteringDisplayData { get; }
@@ -115,7 +115,7 @@ namespace NvAPIWrapper.Display
return false;
}
return Equals((HDRColorData) obj);
return Equals((HDRColorData)obj);
}
/// <inheritdoc />
@@ -126,7 +126,7 @@ namespace NvAPIWrapper.Display
var hashCode = ColorDepth.GetHashCode();
hashCode = (hashCode * 397) ^ ColorFormat.GetHashCode();
hashCode = (hashCode * 397) ^ DynamicRange.GetHashCode();
hashCode = (hashCode * 397) ^ (int) HDRMode;
hashCode = (hashCode * 397) ^ (int)HDRMode;
hashCode = (hashCode * 397) ^ MasteringDisplayData.GetHashCode();
return hashCode;
+6
View File
@@ -755,5 +755,11 @@ The best and suggested method to provide this is via a Windows Service. Only whe
public static string ToUnitString(this uint value, int div = 1000, string units = "MHz") => $"{value / div}{units}";
public static string ToUnitString(this int value, int div = 1000, string units = "MHz") => $"{value / div}{units}";
public static string ToUnitString(string units = "°", params double?[] values)
{
var notNullValues = values.Where(v => v.HasValue).Select(v => $"{v}{units}");
return string.Join("/", notNullValues);
}
}
}
+8
View File
@@ -0,0 +1,8 @@
namespace ColorControl.Shared.Contracts.Game;
public class GameApp
{
public string Path { get; set; }
public string Filename { get; set; }
public string FriendlyName { get; set; }
}
+33 -26
View File
@@ -4,42 +4,49 @@ namespace ColorControl.Shared.Contracts.NVIDIA;
public enum NvDitherState
{
[Description("Auto")]
Auto = 0,
[Description("Enabled")]
Enabled = 1,
[Description("Disabled")]
Disabled = 2
[Description("Auto")]
Auto = 0,
[Description("Enabled")]
Enabled = 1,
[Description("Disabled")]
Disabled = 2
}
public enum NvDitherBits
{
[Description("6-bit")]
Bits6 = 0,
[Description("8-bit")]
Bits8 = 1,
[Description("10-bit")]
Bits10 = 2
[Description("6-bit")]
Bits6 = 0,
[Description("8-bit")]
Bits8 = 1,
[Description("10-bit")]
Bits10 = 2
}
public enum NvDitherMode
{
[Description("Spatial Dynamic")]
SpatialDynamic = 0,
[Description("Spatial Static")]
SpatialStatic = 1,
[Description("Spatial Dynamic 2x2")]
SpatialDynamic2x2 = 2,
[Description("Spatial Static 2x2")]
SpatialStatic2x2 = 3,
[Description("Temporal")]
Temporal = 4
[Description("Spatial Dynamic")]
SpatialDynamic = 0,
[Description("Spatial Static")]
SpatialStatic = 1,
[Description("Spatial Dynamic 2x2")]
SpatialDynamic2x2 = 2,
[Description("Spatial Static 2x2")]
SpatialStatic2x2 = 3,
[Description("Temporal")]
Temporal = 4
}
public enum NovideoColorSpace
{
sRGB,
DisplayP3,
AdobeRGB,
BT2020
sRGB,
DisplayP3,
AdobeRGB,
BT2020
}
public enum NvThermalSensorType
{
Gpu = 0,
HotSpot = 1,
Memory = 3
}
+28
View File
@@ -0,0 +1,28 @@
using NvAPIWrapper.Native.GPU.Structures;
using static NvAPIWrapper.Native.GPU.Structures.PrivateClockBoostLockV2;
namespace ColorControl.Shared.Contracts.NVIDIA;
public class NvGpuInfoDto
{
public List<ClockBoostLock> ClockBoostLocks { get; set; } = new();
public ClockDomainInfo StockGraphicsClock { get; set; }
public ClockDomainInfo StockMemoryClock { get; set; }
public PrivateVFPCurveV3 CurveV3 { get; set; }
public PrivateVFPCurveV1 CurveV1 { get; set; }
public int? DefaultPowerInMilliWatts { get; set; }
public int MinPowerInMilliWatts { get; set; }
public int MaxPowerInMilliWatts { get; set; }
public int MinCoreStepInMHz { get; set; } = 15;
public List<NvGpuOcType> SupportedOcTypes { get; set; } = new();
public string PCIIdentifier { get; set; }
public string Name { get; set; }
public uint GpuFrequencyInKhz { get; set; }
public uint MemoryFrequencyInKhz { get; set; }
public uint VoltageInMv { get; set; }
public double PowerInWatts { get; set; }
public double? GpuTemperature { get; set; }
public double? HotSpotTemperature { get; set; }
public double? MemoryTemperature { get; set; }
}
File diff suppressed because it is too large. Load diff
+101 -16
View File
@@ -325,12 +325,12 @@ namespace ColorControl.Shared.Native
private static bool MinRequiredVersion = true;
public static bool AddDisplayColorProfile(string displayName, string profileName, bool setAsDefault = true)
public static bool AddDisplayColorProfile(string displayName, string profileName, bool setAsDefault = true, bool isHdrColorProfile = false)
{
var adapterId = GetAdapterId(displayName);
var sourceId = GetSourceId(displayName);
var err = NativeMethods.ColorProfileAddDisplayAssociation(WCS_PROFILE_MANAGEMENT_SCOPE.WCS_PROFILE_MANAGEMENT_SCOPE_CURRENT_USER, profileName, adapterId, sourceId, setAsDefault, true);
var err = NativeMethods.ColorProfileAddDisplayAssociation(WCS_PROFILE_MANAGEMENT_SCOPE.WCS_PROFILE_MANAGEMENT_SCOPE_CURRENT_USER, profileName, adapterId, sourceId, setAsDefault, isHdrColorProfile);
if (err != NativeConstants.ERROR_SUCCESS)
{
@@ -340,12 +340,12 @@ namespace ColorControl.Shared.Native
return err == NativeConstants.ERROR_SUCCESS;
}
public static bool RemoveDisplayColorProfile(string displayName, string profileName)
public static bool RemoveDisplayColorProfile(string displayName, string profileName, bool isHdrColorProfile = false)
{
var adapterId = GetAdapterId(displayName);
var sourceId = GetSourceId(displayName);
var err = NativeMethods.ColorProfileRemoveDisplayAssociation(WCS_PROFILE_MANAGEMENT_SCOPE.WCS_PROFILE_MANAGEMENT_SCOPE_CURRENT_USER, profileName, adapterId, sourceId, true);
var err = NativeMethods.ColorProfileRemoveDisplayAssociation(WCS_PROFILE_MANAGEMENT_SCOPE.WCS_PROFILE_MANAGEMENT_SCOPE_CURRENT_USER, profileName, adapterId, sourceId, isHdrColorProfile);
if (err != NativeConstants.ERROR_SUCCESS)
{
@@ -355,26 +355,26 @@ namespace ColorControl.Shared.Native
return err == NativeConstants.ERROR_SUCCESS;
}
public static bool SetDisplayDefaultColorProfile(string displayName, string profileName, bool fixMaxTML = true)
public static bool SetDisplayDefaultColorProfile(string displayName, string profileName, bool fixMaxTML = true, bool isHdrColorProfile = false)
{
var adapterId = GetAdapterId(displayName);
var sourceId = GetSourceId(displayName);
var subType = COLORPROFILESUBTYPE.CPST_PERCEPTUAL;
if (profileName == null)
{
profileName = GetDisplayDefaultColorProfile(displayName, COLORPROFILESUBTYPE.CPST_EXTENDED_DISPLAY_COLOR_MODE);
profileName = GetDisplayDefaultColorProfile(displayName, isHdrColorProfile);
if (profileName == null)
{
return true;
}
return RemoveDisplayColorProfile(displayName, profileName) && AddDisplayColorProfile(displayName, profileName, false);
return RemoveDisplayColorProfile(displayName, profileName, isHdrColorProfile) && AddDisplayColorProfile(displayName, profileName, false, isHdrColorProfile);
}
var err = NativeMethods.ColorProfileSetDisplayDefaultAssociation(WCS_PROFILE_MANAGEMENT_SCOPE.WCS_PROFILE_MANAGEMENT_SCOPE_CURRENT_USER, profileName, COLORPROFILETYPE.CPT_ICC, subType, adapterId, sourceId);
var profileSubType = GetColorProfileSubTypeByDynamicRange(isHdrColorProfile);
var err = NativeMethods.ColorProfileSetDisplayDefaultAssociation(WCS_PROFILE_MANAGEMENT_SCOPE.WCS_PROFILE_MANAGEMENT_SCOPE_CURRENT_USER, profileName, COLORPROFILETYPE.CPT_ICC, profileSubType, adapterId, sourceId);
if (err != NativeConstants.ERROR_SUCCESS)
{
@@ -394,7 +394,7 @@ namespace ColorControl.Shared.Native
return err == NativeConstants.ERROR_SUCCESS;
}
public static string GetDisplayDefaultColorProfile(string displayName, COLORPROFILESUBTYPE profileSubType = COLORPROFILESUBTYPE.CPST_STANDARD_DISPLAY_COLOR_MODE)
public static string GetDisplayDefaultColorProfile(string displayName, bool isHdrColorProfile)
{
if (!MinRequiredVersion)
{
@@ -404,6 +404,8 @@ namespace ColorControl.Shared.Native
var adapterId = GetAdapterId(displayName);
var sourceId = GetSourceId(displayName);
var profileSubType = GetColorProfileSubTypeByDynamicRange(isHdrColorProfile);
var scope = GetUsePerUserDisplayProfiles(displayName) ? WCS_PROFILE_MANAGEMENT_SCOPE.WCS_PROFILE_MANAGEMENT_SCOPE_CURRENT_USER : WCS_PROFILE_MANAGEMENT_SCOPE.WCS_PROFILE_MANAGEMENT_SCOPE_SYSTEM_WIDE;
try
{
@@ -431,6 +433,11 @@ namespace ColorControl.Shared.Native
return null;
}
public static COLORPROFILESUBTYPE GetColorProfileSubTypeByDynamicRange(bool isHdr)
{
return isHdr ? COLORPROFILESUBTYPE.CPST_EXTENDED_DISPLAY_COLOR_MODE : COLORPROFILESUBTYPE.CPST_STANDARD_DISPLAY_COLOR_MODE;
}
[StructLayout(LayoutKind.Sequential)]
public struct UnmanagedStruct
{
@@ -652,6 +659,78 @@ namespace ColorControl.Shared.Native
);
}
public static DISPLAYCONFIG_SOURCE_DPI_SCALE_GET GetScaling(string displayName = null)
{
return ExecuteForModeConfig((modeInfo) =>
{
if (modeInfo.infoType == DisplayConfigModeInfoType.Source)
{
var requestPacket = new DISPLAYCONFIG_SOURCE_DPI_SCALE_GET();
requestPacket.header = new DISPLAYCONFIG_DEVICE_INFO_HEADER();
requestPacket.header.type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_DPI_SCALE;
requestPacket.header.size = Marshal.SizeOf<DISPLAYCONFIG_SOURCE_DPI_SCALE_GET>();
requestPacket.header.adapterId = modeInfo.adapterId;
requestPacket.header.id = modeInfo.id;
var err = NativeMethods.DisplayConfigGetDeviceInfo(ref requestPacket);
if (err == NativeConstants.ERROR_SUCCESS)
{
return (requestPacket, false);
}
}
return (default, true);
}, displayName
);
}
public static bool SetScaling(int percentage, string displayName = null)
{
var dpiInfo = GetScaling(displayName);
if (percentage == dpiInfo.curScaleRel)
{
return true;
}
if (percentage < dpiInfo.minScaleRel)
{
percentage = dpiInfo.minScaleRel;
}
else if (percentage > dpiInfo.maxScaleRel)
{
percentage = dpiInfo.maxScaleRel;
}
return ExecuteForModeConfig((modeInfo) =>
{
if (modeInfo.infoType == DisplayConfigModeInfoType.Source)
{
var setPacket = new DISPLAYCONFIG_SOURCE_DPI_SCALE_SET();
setPacket.header = new DISPLAYCONFIG_DEVICE_INFO_HEADER();
setPacket.header.type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_SET_DPI_SCALE;
setPacket.header.size = Marshal.SizeOf<DISPLAYCONFIG_SOURCE_DPI_SCALE_SET>();
setPacket.header.adapterId = modeInfo.adapterId;
setPacket.header.id = modeInfo.id;
setPacket.scaleRel = -7;
var err = NativeMethods.DisplayConfigSetDeviceInfo(ref setPacket);
if (err == NativeConstants.ERROR_SUCCESS)
{
return (true, false);
}
}
return (false, true);
}, displayName
);
}
private static T ExecuteForModeConfig<T>(DisplayConfigModeInfoDelegate<T> infoDelegate, string displayName = null, QueryDisplayFlags queryDisplayFlags = QueryDisplayFlags.OnlyActivePaths)
{
uint pathCount, modeCount;
@@ -921,14 +1000,14 @@ namespace ColorControl.Shared.Native
return displayName1.Equals(displayName2, StringComparison.OrdinalIgnoreCase);
}
private enum DISPLAYCONFIG_MODE_INFO_TYPE
public enum DISPLAYCONFIG_MODE_INFO_TYPE
{
DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE = 1,
DISPLAYCONFIG_MODE_INFO_TYPE_TARGET = 2,
DISPLAYCONFIG_MODE_INFO_TYPE_DESKTOP_IMAGE = 3,
}
private enum DISPLAYCONFIG_DEVICE_INFO_TYPE
public enum DISPLAYCONFIG_DEVICE_INFO_TYPE
{
DISPLAYCONFIG_DEVICE_INFO_GET_DPI_SCALE = -3,
DISPLAYCONFIG_DEVICE_INFO_SET_DPI_SCALE = -4,
@@ -950,7 +1029,7 @@ namespace ColorControl.Shared.Native
private const uint DISPLAYCONFIG_DEVICE_INFO_SET_ADVANCED_COLOR_PARAM = 0xFFFFFFF0;
[StructLayout(LayoutKind.Sequential)]
private struct DISPLAYCONFIG_DEVICE_INFO_HEADER
public struct DISPLAYCONFIG_DEVICE_INFO_HEADER
{
public DISPLAYCONFIG_DEVICE_INFO_TYPE type;
public int size;
@@ -1402,7 +1481,7 @@ namespace ColorControl.Shared.Native
};
[StructLayout(LayoutKind.Sequential)]
private struct DISPLAYCONFIG_SOURCE_DPI_SCALE_GET
public struct DISPLAYCONFIG_SOURCE_DPI_SCALE_GET
{
public DISPLAYCONFIG_DEVICE_INFO_HEADER header;
/*
@@ -1423,7 +1502,7 @@ namespace ColorControl.Shared.Native
public int maxScaleRel;
};
private struct DISPLAYCONFIG_SOURCE_DPI_SCALE_SET
public struct DISPLAYCONFIG_SOURCE_DPI_SCALE_SET
{
public DISPLAYCONFIG_DEVICE_INFO_HEADER header;
/*
@@ -1520,6 +1599,12 @@ namespace ColorControl.Shared.Native
[DllImport("user32")]
public static extern int DisplayConfigSetDeviceInfo(ref DISPLAYCONFIG_SET_ADVANCED_COLOR_PARAM setPacket);
[DllImport("user32")]
public static extern int DisplayConfigGetDeviceInfo(ref DISPLAYCONFIG_SOURCE_DPI_SCALE_GET requestPacket);
[DllImport("user32")]
public static extern int DisplayConfigSetDeviceInfo(ref DISPLAYCONFIG_SOURCE_DPI_SCALE_SET setPacket);
[DllImport("user32")]
public static extern uint GetDpiForSystem();
+2 -1
View File
@@ -76,7 +76,8 @@ public class RpcServerService
{
if (arg.GetType().Name == "JObject" || arg.GetType().Name == "JArray")
{
var obj = JsonConvert.DeserializeObject(arg.ToString(), type);
var jsonString = arg.ToString();
var obj = jsonString == "{}" ? Type.Missing : JsonConvert.DeserializeObject(jsonString, type);
list.Add(obj);
return;
}