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;
}
}
}