2021-06-22 09:05:24 +00:00
using System ;
using System.Collections.Generic ;
using System.IO ;
using System.Linq ;
using System.Windows.Forms ;
using DisplayMagicianShared.Resources ;
using Newtonsoft.Json ;
using System.Drawing ;
using System.Drawing.Imaging ;
using System.Text.RegularExpressions ;
using IWshRuntimeLibrary ;
2021-07-24 04:05:38 +00:00
//using ATI.ADL;
2021-06-22 09:05:24 +00:00
//using WK.Libraries.HotkeyListenerNS;
namespace DisplayMagicianShared.AMD
{
2021-06-27 01:53:00 +00:00
2021-07-24 04:05:38 +00:00
/ * // Struct to be used as the AMD Profile
2021-06-27 01:53:00 +00:00
[JsonObject(MemberSerialization.Fields)]
public struct AMDProfile
{
public List < AMDAdapter > Adapters ;
}
// Struct to store the Display
[JsonObject(MemberSerialization.Fields)]
public struct AMDAdapter
{
2021-06-27 08:46:32 +00:00
public int AdapterIndex ;
public string AdapterName ;
public string DisplayName ;
2021-06-27 01:53:00 +00:00
[JsonProperty]
2021-06-27 02:44:10 +00:00
public ADLAdapterInfoX2 AdapterInfoX2 ;
public List < AMDDisplay > Displays ;
2021-06-27 01:53:00 +00:00
}
// Struct to store the Display
[JsonObject(MemberSerialization.Fields)]
public struct AMDDisplay
{
2021-06-27 02:44:10 +00:00
public string DisplayName ;
public string DisplayConnector ;
2021-06-27 08:46:32 +00:00
public string UDID ;
2021-06-27 01:53:00 +00:00
[JsonRequired]
2021-06-27 02:44:10 +00:00
public List < ADLMode > DisplayModes ;
public bool HDRSupported ;
public bool HDREnabled ;
public bool IsEyefinity ;
2021-06-27 01:53:00 +00:00
2021-07-24 04:05:38 +00:00
} * /
2021-06-27 01:53:00 +00:00
2021-06-22 09:05:24 +00:00
public class AMDProfileItem : ProfileItem , IComparable
{
private static List < AMDProfileItem > _allSavedProfiles = new List < AMDProfileItem > ( ) ;
private ProfileIcon _profileIcon ;
private Bitmap _profileBitmap , _profileShortcutBitmap ;
private List < string > _profileDisplayIdentifiers = new List < string > ( ) ;
2021-06-24 10:14:39 +00:00
private List < ScreenPosition > _screens ;
2021-07-24 04:05:38 +00:00
private AMD_DISPLAY_CONFIG _displayConfig = new AMD_DISPLAY_CONFIG ( ) ;
2021-06-22 09:05:24 +00:00
private static readonly string uuidV4Regex = @"(?im)^[{(]?[0-9A-F]{8}[-]?(?:[0-9A-F]{4}[-]?){3}[0-9A-F]{12}[)}]?$" ;
private string _uuid = "" ;
private bool _isPossible = false ;
private Keys _hotkey = Keys . None ;
public AMDProfileItem ( )
{
}
public new static Version Version = new Version ( 2 , 1 ) ;
#region Instance Properties
[JsonIgnore]
public override bool IsPossible
{
get
{
// Return the cached answer
return _isPossible ;
}
set
{
_isPossible = value ;
}
}
[JsonIgnore]
public override bool IsActive
{
get
{
if ( this . Equals ( ProfileRepository . CurrentProfile ) )
return true ;
else
return false ;
}
}
public override string Driver { get ; } = "AMD" ;
public override string Name { get ; set ; }
//public Topology.Path[] Paths { get; set; } = new Topology.Path[0];
2021-06-27 01:53:00 +00:00
[JsonRequired]
2021-07-24 04:05:38 +00:00
public AMD_DISPLAY_CONFIG DisplayConfig
2021-06-25 09:52:02 +00:00
{
get
{
2021-07-24 04:05:38 +00:00
return _displayConfig ;
2021-06-25 09:52:02 +00:00
}
set
{
2021-07-24 04:05:38 +00:00
_displayConfig = value ;
2021-06-25 09:52:02 +00:00
}
}
2021-06-22 09:05:24 +00:00
public override List < string > ProfileDisplayIdentifiers
{
get
{
if ( _profileDisplayIdentifiers . Count = = 0 )
{
2021-07-24 04:05:38 +00:00
_profileDisplayIdentifiers = AMDLibrary . GetLibrary ( ) . GetCurrentDisplayIdentifiers ( ) ;
2021-06-22 09:05:24 +00:00
}
return _profileDisplayIdentifiers ;
}
set
{
if ( value is List < string > )
_profileDisplayIdentifiers = value ;
}
}
2021-06-24 10:14:39 +00:00
[JsonIgnore]
public override List < ScreenPosition > Screens
{
get
{
if ( _screens . Count = = 0 )
{
_screens = GetScreenPositions ( ) ;
}
return _screens ;
}
2021-06-27 01:53:00 +00:00
set
{
_screens = value ;
}
2021-06-24 10:14:39 +00:00
}
2021-06-27 01:53:00 +00:00
//[JsonConverter(typeof(CustomBitmapConverter))]
[JsonIgnore]
public override Bitmap ProfileBitmap
2021-06-22 09:05:24 +00:00
{
get
{
2021-06-27 01:53:00 +00:00
/ * if ( ! ProfileRepository . ProfilesLoaded )
return null ; * /
2021-06-22 09:05:24 +00:00
if ( _profileBitmap ! = null )
return _profileBitmap ;
else
{
_profileBitmap = this . ProfileIcon . ToBitmap ( 256 , 256 ) ;
return _profileBitmap ;
}
}
set
{
_profileBitmap = value ;
}
}
2021-06-27 01:53:00 +00:00
//[JsonConverter(typeof(CustomBitmapConverter))]
[JsonIgnore]
public override Bitmap ProfileTightestBitmap
{
get
{
if ( _profileShortcutBitmap ! = null )
return _profileShortcutBitmap ;
else
{
_profileShortcutBitmap = this . ProfileIcon . ToTightestBitmap ( ) ;
return _profileShortcutBitmap ;
}
}
set
{
_profileShortcutBitmap = value ;
}
2021-06-29 10:15:57 +00:00
}
2021-06-27 01:53:00 +00:00
2021-06-22 09:05:24 +00:00
#endregion
public override bool IsValid ( )
{
if ( ProfileIcon is ProfileIcon & &
System . IO . File . Exists ( SavedProfileIconCacheFilename ) & &
ProfileBitmap is Bitmap & &
ProfileTightestBitmap is Bitmap & &
ProfileDisplayIdentifiers . Count > 0 )
{
2021-07-24 04:05:38 +00:00
if ( DisplayConfig . AdapterConfigs . Count > 0 )
2021-06-22 09:05:24 +00:00
return true ;
else
return false ;
}
else
return false ;
}
public bool CopyTo ( AMDProfileItem profile , bool overwriteId = true )
{
if ( ! ( profile is AMDProfileItem ) )
return false ;
if ( overwriteId = = true )
profile . UUID = UUID ;
// Copy all our profile data over to the other profile
profile . Name = Name ;
2021-07-24 04:05:38 +00:00
profile . DisplayConfig = DisplayConfig ;
2021-06-22 09:05:24 +00:00
profile . ProfileIcon = ProfileIcon ;
profile . SavedProfileIconCacheFilename = SavedProfileIconCacheFilename ;
profile . ProfileBitmap = ProfileBitmap ;
profile . ProfileTightestBitmap = ProfileTightestBitmap ;
profile . ProfileDisplayIdentifiers = ProfileDisplayIdentifiers ;
2021-06-27 02:44:10 +00:00
//profile.Screens = Screens;
2021-06-22 09:05:24 +00:00
return true ;
}
public override bool PreSave ( )
{
// Prepare our profile data for saving
if ( _profileDisplayIdentifiers . Count = = 0 )
{
2021-07-24 04:05:38 +00:00
_profileDisplayIdentifiers = AMDLibrary . GetLibrary ( ) . GetCurrentDisplayIdentifiers ( ) ;
2021-06-22 09:05:24 +00:00
}
// Return if it is valid and we should continue
return IsValid ( ) ;
}
2021-06-27 02:44:10 +00:00
public override void RefreshPossbility ( )
{
// Check each display in this profile and make sure it's currently available
int validDisplayCount = 0 ;
//validDisplayCount = (from connectedDisplay in ProfileRepository.ConnectedDisplayIdentifiers select connectedDisplay == profileDisplayIdentifier).Count();
foreach ( string profileDisplayIdentifier in ProfileDisplayIdentifiers )
{
// If this profile has a display that isn't currently available then we need to say it's a no!
if ( ProfileRepository . ConnectedDisplayIdentifiers . Any ( s = > profileDisplayIdentifier . Equals ( s ) ) )
{
SharedLogger . logger . Trace ( $"ProfileItem/RefreshPossbility: We found the display in the profile {Name} with profileDisplayIdentifier {profileDisplayIdentifier} is connected now." ) ;
validDisplayCount + + ;
}
else
{
SharedLogger . logger . Warn ( $"ProfileItem/RefreshPossbility: We found the display in the profile {Name} with profileDisplayIdentifier {profileDisplayIdentifier} is NOT currently connected, so this profile cannot be used." ) ;
}
}
if ( validDisplayCount = = ProfileDisplayIdentifiers . Count )
{
SharedLogger . logger . Debug ( $"ProfileRepository/IsPossibleRefresh: The profile {Name} is possible!" ) ;
_isPossible = true ;
}
else
{
SharedLogger . logger . Debug ( $"ProfileRepository/IsPossibleRefresh: The profile {Name} is NOT possible!" ) ;
_isPossible = false ;
}
}
2021-06-26 09:54:11 +00:00
public override bool CreateProfileFromCurrentDisplaySettings ( )
2021-06-24 10:14:39 +00:00
{
2021-06-26 09:54:11 +00:00
AMDLibrary amdLibrary = AMDLibrary . GetLibrary ( ) ;
if ( amdLibrary . IsInstalled )
{
// Create the profile data from the current config
2021-07-24 04:05:38 +00:00
_displayConfig = amdLibrary . GetActiveConfig ( ) ;
2021-06-26 09:54:11 +00:00
// Now, since the ActiveProfile has changed, we need to regenerate screen positions
_screens = GetScreenPositions ( ) ;
return true ;
}
else
2021-06-25 09:52:02 +00:00
{
2021-06-26 09:54:11 +00:00
return false ;
}
}
2021-06-27 02:44:10 +00:00
public override bool PerformPostLoadingTasks ( )
2021-06-27 01:53:00 +00:00
{
// First thing we do is to set up the Screens
_screens = GetScreenPositions ( ) ;
return true ;
}
2021-06-26 09:54:11 +00:00
public override List < ScreenPosition > GetScreenPositions ( )
{
// Now we create the screens structure from the AMD profile information
_screens = new List < ScreenPosition > ( ) ;
2021-06-25 09:52:02 +00:00
2021-07-24 04:05:38 +00:00
if ( _displayConfig . AdapterConfigs . Count > 0 )
2021-06-26 09:54:11 +00:00
{
2021-07-24 04:05:38 +00:00
foreach ( var adapter in _displayConfig . AdapterConfigs )
2021-06-25 09:52:02 +00:00
{
2021-06-26 09:54:11 +00:00
foreach ( var display in adapter . Displays )
2021-06-25 09:52:02 +00:00
{
2021-06-26 09:54:11 +00:00
foreach ( var mode in display . DisplayModes )
2021-06-25 09:52:02 +00:00
{
2021-06-26 09:54:11 +00:00
ScreenPosition screen = new ScreenPosition ( ) ;
screen . Library = "AMD" ;
screen . Name = display . DisplayName ;
screen . DisplayConnector = display . DisplayConnector ;
screen . ScreenX = mode . XPos ;
screen . ScreenY = mode . YPos ;
screen . ScreenWidth = mode . XRes ;
screen . ScreenHeight = mode . YRes ;
2021-06-27 01:53:00 +00:00
2021-06-29 10:15:57 +00:00
// If we're at the 0,0 coordinate then we're the primary monitor
if ( screen . ScreenX = = 0 & & screen . ScreenY = = 0 )
{
screen . IsPrimary = true ;
}
2021-06-27 01:53:00 +00:00
// HDR information
if ( display . HDRSupported )
{
screen . HDRSupported = true ;
if ( display . HDREnabled )
{
screen . HDREnabled = true ;
}
else
{
screen . HDREnabled = false ;
}
}
else
{
screen . HDRSupported = false ;
screen . HDREnabled = false ;
}
2021-06-26 09:54:11 +00:00
2021-06-27 01:53:00 +00:00
// Spanned screen options
if ( display . IsEyefinity )
{
screen . IsSpanned = true ;
screen . Colour = Color . FromArgb ( 200 , 237 , 28 , 36 ) ; // represents AMD Red
screen . SpannedName = "AMD Eyefinity" ;
}
else
{
screen . IsSpanned = false ;
screen . Colour = Color . FromArgb ( 255 , 195 , 195 , 195 ) ; // represents normal screen colour
}
2021-06-26 09:54:11 +00:00
// Figure out features
//ATI.ADL.ADL.ConvertDisplayModeFlags(mode.ModeValue);
2021-06-27 01:53:00 +00:00
2021-06-26 09:54:11 +00:00
//screen.Features = mode.ModeValue;
_screens . Add ( screen ) ;
2021-06-25 09:52:02 +00:00
}
}
}
}
2021-06-26 09:54:11 +00:00
2021-06-25 09:52:02 +00:00
return _screens ;
2021-06-24 10:14:39 +00:00
}
2021-06-22 09:05:24 +00:00
// The public override for the Object.Equals
public override bool Equals ( object obj )
{
return this . Equals ( obj as AMDProfileItem ) ;
}
// Profiles are equal if their Viewports are equal
public bool Equals ( AMDProfileItem other )
{
// If parameter is null, return false.
if ( other is null )
return false ;
// Optimization for a common success case.
if ( Object . ReferenceEquals ( this , other ) )
return true ;
// If run-time types are not exactly the same, return false.
if ( this . GetType ( ) ! = other . GetType ( ) )
return false ;
2021-07-24 04:05:38 +00:00
// If the DisplayConfig's equal each other
if ( DisplayConfig . Equals ( other . DisplayConfig ) )
2021-06-22 09:05:24 +00:00
return false ;
// Check if the profile identifiers are not the same, then return false
int foundDICount = 0 ;
foreach ( string profileDI in ProfileDisplayIdentifiers )
{
if ( other . ProfileDisplayIdentifiers . Contains ( profileDI ) )
{
foundDICount + + ;
continue ;
}
}
if ( foundDICount ! = other . ProfileDisplayIdentifiers . Count )
return false ;
foundDICount = 0 ;
foreach ( string profileDI in other . ProfileDisplayIdentifiers )
{
if ( ProfileDisplayIdentifiers . Contains ( profileDI ) )
{
foundDICount + + ;
continue ;
}
}
if ( foundDICount ! = ProfileDisplayIdentifiers . Count )
return false ;
// Check whether the profiles' properties are equal
// We need to exclude the name as the name is solely for saving to disk
// and displaying to the user.
// Two profiles are equal only when they have the same viewport data
// The data may be in different orders each run, so we need to compare them one by one
int foundPathsCount = 0 ;
int foundOtherPathsCount = 0 ;
// TODO: Make this work in AMD land
/ * foreach ( Topology . Path profilePath in Paths )
{
if ( other . Paths . Contains ( profilePath ) )
{
foundPathsCount + + ;
continue ;
}
}
foreach ( Topology . Path otherPath in other . Paths )
{
if ( Paths . Contains ( otherPath ) )
{
foundOtherPathsCount + + ;
continue ;
}
} * /
if ( foundPathsCount = = foundOtherPathsCount )
return true ;
else
return false ;
}
// If Equals() returns true for this object compared to another
// then GetHashCode() must return the same value for these objects.
/ * public override int GetHashCode ( )
{
// Get hash code for the Viewports field if it is not null.
int hashPaths = Paths = = null ? 0 : Paths . GetHashCode ( ) ;
//Calculate the hash code for the product.
return hashPaths ;
} * /
public override int GetHashCode ( )
{
// Get hash code for the ProfileDisplayIdentifiers field if it is not null.
int hashIds = ProfileDisplayIdentifiers = = null ? 0 : ProfileDisplayIdentifiers . GetHashCode ( ) ;
// Get ProfileData too
2021-07-24 04:05:38 +00:00
int hashProfileData = DisplayConfig . GetHashCode ( ) ;
2021-06-22 09:05:24 +00:00
// Calculate the hash code for the product.
return ( hashIds , hashProfileData ) . GetHashCode ( ) ;
}
public override string ToString ( )
{
return ( Name ? ? Language . UN_TITLED_PROFILE ) ;
}
}
// Custom Equality comparer for the Profile class
// Allows us to use 'Contains'
class AMDProfileComparer : IEqualityComparer < AMDProfileItem >
{
// Products are equal if their names and product numbers are equal.
/ * public bool Equals ( AMDProfileItem x , AMDProfileItem y )
{
//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 ( x is null | | y is null )
return false ;
// Check whether the profiles' properties are equal
// We need to exclude the name as the name is solely for saving to disk
// and displaying to the user.
// Two profiles are equal only when they have the same viewport data
if ( x . Paths . SequenceEqual ( y . Paths ) )
return true ;
else
return false ;
} * /
public bool Equals ( AMDProfileItem x , AMDProfileItem y )
{
//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 ( x is null | | y is null )
return false ;
2021-07-24 04:05:38 +00:00
2021-06-22 09:05:24 +00:00
// Check if the profile identifiers are not the same, then return false
int foundDICount = 0 ;
foreach ( string profileDI in x . ProfileDisplayIdentifiers )
{
if ( y . ProfileDisplayIdentifiers . Contains ( profileDI ) )
{
foundDICount + + ;
continue ;
}
}
if ( foundDICount ! = x . ProfileDisplayIdentifiers . Count )
return false ;
foundDICount = 0 ;
foreach ( string profileDI in y . ProfileDisplayIdentifiers )
{
if ( x . ProfileDisplayIdentifiers . Contains ( profileDI ) )
{
foundDICount + + ;
continue ;
}
}
if ( foundDICount ! = y . ProfileDisplayIdentifiers . Count )
return false ;
2021-07-24 04:05:38 +00:00
// Now we need to check the Display Configs themselves
if ( x . DisplayConfig . Equals ( y . DisplayConfig ) )
2021-06-22 09:05:24 +00:00
return false ;
2021-06-29 10:15:57 +00:00
return true ;
2021-06-22 09:05:24 +00:00
}
// If Equals() returns true for a pair of objects
// then GetHashCode() must return the same value for these objects.
/ * public int GetHashCode ( AMDProfileItem profile )
{
// Check whether the object is null
if ( profile is null ) return 0 ;
// Get hash code for the Viewports field if it is not null.
int hashPaths = profile . Paths = = null ? 0 : profile . Paths . GetHashCode ( ) ;
//Calculate the hash code for the product.
return hashPaths ;
} * /
// Modified the GetHashCode to compare the displayidentifier
public int GetHashCode ( AMDProfileItem profile )
{
// Check whether the object is null
if ( profile is null ) return 0 ;
// Get hash code for the ProfileDisplayIdentifiers field if it is not null.
int hashIds = profile . ProfileDisplayIdentifiers = = null ? 0 : profile . ProfileDisplayIdentifiers . GetHashCode ( ) ;
// Get hash code for the Paths
2021-07-24 04:05:38 +00:00
int hashProfileData = profile . DisplayConfig . GetHashCode ( ) ;
2021-06-22 09:05:24 +00:00
//Calculate the hash code for the product.
return ( hashIds , hashProfileData ) . GetHashCode ( ) ;
}
}
}