using WindowsDisplayAPI.Exceptions; using WindowsDisplayAPI.Native.DisplayConfig; using WindowsDisplayAPI.Native.DisplayConfig.Structures; namespace WindowsDisplayAPI.DisplayConfig { /// /// Represents a path and its target /// public class PathTargetInfo { private readonly PathTargetDesktopImage _desktopImage; private readonly PathTargetSignalInfo _signalInfo; /// /// Creates a new PathTargetInfo /// /// The display target device /// A boolean value indicating the target virtual mode support public PathTargetInfo(PathDisplayTarget displayTarget, bool isVirtualModeSupported = false) { DisplayTarget = displayTarget; IsVirtualModeSupportedByPath = isVirtualModeSupported; } /// /// Creates a new PathTargetInfo /// /// The display target device /// Display frequency in millihertz /// Display scan line ordering /// Display rotation /// Display scaling /// A boolean value indicating the target virtual mode support public PathTargetInfo( PathDisplayTarget displayTarget, ulong frequencyInMillihertz, DisplayConfigScanLineOrdering scanLineOrdering = DisplayConfigScanLineOrdering.NotSpecified, DisplayConfigRotation rotation = DisplayConfigRotation.NotSpecified, DisplayConfigScaling scaling = DisplayConfigScaling.Preferred, bool isVirtualModeSupported = false ) : this(displayTarget, isVirtualModeSupported) { FrequencyInMillihertz = frequencyInMillihertz; ScanLineOrdering = scanLineOrdering; Rotation = rotation; Scaling = scaling; } /// /// Creates a new PathTargetInfo /// /// The display target device /// The display signal information /// A boolean value indicating the target virtual mode support public PathTargetInfo( PathDisplayTarget displayTarget, PathTargetSignalInfo signalInfo, bool isVirtualModeSupported = false ) : this(displayTarget, isVirtualModeSupported) { _signalInfo = signalInfo; FrequencyInMillihertz = signalInfo.VerticalSyncFrequencyInMillihertz; ScanLineOrdering = signalInfo.ScanLineOrdering; IsSignalInformationAvailable = true; } /// /// Creates a new PathTargetInfo /// /// The display target device /// The display signal information /// Display rotation /// Display scaling /// A boolean value indicating the target virtual mode support public PathTargetInfo( PathDisplayTarget displayTarget, PathTargetSignalInfo signalInfo, DisplayConfigRotation rotation = DisplayConfigRotation.NotSpecified, DisplayConfigScaling scaling = DisplayConfigScaling.Preferred, bool isVirtualModeSupported = false ) : this( displayTarget, 0, DisplayConfigScanLineOrdering.NotSpecified, rotation, scaling, isVirtualModeSupported ) { _signalInfo = signalInfo; FrequencyInMillihertz = signalInfo.VerticalSyncFrequencyInMillihertz; ScanLineOrdering = signalInfo.ScanLineOrdering; IsSignalInformationAvailable = true; } /// /// Creates a new PathTargetInfo /// /// The display target device /// The display signal information /// The display desktop image information /// A boolean value indicating the target virtual mode support public PathTargetInfo( PathDisplayTarget displayTarget, PathTargetSignalInfo signalInfo, PathTargetDesktopImage desktopImage, bool isVirtualModeSupported = false ) : this(displayTarget, signalInfo, isVirtualModeSupported) { _desktopImage = desktopImage; IsDesktopImageInformationAvailable = true; } /// /// Creates a new PathTargetInfo /// /// The display target device /// The display signal information /// The display desktop image information /// Display rotation /// Display scaling /// A boolean value indicating the target virtual mode support public PathTargetInfo( PathDisplayTarget displayTarget, PathTargetSignalInfo signalInfo, PathTargetDesktopImage desktopImage, DisplayConfigRotation rotation = DisplayConfigRotation.NotSpecified, DisplayConfigScaling scaling = DisplayConfigScaling.Preferred, bool isVirtualModeSupported = false ) : this(displayTarget, signalInfo, rotation, scaling, isVirtualModeSupported) { _desktopImage = desktopImage; IsDesktopImageInformationAvailable = true; } internal PathTargetInfo( DisplayConfigPathInfoFlags pathFlags, DisplayConfigPathTargetInfo targetInfo, DisplayConfigTargetMode? targetMode, DisplayConfigDesktopImageInfo? desktopImageMode ) { IsPathActive = pathFlags.HasFlag(DisplayConfigPathInfoFlags.Active); IsVirtualModeSupportedByPath = pathFlags.HasFlag(DisplayConfigPathInfoFlags.SupportVirtualMode); DisplayTarget = new PathDisplayTarget( new PathDisplayAdapter(targetInfo.AdapterId), targetInfo.TargetId, targetInfo.TargetAvailable ); OutputTechnology = targetInfo.OutputTechnology; Rotation = targetInfo.Rotation; Scaling = targetInfo.Scaling; ScanLineOrdering = targetInfo.ScanLineOrdering; FrequencyInMillihertz = targetInfo.RefreshRate.ToValue(1000); ForcedBootAvailability = targetInfo.StatusFlags.HasFlag( DisplayConfigPathTargetInfoFlags.AvailabilityBoot ); ForcedPathAvailability = targetInfo.StatusFlags.HasFlag( DisplayConfigPathTargetInfoFlags.AvailabilityPath ); ForcedSystemAvailability = targetInfo.StatusFlags.HasFlag( DisplayConfigPathTargetInfoFlags.AvailabilitySystem ); IsCurrentlyInUse = targetInfo.StatusFlags.HasFlag( DisplayConfigPathTargetInfoFlags.InUse ); IsForcible = targetInfo.StatusFlags.HasFlag( DisplayConfigPathTargetInfoFlags.Forcible ); IsSignalInformationAvailable = targetMode.HasValue; if (targetMode.HasValue) { _signalInfo = new PathTargetSignalInfo(targetMode.Value.TargetVideoSignalInfo); } IsDesktopImageInformationAvailable = desktopImageMode.HasValue; if (desktopImageMode.HasValue) { _desktopImage = new PathTargetDesktopImage(desktopImageMode.Value); } } /// /// Gets an instance of PathTargetDesktopImage containing information about this target desktop image /// /// Target mode information is missing public PathTargetDesktopImage DesktopImage { get { if (!IsDesktopImageInformationAvailable) { throw new MissingModeException( "Desktop image information is missing or not available.", DisplayConfigModeInfoType.DesktopImage ); } return _desktopImage; } } /// /// Gets extra information about the representing display target device /// public PathDisplayTarget DisplayTarget { get; } /// /// Gets a boolean value indicating that the output is currently being forced in a boot-persistent manner /// public bool ForcedBootAvailability { get; } /// /// Gets a boolean value indicating that the output is currently being forced in a path-persistent manner /// public bool ForcedPathAvailability { get; } /// /// Gets a boolean value indicating that the output is currently being forced in a non-persistent manner /// public bool ForcedSystemAvailability { get; } /// /// Gets a value that specifies the refresh rate of the target /// public ulong FrequencyInMillihertz { get; } /// /// Gets a boolean value indicating if the target is in use on an active path /// public bool IsCurrentlyInUse { get; } /// /// Gets a boolean value indicating the presence of the desktop image information /// public bool IsDesktopImageInformationAvailable { get; } /// /// Gets a boolean value indicating that the output can be forced on this target even if a monitor is not detected /// public bool IsForcible { get; } /// /// Gets a boolean value indicating if this path is or should be active /// public bool IsPathActive { get; } = true; /// /// Gets a boolean value indicating the presence of the signal information /// public bool IsSignalInformationAvailable { get; } /// /// Gets a boolean value that indicates if the path supports virtual mode /// public bool IsVirtualModeSupportedByPath { get; } /// /// Gets the type of the display device connection /// public DisplayConfigVideoOutputTechnology OutputTechnology { get; } = DisplayConfigVideoOutputTechnology.Other; /// /// Gets the rotation of the target /// public DisplayConfigRotation Rotation { get; } /// /// Gets the value that specifies how the source image is scaled to the target /// public DisplayConfigScaling Scaling { get; } /// /// Gets the value that specifies the scan-line ordering of the output on the target /// public DisplayConfigScanLineOrdering ScanLineOrdering { get; } /// /// Gets the target device signal information /// /// Target mode information is missing public PathTargetSignalInfo SignalInfo { get { if (!IsSignalInformationAvailable) { throw new MissingModeException( "Target mode information is missing or not available.", DisplayConfigModeInfoType.Target ); } return _signalInfo; } } /// public override string ToString() { return $"{DisplayTarget}: {FrequencyInMillihertz / 1000}hz{(IsCurrentlyInUse ? " [In Use]" : "")}"; } internal DisplayConfigDesktopImageInfo? GetDisplayConfigDesktopImageInfo() { if (IsDesktopImageInformationAvailable) { return DesktopImage.GetDisplayConfigDesktopImageInfo(); } return null; } internal DisplayConfigTargetMode? GetDisplayConfigTargetMode() { if (IsSignalInformationAvailable) { return new DisplayConfigTargetMode(SignalInfo.GetDisplayConfigVideoSignalInfo()); } return null; } } }