mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-16 03:37:59 +01:00
Refactor color temp init to be synchronous in DDC/CI
Simplifies color temperature initialization by moving it from async handling in MainViewModel to synchronous initialization during monitor enumeration in DdcCiController. Removes related async methods and UI update logic, reducing complexity and ensuring color temperature values are available immediately after enumeration.
This commit is contained in:
@@ -576,6 +576,12 @@ namespace PowerDisplay.Common.Drivers.DDC
|
|||||||
{
|
{
|
||||||
InitializeInputSource(monitor, candidate.Handle);
|
InitializeInputSource(monitor, candidate.Handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize color temperature if supported
|
||||||
|
if (monitor.SupportsColorTemperature)
|
||||||
|
{
|
||||||
|
InitializeColorTemperature(monitor, candidate.Handle);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
monitors.Add(monitor);
|
monitors.Add(monitor);
|
||||||
@@ -600,6 +606,18 @@ namespace PowerDisplay.Common.Drivers.DDC
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialize color temperature value for a monitor using VCP 0x14.
|
||||||
|
/// </summary>
|
||||||
|
private static void InitializeColorTemperature(Monitor monitor, IntPtr handle)
|
||||||
|
{
|
||||||
|
if (DdcCiNative.TryGetVCPFeature(handle, VcpCodeSelectColorPreset, out uint current, out uint _))
|
||||||
|
{
|
||||||
|
monitor.CurrentColorTemperature = (int)current;
|
||||||
|
Logger.LogDebug($"[{monitor.Id}] Color temperature: {VcpValueNames.GetFormattedName(VcpCodeSelectColorPreset, (int)current)}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Update monitor capability flags based on parsed VCP capabilities.
|
/// Update monitor capability flags based on parsed VCP capabilities.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -344,56 +344,6 @@ namespace PowerDisplay.Helpers
|
|||||||
return Task.FromResult(result);
|
return Task.FromResult(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initialize input source for a monitor (async operation)
|
|
||||||
/// </summary>
|
|
||||||
public async Task InitializeInputSourceAsync(string monitorId, CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var sourceInfo = await GetInputSourceAsync(monitorId, cancellationToken);
|
|
||||||
if (sourceInfo.IsValid)
|
|
||||||
{
|
|
||||||
var monitor = GetMonitor(monitorId);
|
|
||||||
if (monitor != null)
|
|
||||||
{
|
|
||||||
// Store raw VCP 0x60 value (e.g., 0x11 for HDMI-1)
|
|
||||||
monitor.CurrentInputSource = sourceInfo.Current;
|
|
||||||
Logger.LogInfo($"[{monitorId}] Input source initialized: {monitor.InputSourceName}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logger.LogWarning($"Failed to initialize input source for {monitorId}: {ex.Message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initialize color temperature for a monitor (async operation)
|
|
||||||
/// </summary>
|
|
||||||
public async Task InitializeColorTemperatureAsync(string monitorId, CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var tempInfo = await GetColorTemperatureAsync(monitorId, cancellationToken);
|
|
||||||
if (tempInfo.IsValid)
|
|
||||||
{
|
|
||||||
var monitor = GetMonitor(monitorId);
|
|
||||||
if (monitor != null)
|
|
||||||
{
|
|
||||||
// Store raw VCP 0x14 preset value (e.g., 0x05 for 6500K)
|
|
||||||
// No Kelvin conversion - we use discrete presets
|
|
||||||
monitor.CurrentColorTemperature = tempInfo.Current;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logger.LogWarning($"Failed to initialize color temperature for {monitorId}: {ex.Message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get monitor by ID. Uses dictionary lookup for O(1) performance.
|
/// Get monitor by ID. Uses dictionary lookup for O(1) performance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -95,7 +95,6 @@ public partial class MainViewModel
|
|||||||
var settings = _settingsUtils.GetSettingsOrDefault<PowerDisplaySettings>(PowerDisplaySettings.ModuleName);
|
var settings = _settingsUtils.GetSettingsOrDefault<PowerDisplaySettings>(PowerDisplaySettings.ModuleName);
|
||||||
var hiddenMonitorIds = GetHiddenMonitorIds(settings);
|
var hiddenMonitorIds = GetHiddenMonitorIds(settings);
|
||||||
|
|
||||||
var colorTempTasks = new List<Task>();
|
|
||||||
foreach (var monitor in monitors)
|
foreach (var monitor in monitors)
|
||||||
{
|
{
|
||||||
// Skip monitors that are marked as hidden in settings
|
// Skip monitors that are marked as hidden in settings
|
||||||
@@ -107,69 +106,14 @@ public partial class MainViewModel
|
|||||||
|
|
||||||
var vm = new MonitorViewModel(monitor, _monitorManager, this);
|
var vm = new MonitorViewModel(monitor, _monitorManager, this);
|
||||||
Monitors.Add(vm);
|
Monitors.Add(vm);
|
||||||
|
|
||||||
// Asynchronously initialize color temperature for DDC/CI monitors
|
|
||||||
if (monitor.SupportsColorTemperature && monitor.CommunicationMethod == "DDC/CI")
|
|
||||||
{
|
|
||||||
var task = InitializeColorTemperatureSafeAsync(monitor.Id, vm);
|
|
||||||
colorTempTasks.Add(task);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OnPropertyChanged(nameof(HasMonitors));
|
OnPropertyChanged(nameof(HasMonitors));
|
||||||
OnPropertyChanged(nameof(ShowNoMonitorsMessage));
|
OnPropertyChanged(nameof(ShowNoMonitorsMessage));
|
||||||
|
|
||||||
// Wait for color temperature initialization to complete before saving
|
// Save monitor information to settings and reload
|
||||||
// This ensures we save the actual scanned values instead of defaults
|
SaveMonitorsToSettings();
|
||||||
if (colorTempTasks.Count > 0)
|
_ = ReloadMonitorSettingsAsync(null);
|
||||||
{
|
|
||||||
// Use fire-and-forget async method to avoid blocking UI thread
|
|
||||||
_ = WaitForColorTempAndSaveAsync(colorTempTasks);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// No color temperature tasks, save immediately
|
|
||||||
SaveMonitorsToSettings();
|
|
||||||
|
|
||||||
// Restore saved settings if enabled (async, don't block)
|
|
||||||
_ = ReloadMonitorSettingsAsync(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task WaitForColorTempAndSaveAsync(IReadOnlyList<Task> colorTempTasks)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Wait for all color temperature initialization tasks to complete
|
|
||||||
await Task.WhenAll(colorTempTasks);
|
|
||||||
|
|
||||||
// Save monitor information to settings.json and reload settings
|
|
||||||
// Must be done on UI thread since these methods access UI properties and observable collections
|
|
||||||
_dispatcherQueue.TryEnqueue(async () =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
SaveMonitorsToSettings();
|
|
||||||
|
|
||||||
// Restore saved settings if enabled (async)
|
|
||||||
await ReloadMonitorSettingsAsync(null); // Tasks already completed, pass null
|
|
||||||
}
|
|
||||||
catch (Exception innerEx)
|
|
||||||
{
|
|
||||||
Logger.LogError($"[WaitForColorTempAndSaveAsync] Error in UI thread operation: {innerEx.Message}");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logger.LogWarning($"[WaitForColorTempAndSaveAsync] Color temperature initialization failed: {ex.Message}");
|
|
||||||
|
|
||||||
// Save anyway with whatever values we have
|
|
||||||
_dispatcherQueue.TryEnqueue(() =>
|
|
||||||
{
|
|
||||||
SaveMonitorsToSettings();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task SetAllBrightnessAsync(int brightness)
|
public async Task SetAllBrightnessAsync(int brightness)
|
||||||
@@ -192,35 +136,4 @@ public partial class MainViewModel
|
|||||||
settings.Properties.Monitors
|
settings.Properties.Monitors
|
||||||
.Where(m => m.IsHidden)
|
.Where(m => m.IsHidden)
|
||||||
.Select(m => m.InternalName));
|
.Select(m => m.InternalName));
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Safe wrapper for initializing color temperature asynchronously
|
|
||||||
/// </summary>
|
|
||||||
private async Task InitializeColorTemperatureSafeAsync(string monitorId, MonitorViewModel vm)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Read current color temperature from hardware
|
|
||||||
await _monitorManager.InitializeColorTemperatureAsync(monitorId);
|
|
||||||
|
|
||||||
// Get the monitor and use the hardware value as-is
|
|
||||||
var monitor = _monitorManager.GetMonitor(monitorId);
|
|
||||||
if (monitor != null)
|
|
||||||
{
|
|
||||||
Logger.LogInfo($"[{monitorId}] Read color temperature from hardware: {monitor.CurrentColorTemperature}");
|
|
||||||
|
|
||||||
_dispatcherQueue.TryEnqueue(() =>
|
|
||||||
{
|
|
||||||
// Update color temperature without triggering hardware write
|
|
||||||
// Use the hardware value directly, even if not in the preset list
|
|
||||||
// This will also update monitor_state.json via MonitorStateManager
|
|
||||||
vm.UpdatePropertySilently(nameof(vm.ColorTemperature), monitor.CurrentColorTemperature);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logger.LogWarning($"Failed to initialize color temperature for {monitorId}: {ex.Message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user