2017-02-26 19:23:31 +00:00
using System ;
using System.Linq ;
using WindowsDisplayAPI.DisplayConfig ;
2020-12-20 07:42:04 +00:00
using DisplayMagicianShared.NVIDIA ;
2018-10-20 00:19:30 +00:00
using Newtonsoft.Json ;
using Newtonsoft.Json.Converters ;
2020-05-13 11:04:18 +00:00
using System.Collections.Generic ;
2017-02-26 19:23:31 +00:00
2020-12-20 07:42:04 +00:00
namespace DisplayMagicianShared.Topology
2017-02-26 19:23:31 +00:00
{
2020-10-07 07:08:36 +00:00
public class PathTarget : IEquatable < PathTarget >
2017-02-26 19:23:31 +00:00
{
2020-10-07 07:08:36 +00:00
public PathTarget ( PathTargetInfo targetInfo , SurroundTopology surround = null )
2017-02-26 19:23:31 +00:00
{
DevicePath = targetInfo . DisplayTarget . DevicePath ;
var index = DevicePath . IndexOf ( "{" , StringComparison . InvariantCultureIgnoreCase ) ;
2018-10-20 00:27:25 +00:00
2017-02-26 19:23:31 +00:00
if ( index > 0 )
2018-10-20 00:27:25 +00:00
{
2017-02-26 19:23:31 +00:00
DevicePath = DevicePath . Substring ( 0 , index ) . TrimEnd ( '#' ) ;
2021-05-19 09:32:49 +00:00
SharedLogger . logger . Trace ( $"PathTarget/PathTarget: Grabbed the DevicePath of {DevicePath}." ) ;
2018-10-20 00:27:25 +00:00
}
2017-02-26 19:23:31 +00:00
FrequencyInMillihertz = targetInfo . FrequencyInMillihertz ;
2021-05-19 09:32:49 +00:00
SharedLogger . logger . Trace ( $"PathTarget/PathTarget: Grabbed the FrequencyInMillihertz of {FrequencyInMillihertz}." ) ;
2017-02-26 19:23:31 +00:00
Rotation = targetInfo . Rotation . ToRotation ( ) ;
2021-05-19 09:32:49 +00:00
SharedLogger . logger . Trace ( $"PathTarget/PathTarget: Grabbed the Rotation of {Rotation}." ) ;
2018-10-20 00:19:30 +00:00
Scaling = targetInfo . Scaling . ToScaling ( ) ;
2021-05-19 09:32:49 +00:00
SharedLogger . logger . Trace ( $"PathTarget/PathTarget: Grabbed the Scaling of {Scaling}." ) ;
2018-10-20 00:19:30 +00:00
ScanLineOrdering = targetInfo . ScanLineOrdering . ToScanLineOrdering ( ) ;
2021-05-19 09:32:49 +00:00
SharedLogger . logger . Trace ( $"PathTarget/PathTarget: Grabbed the ScanLineOrdering of {ScanLineOrdering}." ) ;
2018-10-20 00:27:25 +00:00
2017-02-26 19:23:31 +00:00
try
{
DisplayName = targetInfo . DisplayTarget . FriendlyName ;
2021-05-19 09:32:49 +00:00
SharedLogger . logger . Trace ( $"PathTarget/PathTarget: Grabbed the DisplayName of {DisplayName}." ) ;
2017-02-26 19:23:31 +00:00
}
2021-05-19 09:32:49 +00:00
catch ( Exception ex )
2017-02-26 19:23:31 +00:00
{
2021-05-19 09:32:49 +00:00
SharedLogger . logger . Warn ( ex , $"PathTarget/PathTarget: Exception grabbing the DisplayName of {DisplayName} from the TargetInfo DisplayTarget." ) ;
2017-02-26 19:23:31 +00:00
DisplayName = null ;
}
2018-10-20 00:27:25 +00:00
2021-05-19 09:32:49 +00:00
if ( surround ! = null )
{
2021-05-19 10:24:04 +00:00
SharedLogger . logger . Trace ( $"PathTarget/PathTarget: This PathTarget supplied an NVIDIA surround object, so using the SurroundTopology supplied." ) ;
SurroundTopology = surround ;
}
else
{
2021-05-19 09:32:49 +00:00
try
{
SurroundTopology = SurroundTopology . FromPathTargetInfo ( targetInfo ) ;
2021-05-19 10:24:04 +00:00
if ( SurroundTopology ! = null )
{
SharedLogger . logger . Trace ( $"PathTarget/PathTarget: The SurroundTopology object supplied was null, so we created one ourselves. We found {SurroundTopology.Displays.Count()} displays involved in it {SurroundTopology.Columns}x{SurroundTopology.Rows}" ) ;
}
else
{
SharedLogger . logger . Trace ( $"PathTarget/PathTarget: The SurroundTopology object supplied was null, so we tried to create one ourselves and failed. This is likely a non NVIDIA surround display profile." ) ;
}
2021-05-19 09:32:49 +00:00
}
catch ( Exception ex )
{
2021-05-19 10:24:04 +00:00
SharedLogger . logger . Error ( ex , $"PathTarget/PathTarget: A SurroundTopology object was not supplied, but we had an exception getting our own SurroundTopology from the PathTargetInfo object." ) ;
2021-05-19 09:32:49 +00:00
}
}
2017-02-26 19:23:31 +00:00
}
2017-08-10 14:21:45 +00:00
2017-02-26 19:23:31 +00:00
2020-10-07 07:08:36 +00:00
public PathTarget ( )
2017-02-26 19:23:31 +00:00
{
}
2017-08-10 14:21:45 +00:00
public string DevicePath { get ; set ; }
2017-02-26 19:23:31 +00:00
public string DisplayName { get ; set ; }
2018-10-20 00:19:30 +00:00
2017-02-26 19:23:31 +00:00
public ulong FrequencyInMillihertz { get ; set ; }
2018-10-20 00:19:30 +00:00
[JsonConverter(typeof(StringEnumConverter))]
2017-02-26 19:23:31 +00:00
public Rotation Rotation { get ; set ; }
2018-10-20 00:19:30 +00:00
[JsonConverter(typeof(StringEnumConverter))]
public Scaling Scaling { get ; set ; }
[JsonConverter(typeof(StringEnumConverter))]
public ScanLineOrdering ScanLineOrdering { get ; set ; }
2017-08-10 14:21:45 +00:00
public SurroundTopology SurroundTopology { get ; set ; }
2017-02-26 19:23:31 +00:00
/// <inheritdoc />
2020-05-13 11:04:18 +00:00
public override string ToString ( )
2017-02-26 19:23:31 +00:00
{
2020-05-13 11:04:18 +00:00
return DisplayName ? ? $"PathTarget {DevicePath}" ;
}
2018-10-20 00:27:25 +00:00
2020-05-13 11:04:18 +00:00
public PathTargetInfo ToPathTargetInfo ( )
{
var targetDevice =
PathDisplayTarget . GetDisplayTargets ( )
. FirstOrDefault (
target = > target . DevicePath . StartsWith ( DevicePath ,
StringComparison . InvariantCultureIgnoreCase ) ) ;
if ( targetDevice = = null )
2020-05-12 10:46:23 +00:00
{
2020-05-13 11:04:18 +00:00
return null ;
2020-05-12 10:46:23 +00:00
}
2020-05-13 11:04:18 +00:00
return new PathTargetInfo ( new PathDisplayTarget ( targetDevice . Adapter , targetDevice . TargetId ) ,
FrequencyInMillihertz , ScanLineOrdering . ToDisplayConfigScanLineOrdering ( ) ,
Rotation . ToDisplayConfigRotation ( ) , Scaling . ToDisplayConfigScaling ( ) ) ;
2017-02-26 19:23:31 +00:00
}
2020-05-13 11:04:18 +00:00
// The public override for the Object.Equals
public override bool Equals ( object obj )
2017-02-26 19:23:31 +00:00
{
2020-10-07 07:08:36 +00:00
return this . Equals ( obj as PathTarget ) ;
2017-02-26 19:23:31 +00:00
}
2020-05-13 11:04:18 +00:00
// Profiles are equal if their contents (except name) are equal
2020-10-07 07:08:36 +00:00
public bool Equals ( PathTarget other )
2017-02-26 19:23:31 +00:00
{
2020-05-13 11:04:18 +00:00
// If parameter is null, return false.
if ( Object . ReferenceEquals ( other , null ) )
2018-10-20 00:27:25 +00:00
return false ;
2020-05-13 11:04:18 +00:00
// Optimization for a common success case.
if ( Object . ReferenceEquals ( this , other ) )
2018-10-20 00:27:25 +00:00
return true ;
2020-05-13 11:04:18 +00:00
// If run-time types are not exactly the same, return false.
if ( this . GetType ( ) ! = other . GetType ( ) )
return false ;
// Check whether the Profile Viewport properties are equal
// Two profiles are equal only when they have the same viewport data exactly
if ( FrequencyInMillihertz = = other . FrequencyInMillihertz & &
Rotation . Equals ( other . Rotation ) & &
Scaling . Equals ( other . Scaling ) & &
ScanLineOrdering . Equals ( other . ScanLineOrdering ) & &
DisplayName . Equals ( other . DisplayName ) & &
DevicePath . Equals ( other . DevicePath ) )
2018-10-20 00:27:25 +00:00
{
2020-05-13 11:04:18 +00:00
// If the above all match, then we need to check the SurroundTopology matches
if ( SurroundTopology = = null & & other . SurroundTopology = = null )
return true ;
else if ( SurroundTopology ! = null & & other . SurroundTopology = = null )
return false ;
else if ( SurroundTopology = = null & & other . SurroundTopology ! = null )
return false ;
else if ( SurroundTopology . Equals ( other . SurroundTopology ) )
return true ;
2018-10-20 00:27:25 +00:00
return false ;
}
2020-05-13 11:04:18 +00:00
else
return false ;
2017-02-26 19:23:31 +00:00
}
2020-05-13 11:04:18 +00:00
// If Equals() returns true for this object compared to another
// then GetHashCode() must return the same value for these objects.
2017-02-26 19:23:31 +00:00
public override int GetHashCode ( )
{
2020-05-13 11:04:18 +00:00
// Get hash code for the FrequencyInMillihertz field if it is not null.
int hashFrequencyInMillihertz = FrequencyInMillihertz . GetHashCode ( ) ;
2017-02-26 19:23:31 +00:00
2020-05-13 11:04:18 +00:00
// Get hash code for the Position field if it is not null.
int hashRotation = Rotation . GetHashCode ( ) ;
// Get hash code for the Scaling field if it is not null.
int hashScaling = Scaling . GetHashCode ( ) ;
// Get hash code for the ScanLineOrdering field if it is not null.
int hashScanLineOrdering = ScanLineOrdering . GetHashCode ( ) ;
// Get hash code for the hashDisplayName field if it is not null.
int hashDisplayName = DisplayName = = null ? 0 : DisplayName . GetHashCode ( ) ;
// Get hash code for the DevicePath field if it is not null.
int hashDevicePath = DevicePath = = null ? 0 : DevicePath . GetHashCode ( ) ;
// Get hash code for the SurroundTopology field if it is not null.
int hashSurroundTopology = SurroundTopology = = null ? 0 : SurroundTopology . GetHashCode ( ) ;
//Calculate the hash code for the product.
return hashFrequencyInMillihertz ^ hashRotation ^ hashScaling ^ hashScanLineOrdering ^
hashDisplayName ^ hashDevicePath ^ hashSurroundTopology ;
2017-02-26 19:23:31 +00:00
}
2020-05-13 11:04:18 +00:00
}
2017-02-26 19:23:31 +00:00
2020-05-13 11:04:18 +00:00
// Custom comparer for the ProfileViewportTargetDisplay class
2020-10-07 07:08:36 +00:00
class ProfileViewportTargetDisplayComparer : IEqualityComparer < PathTarget >
2020-05-13 11:04:18 +00:00
{
// Products are equal if their names and product numbers are equal.
2020-10-07 07:08:36 +00:00
public bool Equals ( PathTarget x , PathTarget y )
2017-02-26 19:23:31 +00:00
{
2018-10-20 00:27:25 +00:00
2020-05-13 11:04:18 +00:00
//Check whether the compared objects reference the same data.
if ( Object . ReferenceEquals ( x , y ) ) return true ;
//Check whether any of the compared objects is null.
if ( Object . ReferenceEquals ( x , null ) | | Object . ReferenceEquals ( y , null ) )
return false ;
// Check whether the Profile Viewport properties are equal
// Two profiles are equal only when they have the same viewport data exactly
if ( x . FrequencyInMillihertz = = y . FrequencyInMillihertz & &
x . Rotation . Equals ( y . Rotation ) & &
x . Scaling . Equals ( y . Scaling ) & &
x . ScanLineOrdering . Equals ( y . ScanLineOrdering ) & &
x . DisplayName . Equals ( y . DisplayName ) & &
x . DevicePath . Equals ( y . DevicePath ) )
2018-10-20 00:27:25 +00:00
{
2020-05-13 11:04:18 +00:00
// If the above all match, then we need to check the SurroundTopology matches
if ( x . SurroundTopology = = null & & y . SurroundTopology = = null )
return true ;
else if ( x . SurroundTopology ! = null & & y . SurroundTopology = = null )
return false ;
else if ( x . SurroundTopology = = null & & y . SurroundTopology ! = null )
return false ;
else if ( x . SurroundTopology . Equals ( y . SurroundTopology ) )
return true ;
return false ;
2018-10-20 00:27:25 +00:00
}
2020-05-13 11:04:18 +00:00
else
return false ;
}
2018-10-20 00:27:25 +00:00
2020-05-13 11:04:18 +00:00
// If Equals() returns true for a pair of objects
// then GetHashCode() must return the same value for these objects.
2020-10-07 07:08:36 +00:00
public int GetHashCode ( PathTarget profileViewport )
2020-05-13 11:04:18 +00:00
{
// Check whether the object is null
if ( Object . ReferenceEquals ( profileViewport , null ) ) return 0 ;
// Get hash code for the FrequencyInMillihertz field if it is not null.
int hashFrequencyInMillihertz = profileViewport . FrequencyInMillihertz . GetHashCode ( ) ;
// Get hash code for the Position field if it is not null.
int hashRotation = profileViewport . Rotation . GetHashCode ( ) ;
// Get hash code for the Scaling field if it is not null.
int hashScaling = profileViewport . Scaling . GetHashCode ( ) ;
// Get hash code for the ScanLineOrdering field if it is not null.
int hashScanLineOrdering = profileViewport . ScanLineOrdering . GetHashCode ( ) ;
// Get hash code for the hashDisplayName field if it is not null.
int hashDisplayName = profileViewport . DisplayName = = null ? 0 : profileViewport . DisplayName . GetHashCode ( ) ;
// Get hash code for the DevicePath field if it is not null.
int hashDevicePath = profileViewport . DevicePath = = null ? 0 : profileViewport . DevicePath . GetHashCode ( ) ;
// Get hash code for the SurroundTopology field if it is not null.
int hashSurroundTopology = profileViewport . SurroundTopology = = null ? 0 : profileViewport . SurroundTopology . GetHashCode ( ) ;
//Calculate the hash code for the product.
return hashFrequencyInMillihertz ^ hashRotation ^ hashScaling ^ hashScanLineOrdering ^
hashDisplayName ^ hashDevicePath ^ hashSurroundTopology ;
2017-02-26 19:23:31 +00:00
}
2020-05-13 11:04:18 +00:00
2017-02-26 19:23:31 +00:00
}
}