diff --git a/PowerControl/Helpers/PhysicalMonitorBrightnessController.cs b/PowerControl/Helpers/PhysicalMonitorBrightnessController.cs index d7a81f5..68cc88e 100644 --- a/PowerControl/Helpers/PhysicalMonitorBrightnessController.cs +++ b/PowerControl/Helpers/PhysicalMonitorBrightnessController.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Runtime.InteropServices; @@ -199,28 +200,121 @@ namespace PowerControl.Helpers UpdateMonitors(); } + public struct DisplayResolution + { + public int Width { get; set; } + public int Height { get; set; } + + public DisplayResolution() { Width = 0; Height = 0; } + + public DisplayResolution(int width, int height) { Width = width; Height = height; } + + public static bool operator ==(DisplayResolution sz1, DisplayResolution sz2) => sz1.Width == sz2.Width && sz1.Height == sz2.Height; + + public static bool operator !=(DisplayResolution sz1, DisplayResolution sz2) => !(sz1 == sz2); + + public override readonly bool Equals([NotNullWhen(true)] object? obj) => obj is DisplayResolution && Equals((DisplayResolution)obj); + public readonly bool Equals(DisplayResolution other) => this == other; + + public override readonly int GetHashCode() => HashCode.Combine(Width, Height); + + public override string ToString() + { + return String.Format("{0}x{1}", Width, Height); + } + } + #region Get & Set public void Set(uint brightness) { Set(brightness, true); } - public static int[] GetRefreshRates() + public static DisplayResolution[] GetAllResolutions() + { + HashSet resolutions = new HashSet(); + DEVMODE current = new DEVMODE(); + + if (!EnumDisplaySettings(null, ENUM_CURRENT_SETTINGS, ref current)) + return new DisplayResolution[0]; + + DEVMODE dm = new DEVMODE(); + for (int i = 0; EnumDisplaySettings(null, i, ref dm); i++) + { + if (!dm.dmFields.HasFlag(DM.PelsWidth) || !dm.dmFields.HasFlag(DM.PelsHeight)) + continue; + resolutions.Add(new DisplayResolution(dm.dmPelsWidth, dm.dmPelsHeight)); + } + + return resolutions.ToArray(); + } + + public static DisplayResolution? GetResolution() + { + DEVMODE dm = new DEVMODE(); + + if (!EnumDisplaySettings(null, ENUM_CURRENT_SETTINGS, ref dm)) + return null; + + if (!dm.dmFields.HasFlag(DM.PelsWidth) || !dm.dmFields.HasFlag(DM.PelsHeight)) + return null; + + return new DisplayResolution(dm.dmPelsWidth, dm.dmPelsHeight); + } + + public static bool SetResolution(DisplayResolution size) + { + DEVMODE dm = new DEVMODE(); + + if (!EnumDisplaySettings(null, ENUM_CURRENT_SETTINGS, ref dm)) + return false; + + var refreshRates = GetRefreshRates(size); + if (refreshRates.Count() == 0) + return false; + + dm.dmFields |= DM.PelsWidth | DM.PelsHeight | DM.DisplayFrequency; + dm.dmPelsWidth = size.Width; + dm.dmPelsHeight = size.Height; + dm.dmDisplayFrequency = refreshRates.Last(); + + var dispChange = ChangeDisplaySettingsEx(null, ref dm, IntPtr.Zero, ChangeDisplaySettingsFlags.CDS_NONE, IntPtr.Zero); + + if (!EnumDisplaySettings(null, ENUM_CURRENT_SETTINGS, ref dm)) + return false; + + Trace.WriteLine("DispChange: " + dispChange.ToString() + " Size:" + size.ToString() + + " SetSize:" + new DisplayResolution(dm.dmPelsWidth, dm.dmPelsHeight).ToString()); + + if (dispChange == DISP_CHANGE.Successful) + return true; + + return true; + } + + public static int[] GetRefreshRates(DisplayResolution? size = null) { List refreshRates = new List(); DEVMODE current = new DEVMODE(); + if (size is null) + size = GetResolution(); + if (size is null) + return new int[0]; + if (!EnumDisplaySettings(null, ENUM_CURRENT_SETTINGS, ref current)) return new int[0]; DEVMODE dm = new DEVMODE(); for (int i = 0; EnumDisplaySettings(null, i, ref dm); i++) { - if (dm.dmPelsWidth != current.dmPelsWidth || dm.dmPelsHeight != current.dmPelsHeight || dm.dmBitsPerPel != current.dmBitsPerPel) + if (dm.dmPelsWidth != size?.Width || dm.dmPelsHeight != size?.Height || dm.dmBitsPerPel != current.dmBitsPerPel) continue; refreshRates.Add(dm.dmDisplayFrequency); } + refreshRates.Sort(); + return refreshRates.ToArray(); } @@ -238,6 +332,10 @@ namespace PowerControl.Helpers { DEVMODE dm = new DEVMODE(); + var allowedRefreshRates = GetRefreshRates(); + if (!allowedRefreshRates.Contains(hz)) + return false; + if (!EnumDisplaySettings(null, ENUM_CURRENT_SETTINGS, ref dm)) return false; diff --git a/PowerControl/Menu.cs b/PowerControl/Menu.cs index 4e2ea48..8b73871 100644 --- a/PowerControl/Menu.cs +++ b/PowerControl/Menu.cs @@ -141,6 +141,10 @@ namespace PowerControl Options = result.ToList(); updateOptions(); } + else + { + Visible = false; + } } if (ActiveOption == null) diff --git a/PowerControl/MenuStack.cs b/PowerControl/MenuStack.cs index 1ded66d..a13ab76 100644 --- a/PowerControl/MenuStack.cs +++ b/PowerControl/MenuStack.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Navigation; +using static PowerControl.Helpers.PhysicalMonitorBrightnessController; namespace PowerControl { @@ -50,6 +51,29 @@ namespace PowerControl } }, new Menu.MenuItemWithOptions() + { + Name = "Resolution", + ApplyDelay = 1000, + OptionsValues = delegate() + { + var resolutions = Helpers.PhysicalMonitorBrightnessController.GetAllResolutions(); + if (resolutions.Count() > 1) + return resolutions.Select(item => (object)item).ToArray(); + return null; + }, + CurrentValue = delegate() + { + return Helpers.PhysicalMonitorBrightnessController.GetResolution(); + }, + ApplyValue = delegate(object selected) + { + Helpers.PhysicalMonitorBrightnessController.SetResolution((DisplayResolution)selected); + Root["Refresh Rate"].Update(); // force refresh Refresh Rate + Root["FPS Limit"].Update(); // force refresh FPS limit + return Helpers.PhysicalMonitorBrightnessController.GetResolution(); + } + }, + new Menu.MenuItemWithOptions() { Name = "Refresh Rate", ApplyDelay = 1000,