using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using WindowsDisplayAPI.Native; using WindowsDisplayAPI.Native.DisplayConfig; using WindowsDisplayAPI.Native.DisplayConfig.Structures; using WindowsDisplayAPI.Native.Structures; namespace WindowsDisplayAPI.DisplayConfig { /// /// Represents a display path source /// public class PathDisplaySource : IEquatable { private static readonly DisplayConfigSourceDPIScale[] DPIScales = Enum .GetValues(typeof(DisplayConfigSourceDPIScale)) .Cast() .OrderBy(scaling => (uint) scaling) .ToArray(); /// /// Creates a new PathDisplaySource /// /// Display adapter /// Display source identification public PathDisplaySource(PathDisplayAdapter adapter, uint sourceId) { Adapter = adapter; SourceId = sourceId; } /// /// Gets the path display adapter /// public PathDisplayAdapter Adapter { get; } /// /// Gets and sets the current source DPI scaling /// public DisplayConfigSourceDPIScale CurrentDPIScale { get { var dpiScale = new DisplayConfigGetSourceDPIScale(Adapter.AdapterId, SourceId); var result = DisplayConfigApi.DisplayConfigGetDeviceInfo(ref dpiScale); if (result != Win32Status.Success) { throw new Win32Exception((int) result); } var currentScaleIndex = Math.Abs(dpiScale.MinimumScaleSteps) + dpiScale.CurrentScaleSteps; return DPIScales[currentScaleIndex]; } set { var currentScaleStep = Array.IndexOf(DPIScales, value) - Array.IndexOf(DPIScales, RecommendedDPIScale); var dpiScale = new DisplayConfigSetSourceDPIScale(Adapter.AdapterId, SourceId, currentScaleStep); var result = DisplayConfigApi.DisplayConfigSetDeviceInfo(ref dpiScale); if (result != Win32Status.Success) { throw new Win32Exception((int) result); } } } /// /// Returns the corresponding instance. /// public DisplayScreen ToScreen() { return DisplayScreen.GetScreens().FirstOrDefault(info => info.ScreenName.Equals(DisplayName)); } /// /// Gets the display name /// /// Error code can be retrieved from Win32Exception.NativeErrorCode property public string DisplayName { get { var sourceName = new DisplayConfigSourceDeviceName(Adapter.AdapterId, SourceId); var result = DisplayConfigApi.DisplayConfigGetDeviceInfo(ref sourceName); if (result == Win32Status.Success) { return sourceName.DeviceName; } throw new Win32Exception((int) result); } } /// /// Gets the maximum DPI scaling for this source /// public DisplayConfigSourceDPIScale MaximumDPIScale { get { var dpiScale = new DisplayConfigGetSourceDPIScale(Adapter.AdapterId, SourceId); var result = DisplayConfigApi.DisplayConfigGetDeviceInfo(ref dpiScale); if (result != Win32Status.Success) { throw new Win32Exception((int) result); } var currentScaleIndex = Math.Abs(dpiScale.MinimumScaleSteps) + dpiScale.MaximumScaleSteps; return DPIScales[currentScaleIndex]; } } /// /// Gets the recommended DPI scaling for this source /// public DisplayConfigSourceDPIScale RecommendedDPIScale { get { var dpiScale = new DisplayConfigGetSourceDPIScale(Adapter.AdapterId, SourceId); var result = DisplayConfigApi.DisplayConfigGetDeviceInfo(ref dpiScale); if (result != Win32Status.Success) { throw new Win32Exception((int) result); } return DPIScales[Math.Abs(dpiScale.MinimumScaleSteps)]; } } /// /// Gets the zero based display identification /// public uint SourceId { get; } /// public bool Equals(PathDisplaySource other) { if (ReferenceEquals(null, other)) { return false; } if (ReferenceEquals(this, other)) { return true; } return Adapter == other.Adapter && SourceId == other.SourceId; } /// /// Retrieving a list of all display sources from the currently active and inactive paths /// /// An array of PathDisplaySource instances public static PathDisplaySource[] GetDisplaySources() { var sources = new Dictionary, PathDisplaySource>(); foreach (var pathInfo in PathInfo.GetAllPaths()) { var key = Tuple.Create( pathInfo.DisplaySource.Adapter.AdapterId, pathInfo.DisplaySource.SourceId ); if (!pathInfo.DisplaySource.Adapter.IsInvalid && !sources.ContainsKey(key)) { sources.Add(key, pathInfo.DisplaySource); } } return sources.Values.ToArray(); } /// /// Checks for equality of two PathDisplaySource instances /// /// The first instance /// The second instance /// true if both instances are equal, otherwise false public static bool operator ==(PathDisplaySource left, PathDisplaySource right) { return Equals(left, right) || left?.Equals(right) == true; } /// /// Checks for inequality of two PathDisplaySource instances /// /// The first instance /// The second instance /// true if both instances are not equal, otherwise false public static bool operator !=(PathDisplaySource left, PathDisplaySource right) { return !(left == right); } /// public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) { return false; } if (ReferenceEquals(this, obj)) { return true; } return obj.GetType() == GetType() && Equals((PathDisplaySource) obj); } /// public override int GetHashCode() { unchecked { return ((Adapter != null ? Adapter.GetHashCode() : 0) * 397) ^ (int) SourceId; } } /// public override string ToString() { return DisplayName; } } }