From 6e5d4a736f01fd79ef84c43dec25287c2c67b287 Mon Sep 17 00:00:00 2001 From: emoacht Date: Tue, 21 Dec 2021 08:05:21 +0900 Subject: [PATCH 1/6] Add precleared property and capability --- .../Models/Monitor/DdcMonitorItem.cs | 1 + .../Models/Monitor/MonitorConfiguration.cs | 38 +++++++++++++++++-- .../Models/Monitor/MonitorItem.cs | 2 + 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/Source/Monitorian.Core/Models/Monitor/DdcMonitorItem.cs b/Source/Monitorian.Core/Models/Monitor/DdcMonitorItem.cs index 0ef38c1f..1f0f758c 100644 --- a/Source/Monitorian.Core/Models/Monitor/DdcMonitorItem.cs +++ b/Source/Monitorian.Core/Models/Monitor/DdcMonitorItem.cs @@ -18,6 +18,7 @@ internal class DdcMonitorItem : MonitorItem public override bool IsBrightnessSupported => _capability.IsBrightnessSupported; public override bool IsContrastSupported => _capability.IsContrastSupported; + public override bool IsPrecleared => _capability.IsPrecleared; public DdcMonitorItem( string deviceInstanceId, diff --git a/Source/Monitorian.Core/Models/Monitor/MonitorConfiguration.cs b/Source/Monitorian.Core/Models/Monitor/MonitorConfiguration.cs index e88c3873..1fab4cdb 100644 --- a/Source/Monitorian.Core/Models/Monitor/MonitorConfiguration.cs +++ b/Source/Monitorian.Core/Models/Monitor/MonitorConfiguration.cs @@ -8,8 +8,6 @@ using System.Text; using System.Threading.Tasks; -using Monitorian.Core.Helper; - namespace Monitorian.Core.Models.Monitor { /// @@ -559,12 +557,15 @@ internal class MonitorCapability public bool IsContrastSupported { get; } [DataMember(Order = 3)] - public string CapabilitiesString { get; } + public bool IsPrecleared { get; } [DataMember(Order = 4)] - public string CapabilitiesReport { get; } + public string CapabilitiesString { get; } [DataMember(Order = 5)] + public string CapabilitiesReport { get; } + + [DataMember(Order = 6)] public string CapabilitiesData { get; } public MonitorCapability( @@ -582,5 +583,34 @@ public MonitorCapability( this.CapabilitiesReport = capabilitiesReport; this.CapabilitiesData = (capabilitiesData is not null) ? Convert.ToBase64String(capabilitiesData) : null; } + + private MonitorCapability( + bool isHighLevelBrightnessSupported, + bool isLowLevelBrightnessSupported, + bool isContrastSupported, + bool isPrecleared, + string capabilitiesString, + string capabilitiesReport, + byte[] capabilitiesData) : this( + isHighLevelBrightnessSupported: isHighLevelBrightnessSupported, + isLowLevelBrightnessSupported: isLowLevelBrightnessSupported, + isContrastSupported: isContrastSupported, + capabilitiesString: capabilitiesString, + capabilitiesReport: capabilitiesReport, + capabilitiesData: capabilitiesData) + { + this.IsPrecleared = isPrecleared; + } + + public static MonitorCapability PreclearedCapability => _preclearedCapability.Value; + private static readonly Lazy _preclearedCapability = new(() => + new MonitorCapability( + isHighLevelBrightnessSupported: false, + isLowLevelBrightnessSupported: true, + isContrastSupported: true, + isPrecleared: true, + capabilitiesString: null, + capabilitiesReport: null, + capabilitiesData: null)); } } \ No newline at end of file diff --git a/Source/Monitorian.Core/Models/Monitor/MonitorItem.cs b/Source/Monitorian.Core/Models/Monitor/MonitorItem.cs index 11000b03..9285c15f 100644 --- a/Source/Monitorian.Core/Models/Monitor/MonitorItem.cs +++ b/Source/Monitorian.Core/Models/Monitor/MonitorItem.cs @@ -20,6 +20,7 @@ internal abstract class MonitorItem : IMonitor, IDisposable public virtual bool IsBrightnessSupported => IsReachable; public virtual bool IsContrastSupported => false; + public virtual bool IsPrecleared => false; public MonitorItem( string deviceInstanceId, @@ -65,6 +66,7 @@ public override string ToString() (nameof(IsReachable), IsReachable), (nameof(IsBrightnessSupported), IsBrightnessSupported), (nameof(IsContrastSupported), IsContrastSupported), + (nameof(IsPrecleared), IsPrecleared), (nameof(Brightness), Brightness), (nameof(BrightnessSystemAdjusted), BrightnessSystemAdjusted), (nameof(Contrast), Contrast)); From 1f0d50a8fb9ad3c6bf2664c70db13924078cc0b1 Mon Sep 17 00:00:00 2001 From: emoacht Date: Tue, 21 Dec 2021 08:05:49 +0900 Subject: [PATCH 2/6] Add preclear option --- Source/Monitorian.Core/AppKeeper.cs | 2 + .../Models/Monitor/MonitorManager.cs | 48 ++++++++++++++++--- 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/Source/Monitorian.Core/AppKeeper.cs b/Source/Monitorian.Core/AppKeeper.cs index 7e12cea7..c84f0822 100644 --- a/Source/Monitorian.Core/AppKeeper.cs +++ b/Source/Monitorian.Core/AppKeeper.cs @@ -7,6 +7,7 @@ using System.Windows.Threading; using Monitorian.Core.Models; +using Monitorian.Core.Models.Monitor; using Monitorian.Core.Views; using StartupAgency; @@ -70,6 +71,7 @@ public static string[] GetDefinedOptions() => new[] { StartupAgent.Options, + MonitorManager.Options, LanguageService.Options, WindowPainter.Options } diff --git a/Source/Monitorian.Core/Models/Monitor/MonitorManager.cs b/Source/Monitorian.Core/Models/Monitor/MonitorManager.cs index 659a1b26..94f927c2 100644 --- a/Source/Monitorian.Core/Models/Monitor/MonitorManager.cs +++ b/Source/Monitorian.Core/Models/Monitor/MonitorManager.cs @@ -42,6 +42,24 @@ public DeviceItemPlus( #endregion + #region Preclearance + + public static IReadOnlyCollection Options => new[] { Option }; + private const string Option = "/preclear"; + + private static readonly Lazy> _preclearedIds = new(() => + { + var buffer = AppKeeper.DefinedArguments + .SkipWhile(x => !string.Equals(x, Option, StringComparison.OrdinalIgnoreCase)) + .Skip(1) // 1 means option. + .TakeWhile(x => x.StartsWith("DISPLAY")) + .Select(x => x.Replace(@"\\", @"\")); // Backslash will be escaped in JSON. + + return new HashSet(buffer); + }); + + #endregion + public static async Task> EnumerateMonitorsAsync() { var deviceItems = await GetMonitorDevicesAsync(); @@ -49,7 +67,7 @@ public static async Task> EnumerateMonitorsAsync() return EnumerateMonitors(deviceItems); } - private static HashSet _ids; + private static HashSet _foundIds; private static async Task> GetMonitorDevicesAsync() { @@ -58,7 +76,7 @@ private static async Task> GetMonitorDevicesAsync() : DisplayConfig.EnumerateDisplayConfigs().ToArray(); var deviceItems = DeviceContext.EnumerateMonitorDevices().ToArray(); - _ids = new HashSet(deviceItems.Select(x => x.DeviceInstanceId)); + _foundIds = new HashSet(deviceItems.Select(x => x.DeviceInstanceId)); IEnumerable Enumerate() { @@ -101,9 +119,11 @@ private static IEnumerable EnumerateMonitors(List devi foreach (var physicalItem in MonitorConfiguration.EnumeratePhysicalMonitors(handleItem.MonitorHandle)) { int index = -1; - if (physicalItem.Capability.IsBrightnessSupported) + if (physicalItem.Capability.IsBrightnessSupported || + _preclearedIds.Value.Any()) { index = deviceItems.FindIndex(x => + !x.IsInternal && (x.DisplayIndex == handleItem.DisplayIndex) && (x.MonitorIndex == physicalItem.MonitorIndex) && string.Equals(x.Description, physicalItem.Description, StringComparison.OrdinalIgnoreCase)); @@ -115,6 +135,22 @@ private static IEnumerable EnumerateMonitors(List devi } var deviceItem = deviceItems[index]; + + MonitorCapability capability = null; + if (physicalItem.Capability.IsBrightnessSupported) + { + capability = physicalItem.Capability; + } + else if (_preclearedIds.Value.Contains(deviceItem.DeviceInstanceId)) + { + capability = MonitorCapability.PreclearedCapability; + } + else + { + physicalItem.Handle.Dispose(); + continue; + } + yield return new DdcMonitorItem( deviceInstanceId: deviceItem.DeviceInstanceId, description: deviceItem.AlternateDescription, @@ -122,7 +158,7 @@ private static IEnumerable EnumerateMonitors(List devi monitorIndex: deviceItem.MonitorIndex, monitorRect: handleItem.MonitorRect, handle: physicalItem.Handle, - capability: physicalItem.Capability); + capability: capability); deviceItems.RemoveAt(index); if (deviceItems.Count == 0) @@ -175,8 +211,8 @@ private static IEnumerable EnumerateMonitors(List devi public static bool CheckMonitorsChanged() { var newIds = new HashSet(DeviceContext.EnumerateMonitorDevices().Select(x => x.DeviceInstanceId)); - var oldIds = _ids; - _ids = newIds; + var oldIds = _foundIds; + _foundIds = newIds; return (oldIds?.SetEquals(newIds) is not true); } From 7fe6085ab9d229b69615dc62c82d870276b586f1 Mon Sep 17 00:00:00 2001 From: emoacht Date: Wed, 22 Dec 2021 16:13:40 +0900 Subject: [PATCH 3/6] Increment build number --- Source/Installer/Product.wxs | 2 +- Source/Monitorian.Core/Properties/AssemblyInfo.cs | 4 ++-- Source/Monitorian/Properties/AssemblyInfo.cs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Source/Installer/Product.wxs b/Source/Installer/Product.wxs index 65225900..49efa1b0 100644 --- a/Source/Installer/Product.wxs +++ b/Source/Installer/Product.wxs @@ -1,6 +1,6 @@  - Date: Thu, 23 Dec 2021 16:25:14 +0900 Subject: [PATCH 4/6] Extend method to load from AppData folder --- .../Monitorian.Core/Models/AppDataService.cs | 37 ++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/Source/Monitorian.Core/Models/AppDataService.cs b/Source/Monitorian.Core/Models/AppDataService.cs index d49eff09..da66ff68 100644 --- a/Source/Monitorian.Core/Models/AppDataService.cs +++ b/Source/Monitorian.Core/Models/AppDataService.cs @@ -79,7 +79,34 @@ public static void Rename(string oldFileName, string newFileName) #region Load/Save + /// + /// Loads saved instance from a specified file and copies its properties to current instance. + /// + /// Type of instance + /// Current instance + /// File name of saved instance + /// Known types of members of instance + /// + /// Only values of public and instance properties will be copied. + /// An indexer will be ignored. + /// public static void Load(T instance, string fileName, IEnumerable knownTypes = null) where T : class + { + Load(instance, fileName, BindingFlags.Public | BindingFlags.Instance, knownTypes); + } + + /// + /// Loads saved instance from a specified file and copies its properties to current instance. + /// + /// Type of instance + /// Current instance + /// File name of saved instance + /// Flags to search properties to be copied + /// Known types of members of instance + /// + /// An indexer will be ignored. + /// + public static void Load(T instance, string fileName, BindingFlags flags, IEnumerable knownTypes = null) where T : class { var filePath = Path.Combine(FolderPath, fileName); var fileInfo = new FileInfo(filePath); @@ -95,8 +122,9 @@ public static void Load(T instance, string fileName, IEnumerable knownT var serializer = new DataContractSerializer(type, knownTypes); var loaded = (T)serializer.ReadObject(xr); - type.GetProperties(BindingFlags.Public | BindingFlags.Instance) + type.GetProperties(flags) .Where(x => x.CanWrite) + .Where(x => x.GetIndexParameters().Length == 0) // Exclude indexer to prevent TargetParameterCountException. .ToList() .ForEach(x => x.SetValue(instance, x.GetValue(loaded))); } @@ -110,6 +138,13 @@ public static void Load(T instance, string fileName, IEnumerable knownT } } + /// + /// Saves current instance to a specified file. + /// + /// Type of instance + /// Current instance + /// File name of saved instance + /// Known types of members of instance public static void Save(T instance, string fileName, IEnumerable knownTypes = null) where T : class { AssureFolder(); From 221392b96a717d24b3d1435b041e7068c4ba029d Mon Sep 17 00:00:00 2001 From: emoacht Date: Thu, 23 Dec 2021 20:44:47 +0900 Subject: [PATCH 5/6] Refactor --- Source/Monitorian.Core/AppControllerCore.cs | 2 +- Source/Monitorian.Core/AppKeeper.cs | 2 +- Source/Monitorian.Core/Models/Monitor/MonitorManager.cs | 2 +- .../Models/Watcher/SystemEventsComplement.cs | 4 ++-- Source/Monitorian.Core/ViewModels/MonitorViewModel.cs | 2 +- .../Views/Controls/Sliders/EnhancedSlider.cs | 2 +- .../Views/Converters/StringToVisibilityConverter.cs | 2 +- Source/Monitorian.Core/Views/WindowPainter.cs | 2 +- Source/Monitorian.Supplement/DisplayInformation.cs | 2 +- Source/ScreenFrame/Helper/DpiScaleExtension.cs | 6 ++---- Source/StartupAgency/PipeHolder.cs | 2 +- 11 files changed, 13 insertions(+), 15 deletions(-) diff --git a/Source/Monitorian.Core/AppControllerCore.cs b/Source/Monitorian.Core/AppControllerCore.cs index 60a14f77..9cf11c92 100644 --- a/Source/Monitorian.Core/AppControllerCore.cs +++ b/Source/Monitorian.Core/AppControllerCore.cs @@ -430,7 +430,7 @@ protected internal virtual void SaveCustomization(string deviceInstanceId, strin protected virtual void EnsureUnisonWorkable(MonitorViewModel monitor) { - if (_isUnisonWorkable || (monitor?.IsUnison is not true)) + if (_isUnisonWorkable || (monitor is not { IsUnison: true })) return; _current.Dispatcher.Invoke(() => diff --git a/Source/Monitorian.Core/AppKeeper.cs b/Source/Monitorian.Core/AppKeeper.cs index c84f0822..40b874ce 100644 --- a/Source/Monitorian.Core/AppKeeper.cs +++ b/Source/Monitorian.Core/AppKeeper.cs @@ -87,7 +87,7 @@ private async Task ParseArgumentsAsync(StartupEventArgs e, string[] definedOptio // The first element of StartupEventArgs.Args is not executing assembly's path unlike // that of arguments provided by Environment.GetCommandLineArgs method. args = e.Args.Concat(args).ToArray(); - if (args.Any() is not true) + if (args is not { Length: > 0 }) return; const char optionMark = '/'; diff --git a/Source/Monitorian.Core/Models/Monitor/MonitorManager.cs b/Source/Monitorian.Core/Models/Monitor/MonitorManager.cs index 94f927c2..acccc791 100644 --- a/Source/Monitorian.Core/Models/Monitor/MonitorManager.cs +++ b/Source/Monitorian.Core/Models/Monitor/MonitorManager.cs @@ -108,7 +108,7 @@ IEnumerable Enumerate() private static IEnumerable EnumerateMonitors(List deviceItems) { - if (deviceItems?.Any() is not true) + if (deviceItems is not { Count: > 0 }) yield break; var handleItems = DeviceContext.GetMonitorHandles(); diff --git a/Source/Monitorian.Core/Models/Watcher/SystemEventsComplement.cs b/Source/Monitorian.Core/Models/Watcher/SystemEventsComplement.cs index 2dcc5c5e..46200e14 100644 --- a/Source/Monitorian.Core/Models/Watcher/SystemEventsComplement.cs +++ b/Source/Monitorian.Core/Models/Watcher/SystemEventsComplement.cs @@ -76,7 +76,7 @@ protected override void WndProc(ref Message m) public void RegisterPowerSettingEvent(IReadOnlyCollection settingGuids) { - if (settingGuids?.Any() is not true) + if (settingGuids is not { Count: > 0 }) return; if (!TryGetSystemEventsWindowHandle(out IntPtr windowHandle)) @@ -135,7 +135,7 @@ public void UnregisterPowerSettingEvent() { PowerSettingChanged = null; - if (_registrationHandles?.Any() is true) + if (_registrationHandles is { Count: > 0 }) { foreach (var handle in _registrationHandles) UnregisterPowerSettingNotification(handle); diff --git a/Source/Monitorian.Core/ViewModels/MonitorViewModel.cs b/Source/Monitorian.Core/ViewModels/MonitorViewModel.cs index c016eeea..74d65a1b 100644 --- a/Source/Monitorian.Core/ViewModels/MonitorViewModel.cs +++ b/Source/Monitorian.Core/ViewModels/MonitorViewModel.cs @@ -31,7 +31,7 @@ public MonitorViewModel(AppControllerCore controller, IMonitor monitor) internal void Replace(IMonitor monitor) { - if (monitor?.IsReachable is true) + if (monitor is { IsReachable: true }) { lock (_lock) { diff --git a/Source/Monitorian.Core/Views/Controls/Sliders/EnhancedSlider.cs b/Source/Monitorian.Core/Views/Controls/Sliders/EnhancedSlider.cs index 92d995c8..3d4e60b1 100644 --- a/Source/Monitorian.Core/Views/Controls/Sliders/EnhancedSlider.cs +++ b/Source/Monitorian.Core/Views/Controls/Sliders/EnhancedSlider.cs @@ -55,7 +55,7 @@ protected virtual bool UpdateValue(double value) #region Drag protected bool CanDrag { get; private set; } - protected bool IsDragging => (_thumb?.IsDragging is true); + protected bool IsDragging => (_thumb is { IsDragging: true }); private void CheckCanDrag() { diff --git a/Source/Monitorian.Core/Views/Converters/StringToVisibilityConverter.cs b/Source/Monitorian.Core/Views/Converters/StringToVisibilityConverter.cs index 08e91bba..680c7e81 100644 --- a/Source/Monitorian.Core/Views/Converters/StringToVisibilityConverter.cs +++ b/Source/Monitorian.Core/Views/Converters/StringToVisibilityConverter.cs @@ -21,7 +21,7 @@ public object Convert(object value, Type targetType, object parameter, CultureIn public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { - throw new NotImplementedException(); + throw new NotSupportedException(); } } } \ No newline at end of file diff --git a/Source/Monitorian.Core/Views/WindowPainter.cs b/Source/Monitorian.Core/Views/WindowPainter.cs index 4f352f23..3aa30031 100644 --- a/Source/Monitorian.Core/Views/WindowPainter.cs +++ b/Source/Monitorian.Core/Views/WindowPainter.cs @@ -87,7 +87,7 @@ protected override void PaintBackground(Window window) private bool ChangeColors(Window window) { - if (_colors?.Any() is not true) + if (_colors is not { Count: > 0 }) return false; var isBackgroundChanged = false; diff --git a/Source/Monitorian.Supplement/DisplayInformation.cs b/Source/Monitorian.Supplement/DisplayInformation.cs index edd42373..cfaf3c30 100644 --- a/Source/Monitorian.Supplement/DisplayInformation.cs +++ b/Source/Monitorian.Supplement/DisplayInformation.cs @@ -90,7 +90,7 @@ public static async Task GetDisplayMonitorsAsync() try { var devices = await DeviceInformation.FindAllAsync(DisplayMonitor.GetDeviceSelector(), new[] { deviceInstanceIdKey }); - if (devices?.Any() is true) + if (devices is { Count: > 0 }) { var items = new List(devices.Count); foreach (var device in devices) diff --git a/Source/ScreenFrame/Helper/DpiScaleExtension.cs b/Source/ScreenFrame/Helper/DpiScaleExtension.cs index 80237447..155258ea 100644 --- a/Source/ScreenFrame/Helper/DpiScaleExtension.cs +++ b/Source/ScreenFrame/Helper/DpiScaleExtension.cs @@ -13,11 +13,9 @@ namespace ScreenFrame.Helper /// internal static class DpiScaleExtension { - public static bool IsDefault(this DpiScale a) => - (1D == a.DpiScaleX) && (1D == a.DpiScaleY); + public static bool IsDefault(this DpiScale a) => a is { DpiScaleX: 1D, DpiScaleY: 1D }; - public static bool IsValid(this DpiScale a) => - (0 < a.DpiScaleX) && (0 < a.DpiScaleY); + public static bool IsValid(this DpiScale a) => a is { DpiScaleX: > 0, DpiScaleY: > 0 }; public static Matrix ToMatrix(this DpiScale a) { diff --git a/Source/StartupAgency/PipeHolder.cs b/Source/StartupAgency/PipeHolder.cs index ebe5ec8c..9f8aea6f 100644 --- a/Source/StartupAgency/PipeHolder.cs +++ b/Source/StartupAgency/PipeHolder.cs @@ -180,7 +180,7 @@ private async Task ConnectServerAsync(string[] args, TimeSpan timeout, C using (var writer = new StreamWriter(client, Encoding.UTF8, 1024, leaveOpen: true) { AutoFlush = true }) { - if (args?.Any() is true) + if (args is { Length: > 0 }) { // Filter out null bacause it causes NullReferenceException in WriteLineAsync method // on .NET Framework. From c528f2798d53f830c6fa85eb340af07a6fdb992f Mon Sep 17 00:00:00 2001 From: emoacht Date: Thu, 23 Dec 2021 21:28:44 +0900 Subject: [PATCH 6/6] Increment build number --- Source/Installer/Product.wxs | 2 +- Source/Monitorian.Core/Properties/AssemblyInfo.cs | 4 ++-- Source/Monitorian.Supplement/Properties/AssemblyInfo.cs | 4 ++-- Source/Monitorian/Properties/AssemblyInfo.cs | 4 ++-- Source/ScreenFrame/Properties/AssemblyInfo.cs | 4 ++-- Source/StartupAgency/Properties/AssemblyInfo.cs | 4 ++-- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Source/Installer/Product.wxs b/Source/Installer/Product.wxs index 49efa1b0..c99b9a9f 100644 --- a/Source/Installer/Product.wxs +++ b/Source/Installer/Product.wxs @@ -1,6 +1,6 @@  -