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-08-22 00:54:39 +00:00
using DisplayMagicianShared.Windows ;
2021-06-22 09:05:24 +00:00
namespace DisplayMagicianShared.NVIDIA
{
2021-08-24 09:49:18 +00:00
2021-06-22 09:05:24 +00:00
public class NVIDIAProfileItem : ProfileItem , IComparable
{
private static List < NVIDIAProfileItem > _allSavedProfiles = new List < NVIDIAProfileItem > ( ) ;
private ProfileIcon _profileIcon ;
private Bitmap _profileBitmap , _profileShortcutBitmap ;
private List < string > _profileDisplayIdentifiers = new List < string > ( ) ;
2021-08-21 10:01:23 +00:00
private List < ScreenPosition > _screens ;
2021-08-22 00:54:39 +00:00
private NVIDIA_DISPLAY_CONFIG _nvidiaDisplayConfig = new NVIDIA_DISPLAY_CONFIG ( ) ;
private WINDOWS_DISPLAY_CONFIG _windowsDisplayConfig = new WINDOWS_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 ;
2021-08-22 09:45:51 +00:00
2021-06-22 09:05:24 +00:00
public NVIDIAProfileItem ( )
{
}
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 ;
}
}
2021-08-22 06:58:08 +00:00
public override VIDEO_MODE VideoMode { get ; } = VIDEO_MODE . NVIDIA ;
2021-06-22 09:05:24 +00:00
public override string Name { get ; set ; }
2021-08-21 10:01:23 +00:00
[JsonRequired]
2021-08-22 00:54:39 +00:00
public NVIDIA_DISPLAY_CONFIG NVIDIADisplayConfig
2021-08-21 10:01:23 +00:00
{
get
{
2021-08-22 00:54:39 +00:00
return _nvidiaDisplayConfig ;
2021-08-21 10:01:23 +00:00
}
set
{
2021-08-22 00:54:39 +00:00
_nvidiaDisplayConfig = value ;
}
}
[JsonRequired]
public WINDOWS_DISPLAY_CONFIG WindowsDisplayConfig
{
get
{
return _windowsDisplayConfig ;
}
set
{
_windowsDisplayConfig = value ;
2021-08-21 10:01:23 +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 = NVIDIALibrary . GetLibrary ( ) . GetCurrentDisplayIdentifiers ( ) ;
2021-06-22 09:05:24 +00:00
}
return _profileDisplayIdentifiers ;
}
set
{
if ( value is List < string > )
_profileDisplayIdentifiers = value ;
}
}
#endregion
public override bool IsValid ( )
{
2021-08-22 04:49:38 +00:00
if ( NVIDIALibrary . GetLibrary ( ) . IsValidConfig ( _nvidiaDisplayConfig ) & &
2021-06-22 09:05:24 +00:00
ProfileIcon is ProfileIcon & &
System . IO . File . Exists ( SavedProfileIconCacheFilename ) & &
ProfileBitmap is Bitmap & &
ProfileTightestBitmap is Bitmap & &
ProfileDisplayIdentifiers . Count > 0 )
return true ;
else
return false ;
}
public bool CopyTo ( NVIDIAProfileItem profile , bool overwriteId = true )
{
if ( ! ( profile is NVIDIAProfileItem ) )
return false ;
if ( overwriteId = = true )
profile . UUID = UUID ;
// Copy all our profile data over to the other profile
profile . Name = Name ;
//profile.Paths = Paths;
profile . ProfileIcon = ProfileIcon ;
profile . SavedProfileIconCacheFilename = SavedProfileIconCacheFilename ;
profile . ProfileBitmap = ProfileBitmap ;
profile . ProfileTightestBitmap = ProfileTightestBitmap ;
profile . ProfileDisplayIdentifiers = ProfileDisplayIdentifiers ;
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 = NVIDIALibrary . GetLibrary ( ) . GetCurrentDisplayIdentifiers ( ) ;
2021-06-22 09:05:24 +00:00
}
// Return if it is valid and we should continue
return IsValid ( ) ;
}
2021-08-21 10:01:23 +00:00
public override void RefreshPossbility ( )
{
2021-08-22 03:42:12 +00:00
// Check whether this profile is possible
if ( NVIDIALibrary . GetLibrary ( ) . IsPossibleConfig ( _nvidiaDisplayConfig ) )
2021-08-21 10:01:23 +00:00
{
2021-08-22 03:42:12 +00:00
SharedLogger . logger . Debug ( $"ProfileRepository/IsPossibleRefresh: The NVIDIA profile {Name} is possible!" ) ;
2021-08-21 10:01:23 +00:00
_isPossible = true ;
}
else
{
2021-08-22 03:42:12 +00:00
SharedLogger . logger . Debug ( $"ProfileRepository/IsPossibleRefresh: The NVIDIA profile {Name} is NOT possible!" ) ;
2021-08-21 10:01:23 +00:00
_isPossible = false ;
}
}
2021-08-24 10:46:32 +00:00
// Actually set this profile active
public override bool SetActive ( )
{
NVIDIALibrary nvidiaLibrary = NVIDIALibrary . GetLibrary ( ) ;
WinLibrary winLibrary = WinLibrary . GetLibrary ( ) ;
if ( nvidiaLibrary . IsInstalled )
{
if ( ! nvidiaLibrary . IsActiveConfig ( _nvidiaDisplayConfig ) & & ! winLibrary . IsActiveConfig ( _windowsDisplayConfig ) )
{
if ( nvidiaLibrary . IsPossibleConfig ( _nvidiaDisplayConfig ) )
{
SharedLogger . logger . Trace ( $"ProfileRepository/SetActive: The NVIDIA display settings within profile {Name} are possible to use right now, so we'll use attempt to use them." ) ;
bool itWorkedforNVIDIA = nvidiaLibrary . SetActiveConfig ( _nvidiaDisplayConfig ) ;
if ( itWorkedforNVIDIA )
{
SharedLogger . logger . Trace ( $"ProfileRepository/SetActive: The NVIDIA display settings within profile {Name} were successfully applied." ) ;
// Then let's try to also apply the windows changes
// Note: we are unable to check if the Windows CCD display config is possible, as it won't match if either the current display config is a Mosaic config,
// or if the display config we want to change to is a Mosaic config. So we just have to assume that it will work!
bool itWorkedforWindows = winLibrary . SetActiveConfig ( _windowsDisplayConfig ) ;
if ( itWorkedforWindows )
{
SharedLogger . logger . Trace ( $"ProfileRepository/SetActive: The Windows CCD display settings within profile {Name} were successfully applied." ) ;
return true ;
}
else
{
SharedLogger . logger . Trace ( $"ProfileRepository/SetActive: The Windows CCD display settings within profile {Name} were NOT applied correctly." ) ;
}
}
else
{
SharedLogger . logger . Trace ( $"ProfileRepository/SetActive: The NVIDIA display settings within profile {Name} were NOT applied correctly." ) ;
}
}
else
{
SharedLogger . logger . Error ( $"ProfileRepository/SetActive: ERROR - Cannot apply the NVIDIA display config in profile {Name} as it is not currently possible to use it." ) ;
}
}
else
{
SharedLogger . logger . Info ( $"ProfileRepository/SetActive: The display settings in profile {Name} are already installed. No need to install them again. Exiting." ) ;
}
}
return false ;
}
2021-08-21 10:01:23 +00:00
public override bool CreateProfileFromCurrentDisplaySettings ( )
{
2021-08-21 10:09:41 +00:00
NVIDIALibrary nvidiaLibrary = NVIDIALibrary . GetLibrary ( ) ;
if ( nvidiaLibrary . IsInstalled )
2021-08-21 10:01:23 +00:00
{
// Create the profile data from the current config
2021-08-22 00:54:39 +00:00
_nvidiaDisplayConfig = nvidiaLibrary . GetActiveConfig ( ) ;
_windowsDisplayConfig = WinLibrary . GetLibrary ( ) . GetActiveConfig ( ) ;
2021-08-21 10:01:23 +00:00
// Now, since the ActiveProfile has changed, we need to regenerate screen positions
_screens = GetScreenPositions ( ) ;
return true ;
}
else
{
return false ;
}
}
public override bool PerformPostLoadingTasks ( )
{
// First thing we do is to set up the Screens
_screens = GetScreenPositions ( ) ;
return true ;
}
public override List < ScreenPosition > GetScreenPositions ( )
{
// Now we create the screens structure from the AMD profile information
_screens = new List < ScreenPosition > ( ) ;
2021-08-22 04:49:38 +00:00
int pathCount = _windowsDisplayConfig . DisplayConfigPaths . Length ;
// First of all we need to figure out how many display paths we have.
if ( pathCount < 1 )
{
// Return an empty screen if we have no Display Config Paths to use!
return _screens ;
}
2021-08-24 09:49:18 +00:00
// TODO: Make the NVIDIA displays show the individual screens and overlap!
/ * // Create a dictionary of all the screen sizes we want
Dictionary < string , SpannedScreenPosition > MosaicScreens = new Dictionary < string , SpannedScreenPosition > ( ) ;
for ( int i = 0 ; i < _nvidiaDisplayConfig . MosaicConfig . MosaicGridCount ; i + + )
{
for ( int j = 0 ; j < _nvidiaDisplayConfig . MosaicConfig . MosaicViewports . Where ( item = > item ) ; j + + )
{
}
} * /
2021-08-22 04:49:38 +00:00
foreach ( var path in _windowsDisplayConfig . DisplayConfigPaths )
2021-08-21 10:01:23 +00:00
{
2021-08-22 04:49:38 +00:00
// For each path we go through and get the relevant info we need.
if ( _windowsDisplayConfig . DisplayConfigPaths . Length > 0 )
2021-08-21 10:01:23 +00:00
{
2021-08-22 04:49:38 +00:00
// Set some basics about the screen
ScreenPosition screen = new ScreenPosition ( ) ;
screen . Library = "NVIDIA" ;
2021-08-22 09:45:51 +00:00
UInt32 sourceId = path . SourceInfo . Id ;
2021-08-22 04:49:38 +00:00
UInt32 targetId = path . TargetInfo . Id ;
2021-08-24 09:49:18 +00:00
2021-08-22 04:49:38 +00:00
2021-08-24 09:49:18 +00:00
// Go through the screens as Windows knows them, and then enhance the info with Mosaic data if it applies
2021-08-22 04:49:38 +00:00
foreach ( DISPLAYCONFIG_MODE_INFO displayMode in _windowsDisplayConfig . DisplayConfigModes )
2021-08-21 10:01:23 +00:00
{
2021-08-22 04:49:38 +00:00
// Find the matching Display Config Source Mode
2021-08-22 09:45:51 +00:00
if ( displayMode . InfoType = = DISPLAYCONFIG_MODE_INFO_TYPE . DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE & & displayMode . Id = = sourceId )
2021-08-21 10:01:23 +00:00
{
2021-08-22 04:49:38 +00:00
screen . Name = targetId . ToString ( ) ;
//screen.DisplayConnector = displayMode.DisplayConnector;
screen . ScreenX = displayMode . SourceMode . Position . X ;
screen . ScreenY = displayMode . SourceMode . Position . Y ;
screen . ScreenWidth = ( int ) displayMode . SourceMode . Width ;
screen . ScreenHeight = ( int ) displayMode . SourceMode . Height ;
2021-08-21 10:01:23 +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-08-22 09:45:51 +00:00
2021-08-24 09:49:18 +00:00
// Figure out if this is a spanned screen, and if so, record this info
if ( _nvidiaDisplayConfig . MosaicConfig . IsMosaicEnabled )
{
}
2021-08-22 09:45:51 +00:00
break ;
2021-08-22 04:49:38 +00:00
}
}
2021-08-21 10:01:23 +00:00
2021-08-22 04:49:38 +00:00
foreach ( ADVANCED_HDR_INFO_PER_PATH hdrInfo in _windowsDisplayConfig . DisplayHDRStates )
{
// Find the matching HDR information
if ( hdrInfo . Id = = targetId )
{
2021-08-21 10:01:23 +00:00
// HDR information
2021-08-22 04:49:38 +00:00
if ( hdrInfo . AdvancedColorInfo . AdvancedColorSupported )
2021-08-21 10:01:23 +00:00
{
screen . HDRSupported = true ;
2021-08-22 04:49:38 +00:00
if ( hdrInfo . AdvancedColorInfo . AdvancedColorEnabled )
2021-08-21 10:01:23 +00:00
{
screen . HDREnabled = true ;
}
else
{
screen . HDREnabled = false ;
}
}
else
{
screen . HDRSupported = false ;
screen . HDREnabled = false ;
}
2021-08-22 09:45:51 +00:00
break ;
2021-08-21 10:01:23 +00:00
}
}
2021-08-22 04:49:38 +00:00
// Now we need to check for Spanned screens
if ( _nvidiaDisplayConfig . MosaicConfig . IsMosaicEnabled )
{
screen . IsSpanned = true ;
screen . Colour = Color . FromArgb ( 118 , 185 , 0 ) ; // represents NVIDIA Green
screen . SpannedName = "NVIDIA Surround/Mosaic" ;
}
else
{
screen . IsSpanned = false ;
screen . Colour = Color . FromArgb ( 195 , 195 , 195 ) ; // represents normal screen colour
}
_screens . Add ( screen ) ;
}
}
2021-08-21 10:01:23 +00:00
2021-08-24 09:49:18 +00:00
/ *
// Go through the screens, and update the Mosaic screens with their info (if there are any)
if ( _nvidiaDisplayConfig . MosaicConfig . IsMosaicEnabled )
{
// *** Enum values for the mosaic topology type ***
// NV_MOSAIC_TOPO_1x2_BASIC = 1
// NV_MOSAIC_TOPO_2x1_BASIC = 2,
// NV_MOSAIC_TOPO_1x3_BASIC = 3,
// NV_MOSAIC_TOPO_3x1_BASIC = 4,
// NV_MOSAIC_TOPO_1x4_BASIC = 5,
// NV_MOSAIC_TOPO_4x1_BASIC = 6,
// NV_MOSAIC_TOPO_2x2_BASIC = 7,
// NV_MOSAIC_TOPO_2x3_BASIC = 8,
// NV_MOSAIC_TOPO_2x4_BASIC = 9,
// NV_MOSAIC_TOPO_3x2_BASIC = 10,
// NV_MOSAIC_TOPO_4x2_BASIC = 11,
// NV_MOSAIC_TOPO_1x5_BASIC = 12,
// NV_MOSAIC_TOPO_1x6_BASIC = 13,
// NV_MOSAIC_TOPO_7x1_BASIC = 14,
// *** Enum values for the mosaic topology type ***
// NV_MOSAIC_TOPO_1x2_PASSIVE_STEREO = 23,
// NV_MOSAIC_TOPO_2x1_PASSIVE_STEREO = 24,
// NV_MOSAIC_TOPO_1x3_PASSIVE_STEREO = 25,
// NV_MOSAIC_TOPO_3x1_PASSIVE_STEREO = 26,
// NV_MOSAIC_TOPO_1x4_PASSIVE_STEREO = 27,
// NV_MOSAIC_TOPO_4x1_PASSIVE_STEREO = 28,
// NV_MOSAIC_TOPO_2x2_PASSIVE_STEREO = 29,
for ( int screenIndex = 0 ; screenIndex < _screens . Count ; screenIndex + + )
{
// go through each screen, and check if it matches a mosaic screen
}
} * /
2021-08-21 10:01:23 +00:00
return _screens ;
}
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 NVIDIAProfileItem ) ;
}
// Profiles are equal if their Viewports are equal
public bool Equals ( NVIDIAProfileItem 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-08-22 03:42:12 +00:00
// If NVIDIA Display Config is different then return false.
if ( ! NVIDIADisplayConfig . Equals ( other . NVIDIADisplayConfig ) )
return false ;
// If Windows Display Config is different then return false.
if ( ! WindowsDisplayConfig . Equals ( other . WindowsDisplayConfig ) )
2021-06-22 09:05:24 +00:00
return false ;
2021-08-22 04:49:38 +00:00
// If Display Identifiers are different then return false.
if ( ! ProfileDisplayIdentifiers . SequenceEqual ( other . ProfileDisplayIdentifiers ) )
2021-06-22 09:05:24 +00:00
return false ;
2021-08-22 04:49:38 +00:00
// Otherwise if all the tests work, then we're good!
return true ;
2021-06-22 09:05:24 +00:00
}
// If Equals() returns true for this object compared to another
// then GetHashCode() must return the same value for these objects.
public override int GetHashCode ( )
{
// Calculate the hash code for the product.
2021-08-22 04:49:38 +00:00
return ( NVIDIADisplayConfig , WindowsDisplayConfig , ProfileDisplayIdentifiers ) . GetHashCode ( ) ;
2021-06-22 09:05:24 +00:00
}
}
}