2017-02-26 19:23:31 +00:00
using System ;
using System.Collections.Generic ;
using System.IO ;
using System.Linq ;
2022-03-25 08:51:38 +00:00
using System.Windows ;
2018-10-20 00:23:43 +00:00
using System.Windows.Forms ;
2020-12-20 07:42:04 +00:00
using DisplayMagicianShared.Resources ;
2018-10-20 00:13:40 +00:00
using Newtonsoft.Json ;
2020-05-09 13:02:07 +00:00
using System.Drawing ;
using System.Drawing.Imaging ;
2020-06-14 04:20:52 +00:00
using System.Text.RegularExpressions ;
2021-03-07 01:50:52 +00:00
using IWshRuntimeLibrary ;
2021-06-26 09:54:11 +00:00
using DisplayMagicianShared.AMD ;
2021-09-04 04:32:42 +00:00
using DisplayMagicianShared.NVIDIA ;
using DisplayMagicianShared.Windows ;
2022-02-07 01:43:20 +00:00
using System.Runtime.InteropServices ;
2017-02-26 19:23:31 +00:00
2020-12-20 07:42:04 +00:00
namespace DisplayMagicianShared
2017-02-26 19:23:31 +00:00
{
2021-06-24 10:14:39 +00:00
public struct ScreenPosition
2021-06-25 09:52:02 +00:00
{
public int ScreenX ;
public int ScreenY ;
public int ScreenWidth ;
public int ScreenHeight ;
public string Name ;
2021-12-16 23:25:02 +00:00
public string AdapterName ;
2021-06-26 09:54:11 +00:00
public string Library ;
2021-06-25 09:52:02 +00:00
public bool IsPrimary ;
2021-10-16 21:44:03 +00:00
public bool IsClone ;
public int ClonedCopies ;
2021-06-25 09:52:02 +00:00
public Color Colour ;
2021-06-27 01:53:00 +00:00
public string DisplayConnector ;
internal bool HDRSupported ;
internal bool HDREnabled ;
2021-06-25 09:52:02 +00:00
public List < string > Features ;
// If the screen is AMD Eyefinity or NVIDIA Surround or similar, it has screens that are part of it
2021-09-01 02:30:33 +00:00
// These fields indicate this. The spanned screens are added to the SpannedScreens field as required
2021-06-25 09:52:02 +00:00
public bool IsSpanned ;
public List < SpannedScreenPosition > SpannedScreens ;
public int SpannedColumns ;
public int SpannedRows ;
2022-03-25 08:51:38 +00:00
public TaskBarLayout . TaskBarEdge TaskBarEdge ;
2021-06-25 09:52:02 +00:00
}
public struct SpannedScreenPosition
2021-06-24 10:14:39 +00:00
{
public int ScreenX ;
public int ScreenY ;
public int ScreenWidth ;
public int ScreenHeight ;
public string Name ;
2021-06-25 09:52:02 +00:00
public Color Colour ;
public List < string > Features ;
public int Column ;
public int Row ;
2021-06-24 10:14:39 +00:00
}
2021-09-06 10:08:22 +00:00
public class ProfileItem : IComparable < ProfileItem > , IEquatable < ProfileItem >
2017-02-26 19:23:31 +00:00
{
2020-06-07 08:48:45 +00:00
private static List < ProfileItem > _allSavedProfiles = new List < ProfileItem > ( ) ;
2020-05-09 13:02:07 +00:00
private ProfileIcon _profileIcon ;
2020-06-07 08:48:45 +00:00
private Bitmap _profileBitmap , _profileShortcutBitmap ;
2020-08-19 06:55:50 +00:00
private List < string > _profileDisplayIdentifiers = new List < string > ( ) ;
2021-08-22 09:57:29 +00:00
private List < ScreenPosition > _screens = new List < ScreenPosition > ( ) ;
2021-09-19 08:56:58 +00:00
private NVIDIA_DISPLAY_CONFIG _nvidiaDisplayConfig ;
private AMD_DISPLAY_CONFIG _amdDisplayConfig ;
private WINDOWS_DISPLAY_CONFIG _windowsDisplayConfig ;
2017-02-26 19:23:31 +00:00
2020-12-02 08:11:23 +00:00
internal static string AppDataPath = System . IO . Path . Combine ( Environment . GetFolderPath ( Environment . SpecialFolder . LocalApplicationData ) , "DisplayMagician" ) ;
2021-08-27 09:15:53 +00:00
private static string AppWallpaperPath = Path . Combine ( AppDataPath , $"Wallpaper" ) ;
2021-01-28 09:20:00 +00:00
private static readonly string uuidV4Regex = @"(?im)^[{(]?[0-9A-F]{8}[-]?(?:[0-9A-F]{4}[-]?){3}[0-9A-F]{12}[)}]?$" ;
2020-05-09 13:02:07 +00:00
2020-06-15 09:57:46 +00:00
private string _uuid = "" ;
2021-02-28 08:24:12 +00:00
private bool _isPossible = false ;
2021-04-28 10:14:54 +00:00
private Keys _hotkey = Keys . None ;
2021-08-27 09:15:53 +00:00
private string _wallpaperBitmapFilename = "" ;
2022-02-01 09:04:08 +00:00
2020-05-09 13:02:07 +00:00
#region JsonConverterBitmap
internal class CustomBitmapConverter : JsonConverter
{
public override bool CanConvert ( Type objectType )
{
return true ;
}
//convert from byte to bitmap (deserialize)
public override object ReadJson ( JsonReader reader , Type objectType , object existingValue , JsonSerializer serializer )
{
string image = ( string ) reader . Value ;
byte [ ] byteBuffer = Convert . FromBase64String ( image ) ;
2021-01-28 09:03:02 +00:00
MemoryStream memoryStream = new MemoryStream ( byteBuffer )
{
Position = 0
} ;
2020-05-09 13:02:07 +00:00
return ( Bitmap ) Bitmap . FromStream ( memoryStream ) ;
}
//convert bitmap to byte (serialize)
public override void WriteJson ( JsonWriter writer , object value , JsonSerializer serializer )
{
Bitmap bitmap = ( Bitmap ) value ;
ImageConverter converter = new ImageConverter ( ) ;
writer . WriteValue ( ( byte [ ] ) converter . ConvertTo ( bitmap , typeof ( byte [ ] ) ) ) ;
}
public static System . Drawing . Imaging . ImageFormat GetImageFormat ( Bitmap bitmap )
{
ImageFormat img = bitmap . RawFormat ;
if ( img . Equals ( System . Drawing . Imaging . ImageFormat . Jpeg ) )
return System . Drawing . Imaging . ImageFormat . Jpeg ;
if ( img . Equals ( System . Drawing . Imaging . ImageFormat . Bmp ) )
return System . Drawing . Imaging . ImageFormat . Bmp ;
if ( img . Equals ( System . Drawing . Imaging . ImageFormat . Png ) )
return System . Drawing . Imaging . ImageFormat . Png ;
if ( img . Equals ( System . Drawing . Imaging . ImageFormat . Emf ) )
return System . Drawing . Imaging . ImageFormat . Emf ;
if ( img . Equals ( System . Drawing . Imaging . ImageFormat . Exif ) )
return System . Drawing . Imaging . ImageFormat . Exif ;
if ( img . Equals ( System . Drawing . Imaging . ImageFormat . Gif ) )
return System . Drawing . Imaging . ImageFormat . Gif ;
if ( img . Equals ( System . Drawing . Imaging . ImageFormat . Icon ) )
return System . Drawing . Imaging . ImageFormat . Icon ;
if ( img . Equals ( System . Drawing . Imaging . ImageFormat . MemoryBmp ) )
return System . Drawing . Imaging . ImageFormat . MemoryBmp ;
if ( img . Equals ( System . Drawing . Imaging . ImageFormat . Tiff ) )
return System . Drawing . Imaging . ImageFormat . Tiff ;
else
return System . Drawing . Imaging . ImageFormat . Wmf ;
}
}
#endregion
2020-06-15 09:57:46 +00:00
public ProfileItem ( )
2017-02-26 19:23:31 +00:00
{
2021-09-19 08:56:58 +00:00
// Fill out a new NVIDIA and AMD object when a profile is being created
// so that it will save correctly. Json.NET will save null references by default
// unless we fill them up first, and that in turn causes NullReference errors when
// loading the DisplayProfiles_2.0.json into DisplayMagician next time.
// We cannot make the structs themselves create the default entry, so instead, we
// make each library create the default.
_nvidiaDisplayConfig = NVIDIALibrary . GetLibrary ( ) . CreateDefaultConfig ( ) ;
_amdDisplayConfig = AMDLibrary . GetLibrary ( ) . CreateDefaultConfig ( ) ;
2017-02-26 19:23:31 +00:00
}
2020-05-09 13:02:07 +00:00
public static Version Version = new Version ( 2 , 1 ) ;
2020-06-14 04:20:52 +00:00
#region Instance Properties
2018-10-23 23:34:49 +00:00
2020-06-14 04:20:52 +00:00
public string UUID
2017-02-26 19:23:31 +00:00
{
get
{
2020-06-14 04:20:52 +00:00
if ( String . IsNullOrWhiteSpace ( _uuid ) )
2020-08-18 22:16:04 +00:00
_uuid = Guid . NewGuid ( ) . ToString ( "D" ) ;
2020-06-14 04:20:52 +00:00
return _uuid ;
}
set
{
Match match = Regex . Match ( value , uuidV4Regex , RegexOptions . IgnoreCase ) ;
if ( match . Success )
_uuid = value ;
2017-02-26 19:23:31 +00:00
}
}
2018-10-20 00:13:40 +00:00
[JsonIgnore]
2021-06-22 09:05:24 +00:00
public virtual bool IsPossible
2017-02-26 19:23:31 +00:00
{
get
{
2021-02-28 08:24:12 +00:00
// Return the cached answer
return _isPossible ;
}
set
{
_isPossible = value ;
2020-10-22 09:05:15 +00:00
}
}
[JsonIgnore]
2021-06-22 09:05:24 +00:00
public virtual bool IsActive
2020-10-22 09:05:15 +00:00
{
get
{
if ( this . Equals ( ProfileRepository . CurrentProfile ) )
return true ;
else
return false ;
2020-07-24 09:46:53 +00:00
2017-02-26 19:23:31 +00:00
}
}
2021-09-07 09:26:42 +00:00
public virtual VIDEO_MODE VideoMode { get ; set ; } = VIDEO_MODE . WINDOWS ;
2021-06-22 09:05:24 +00:00
2021-04-28 10:14:54 +00:00
public Keys Hotkey {
2021-04-25 09:13:25 +00:00
get
{
return _hotkey ;
}
set
{
2021-04-28 10:14:54 +00:00
_hotkey = value ;
2021-04-25 09:13:25 +00:00
}
}
2021-06-22 09:05:24 +00:00
public virtual string Name { get ; set ; }
2017-02-26 19:23:31 +00:00
2021-09-07 09:26:42 +00:00
[JsonRequired]
public NVIDIA_DISPLAY_CONFIG NVIDIADisplayConfig
{
get
{
return _nvidiaDisplayConfig ;
}
set
{
_nvidiaDisplayConfig = value ;
}
}
[JsonRequired]
public AMD_DISPLAY_CONFIG AMDDisplayConfig
{
get
{
return _amdDisplayConfig ;
}
set
{
_amdDisplayConfig = value ;
}
}
[JsonRequired]
public WINDOWS_DISPLAY_CONFIG WindowsDisplayConfig
{
get
{
return _windowsDisplayConfig ;
}
set
{
_windowsDisplayConfig = value ;
}
}
2020-06-15 09:57:46 +00:00
[JsonIgnore]
2021-06-22 09:05:24 +00:00
public virtual ProfileIcon ProfileIcon
2020-05-09 13:02:07 +00:00
{
2020-05-12 10:46:23 +00:00
get
{
if ( _profileIcon ! = null )
return _profileIcon ;
else
{
_profileIcon = new ProfileIcon ( this ) ;
return _profileIcon ;
}
}
2020-05-09 13:02:07 +00:00
set
{
_profileIcon = value ;
}
}
2021-08-22 09:57:29 +00:00
[JsonIgnore]
2021-06-24 10:14:39 +00:00
public virtual List < ScreenPosition > Screens
{
get
{
2022-02-05 22:52:47 +00:00
if ( _screens . Count = = 0 & & ProfileRepository . ProfilesLoaded )
2021-06-24 10:14:39 +00:00
{
_screens = GetScreenPositions ( ) ;
}
return _screens ;
}
2021-06-27 01:53:00 +00:00
set
{
_screens = value ;
}
2021-06-24 10:14:39 +00:00
}
2020-06-14 04:20:52 +00:00
public string SavedProfileIconCacheFilename { get ; set ; }
2022-01-30 07:24:36 +00:00
2020-05-10 10:47:18 +00:00
2021-09-01 22:42:26 +00:00
public Wallpaper . Mode WallpaperMode { get ; set ; }
2021-08-27 09:15:53 +00:00
2021-08-27 10:26:12 +00:00
public Wallpaper . Style WallpaperStyle { get ; set ; }
2021-08-27 09:15:53 +00:00
public string WallpaperBitmapFilename {
get
{
return _wallpaperBitmapFilename ;
}
set
{
_wallpaperBitmapFilename = value ;
}
}
2021-06-22 09:05:24 +00:00
public virtual List < string > ProfileDisplayIdentifiers
2020-08-19 06:55:50 +00:00
{
get
{
if ( _profileDisplayIdentifiers . Count = = 0 )
{
2021-07-24 04:05:38 +00:00
_profileDisplayIdentifiers = ProfileRepository . GetCurrentDisplayIdentifiers ( ) ;
2020-08-19 06:55:50 +00:00
}
return _profileDisplayIdentifiers ;
}
set
{
if ( value is List < string > )
_profileDisplayIdentifiers = value ;
}
}
2021-08-22 09:45:51 +00:00
[JsonConverter(typeof(CustomBitmapConverter))]
2021-06-22 09:05:24 +00:00
public virtual Bitmap ProfileBitmap
2020-05-09 13:02:07 +00:00
{
2020-05-12 10:46:23 +00:00
get
{
if ( _profileBitmap ! = null )
return _profileBitmap ;
else
{
2020-06-07 08:48:45 +00:00
_profileBitmap = this . ProfileIcon . ToBitmap ( 256 , 256 ) ;
2020-05-12 10:46:23 +00:00
return _profileBitmap ;
}
}
2020-05-09 13:02:07 +00:00
set
{
_profileBitmap = value ;
}
2018-10-20 00:13:40 +00:00
}
2017-02-26 19:23:31 +00:00
2021-08-22 09:45:51 +00:00
[JsonConverter(typeof(CustomBitmapConverter))]
2021-06-27 01:53:00 +00:00
public virtual Bitmap ProfileTightestBitmap
2020-06-07 08:48:45 +00:00
{
get
{
2022-02-11 20:18:03 +00:00
if ( ProfileRepository . ProfilesLoaded )
{
if ( _profileShortcutBitmap ! = null )
return _profileShortcutBitmap ;
else
{
_profileShortcutBitmap = this . ProfileIcon . ToTightestBitmap ( ) ;
return _profileShortcutBitmap ;
}
}
2020-06-07 08:48:45 +00:00
else
{
2022-02-11 20:18:03 +00:00
return null ;
2020-06-07 08:48:45 +00:00
}
}
set
{
_profileShortcutBitmap = value ;
}
}
2020-06-14 04:20:52 +00:00
#endregion
2017-02-26 19:23:31 +00:00
2020-05-09 13:02:07 +00:00
public static bool IsValidName ( string testName )
{
2020-06-07 08:48:45 +00:00
foreach ( ProfileItem loadedProfile in _allSavedProfiles )
2020-05-09 13:02:07 +00:00
{
if ( loadedProfile . Name = = testName )
{
return false ;
}
}
return true ;
}
2020-06-15 09:57:46 +00:00
public static bool IsValidUUID ( string testId )
2020-05-09 13:02:07 +00:00
{
2020-06-14 04:20:52 +00:00
Match match = Regex . Match ( testId , uuidV4Regex , RegexOptions . IgnoreCase ) ;
if ( match . Success )
2020-05-10 10:47:18 +00:00
return true ;
2020-06-14 04:20:52 +00:00
else
return false ;
2020-05-10 10:47:18 +00:00
}
2021-09-07 09:26:42 +00:00
public bool IsValid ( )
2020-08-19 06:55:50 +00:00
{
2021-09-07 09:26:42 +00:00
if ( VideoMode = = VIDEO_MODE . NVIDIA )
{
if ( ! NVIDIALibrary . GetLibrary ( ) . IsValidConfig ( _nvidiaDisplayConfig ) )
{
2021-12-16 22:53:23 +00:00
SharedLogger . logger . Error ( $"ProfileItem/IsValid: The profile {Name} has an invalid NVIDIA display config" ) ;
2021-09-07 09:26:42 +00:00
return false ;
}
}
else if ( VideoMode = = VIDEO_MODE . AMD )
{
if ( ! AMDLibrary . GetLibrary ( ) . IsValidConfig ( _amdDisplayConfig ) )
{
2021-12-16 22:53:23 +00:00
SharedLogger . logger . Error ( $"ProfileItem/IsValid: The profile {Name} has an invalid AMD display config" ) ;
2021-09-07 09:26:42 +00:00
return false ;
}
}
else if ( VideoMode = = VIDEO_MODE . WINDOWS )
{
if ( ! WinLibrary . GetLibrary ( ) . IsValidConfig ( _windowsDisplayConfig ) )
{
2021-12-16 22:53:23 +00:00
SharedLogger . logger . Error ( $"ProfileItem/IsValid: The profile {Name} has an invalid Windows CCD display config" ) ;
2021-09-07 09:26:42 +00:00
return false ;
}
}
else
{
2021-12-16 22:53:23 +00:00
SharedLogger . logger . Error ( $"ProfileItem/IsValid: The profile {Name} has an unknown video mode!" ) ;
2021-09-07 09:26:42 +00:00
}
// The rest of the
if ( ProfileIcon is ProfileIcon & &
System . IO . File . Exists ( SavedProfileIconCacheFilename ) & &
ProfileBitmap is Bitmap & &
ProfileTightestBitmap is Bitmap & &
ProfileDisplayIdentifiers . Count > 0 )
return true ;
else
return false ;
2020-08-19 06:55:50 +00:00
}
2018-10-20 00:27:25 +00:00
2021-09-07 09:26:42 +00:00
2020-09-18 10:52:18 +00:00
2021-06-22 09:05:24 +00:00
public virtual bool CopyTo ( ProfileItem profile , bool overwriteId = true )
2020-06-14 04:20:52 +00:00
{
2020-06-15 09:57:46 +00:00
if ( overwriteId = = true )
2020-06-14 04:20:52 +00:00
profile . UUID = UUID ;
// Copy all our profile data over to the other profile
profile . Name = Name ;
2021-09-07 09:26:42 +00:00
profile . AMDDisplayConfig = AMDDisplayConfig ;
profile . NVIDIADisplayConfig = NVIDIADisplayConfig ;
profile . WindowsDisplayConfig = WindowsDisplayConfig ;
2020-06-14 04:20:52 +00:00
profile . ProfileIcon = ProfileIcon ;
profile . SavedProfileIconCacheFilename = SavedProfileIconCacheFilename ;
profile . ProfileBitmap = ProfileBitmap ;
profile . ProfileTightestBitmap = ProfileTightestBitmap ;
2020-08-19 06:55:50 +00:00
profile . ProfileDisplayIdentifiers = ProfileDisplayIdentifiers ;
2021-09-01 22:42:26 +00:00
profile . WallpaperMode = WallpaperMode ;
2021-08-27 09:15:53 +00:00
profile . WallpaperBitmapFilename = WallpaperBitmapFilename ;
2021-08-27 10:26:12 +00:00
profile . WallpaperStyle = WallpaperStyle ;
2020-06-14 04:20:52 +00:00
return true ;
2017-02-26 19:23:31 +00:00
}
2021-06-22 09:05:24 +00:00
public virtual bool PreSave ( )
2020-08-19 06:55:50 +00:00
{
// Prepare our profile data for saving
2021-10-30 23:50:57 +00:00
// Disabling as this should never happen now
/ * if ( _profileDisplayIdentifiers . Count = = 0 )
2020-08-19 06:55:50 +00:00
{
2021-07-24 04:05:38 +00:00
_profileDisplayIdentifiers = ProfileRepository . GetCurrentDisplayIdentifiers ( ) ;
2021-10-30 23:50:57 +00:00
} * /
2020-08-19 06:55:50 +00:00
// Return if it is valid and we should continue
return IsValid ( ) ;
}
2020-05-13 11:04:18 +00:00
2021-09-07 09:26:42 +00:00
public bool CreateProfileFromCurrentDisplaySettings ( )
2021-06-26 09:54:11 +00:00
{
2021-10-24 08:29:53 +00:00
// Calling the 3 different libraries automatically gets the different configs from each of the 3 video libraries.
// If the video library isn't in use then it also fills in the defaults so that the JSON file can save properly
2021-09-19 08:56:58 +00:00
// (C# Structs populate with default values which mean that arrays start with null)
2021-10-24 08:29:53 +00:00
try
2022-01-10 08:06:02 +00:00
{
//await Program.AppBackgroundTaskSemaphoreSlim.WaitAsync(0);
2021-10-24 08:29:53 +00:00
NVIDIALibrary nvidiaLibrary = NVIDIALibrary . GetLibrary ( ) ;
AMDLibrary amdLibrary = AMDLibrary . GetLibrary ( ) ;
WinLibrary winLibrary = WinLibrary . GetLibrary ( ) ;
2021-09-07 09:26:42 +00:00
2021-10-24 08:34:43 +00:00
// For a library update to the latest version so that we pick up any new changes since the last update
2021-10-29 09:10:29 +00:00
if ( VideoMode = = VIDEO_MODE . NVIDIA & & nvidiaLibrary . IsInstalled )
{
nvidiaLibrary . UpdateActiveConfig ( ) ;
winLibrary . UpdateActiveConfig ( ) ;
}
else if ( VideoMode = = VIDEO_MODE . AMD & & amdLibrary . IsInstalled )
{
amdLibrary . UpdateActiveConfig ( ) ;
winLibrary . UpdateActiveConfig ( ) ;
}
else
{
winLibrary . UpdateActiveConfig ( ) ;
}
2021-10-24 08:34:43 +00:00
// Grab the profile data from the current stored config (that we just updated)
2021-10-24 08:29:53 +00:00
_nvidiaDisplayConfig = nvidiaLibrary . ActiveDisplayConfig ;
_amdDisplayConfig = amdLibrary . ActiveDisplayConfig ;
_windowsDisplayConfig = winLibrary . ActiveDisplayConfig ;
_profileDisplayIdentifiers = nvidiaLibrary . CurrentDisplayIdentifiers ;
2021-09-07 09:26:42 +00:00
2021-10-24 08:29:53 +00:00
// Now, since the ActiveProfile has changed, we need to regenerate screen positions
_screens = GetScreenPositions ( ) ;
2021-09-07 09:26:42 +00:00
2021-10-24 08:29:53 +00:00
return true ;
2021-09-07 09:26:42 +00:00
}
2021-10-24 08:29:53 +00:00
catch ( Exception ex )
2021-09-07 09:26:42 +00:00
{
2021-12-16 22:53:23 +00:00
SharedLogger . logger . Error ( ex , $"ProfileItem/CreateProfileFromCurrentDisplaySettings: Exception getting the config settings!" ) ;
2021-09-07 09:26:42 +00:00
return false ;
}
2021-06-26 09:54:11 +00:00
}
2021-03-07 01:50:52 +00:00
// ReSharper disable once FunctionComplexityOverflow
// ReSharper disable once CyclomaticComplexity
public bool CreateShortcut ( string shortcutFileName )
{
string shortcutDescription = string . Empty ;
string shortcutIconFileName ;
var shortcutArgs = new List < string >
{
// Add the SwitchProfile command as the first argument to start to switch to another profile
$"{DisplayMagicianStartupAction.ChangeProfile}" ,
$"\" { UUID } \ ""
} ;
// Prepare text for the shortcut description field
shortcutDescription = $"Change to the '{Name}' DisplayMagician Display Profile." ;
// Now we are ready to create a shortcut based on the filename the user gave us
shortcutFileName = System . IO . Path . ChangeExtension ( shortcutFileName , @"lnk" ) ;
// And we use the Icon from the shortcutIconCache
shortcutIconFileName = SavedProfileIconCacheFilename ;
// If the user supplied a file
if ( shortcutFileName ! = null )
{
try
{
// Remove the old file if it exists to replace it
if ( System . IO . File . Exists ( shortcutFileName ) )
{
System . IO . File . Delete ( shortcutFileName ) ;
}
// Actually create the shortcut!
//var wshShellType = Type.GetTypeFromCLSID(new Guid("72C24DD5-D70A-438B-8A42-98424B88AFB8"));
//dynamic wshShell = Activator.CreateInstance(wshShellType);
WshShell shell = new WshShell ( ) ;
IWshShortcut shortcut = ( IWshShortcut ) shell . CreateShortcut ( shortcutFileName ) ;
shortcut . TargetPath = Application . ExecutablePath ;
shortcut . Arguments = string . Join ( " " , shortcutArgs ) ;
shortcut . Description = shortcutDescription ;
shortcut . WorkingDirectory = System . IO . Path . GetDirectoryName ( Application . ExecutablePath ) ? ?
string . Empty ;
shortcut . IconLocation = shortcutIconFileName ;
shortcut . Save ( ) ;
}
catch ( Exception ex )
{
2021-12-16 22:53:23 +00:00
SharedLogger . logger . Warn ( ex , $"ProfileItem/CreateShortcut: Execption while creating desktop shortcut!" ) ;
2021-03-07 01:50:52 +00:00
// Clean up a failed attempt
if ( System . IO . File . Exists ( shortcutFileName ) )
{
System . IO . File . Delete ( shortcutFileName ) ;
}
}
}
// Return a status on how it went
// true if it was a success or false if it was not
return shortcutFileName ! = null & & System . IO . File . Exists ( shortcutFileName ) ;
}
2021-06-27 02:44:10 +00:00
public virtual void RefreshPossbility ( )
2021-03-07 04:11:46 +00:00
{
2021-09-18 09:55:43 +00:00
// Check whether this profile is the same as the video mode, otherwise it's not possible
if ( ProfileRepository . CurrentVideoMode ! = VideoMode )
{
2021-12-16 22:53:23 +00:00
SharedLogger . logger . Debug ( $"ProfileItem/IsPossibleRefresh: The NVIDIA profile {Name} is NOT possible!" ) ;
2021-09-18 09:55:43 +00:00
_isPossible = false ;
return ;
}
// Otherwise actually check the possibility
2021-09-07 09:26:42 +00:00
if ( ProfileRepository . CurrentVideoMode = = VIDEO_MODE . NVIDIA & & NVIDIALibrary . GetLibrary ( ) . IsInstalled )
{
if ( NVIDIALibrary . GetLibrary ( ) . IsPossibleConfig ( _nvidiaDisplayConfig ) )
{
2021-04-04 06:59:38 +00:00
2021-12-16 22:53:23 +00:00
SharedLogger . logger . Debug ( $"ProfileItem/IsPossibleRefresh: The NVIDIA profile {Name} is possible!" ) ;
2021-09-07 09:26:42 +00:00
_isPossible = true ;
2021-05-19 09:32:49 +00:00
2021-09-07 09:26:42 +00:00
}
else
{
2021-12-16 22:53:23 +00:00
SharedLogger . logger . Debug ( $"ProfileItem/IsPossibleRefresh: The NVIDIA profile {Name} is NOT possible!" ) ;
2021-09-07 09:26:42 +00:00
_isPossible = false ;
}
}
else if ( ProfileRepository . CurrentVideoMode = = VIDEO_MODE . AMD & & AMDLibrary . GetLibrary ( ) . IsInstalled )
2021-03-07 04:11:46 +00:00
{
2021-09-07 09:26:42 +00:00
if ( AMDLibrary . GetLibrary ( ) . IsPossibleConfig ( _amdDisplayConfig ) )
2021-05-19 09:32:49 +00:00
{
2021-09-07 09:26:42 +00:00
2021-12-16 22:53:23 +00:00
SharedLogger . logger . Debug ( $"ProfileItem/IsPossibleRefresh: The AMD profile {Name} is possible!" ) ;
2021-09-07 09:26:42 +00:00
_isPossible = true ;
2021-05-19 09:32:49 +00:00
}
else
{
2021-12-16 22:53:23 +00:00
SharedLogger . logger . Debug ( $"ProfileItem/IsPossibleRefresh: The AMD profile {Name} is NOT possible!" ) ;
2021-09-07 09:26:42 +00:00
_isPossible = false ;
2021-05-19 09:32:49 +00:00
}
2021-03-07 04:11:46 +00:00
}
2021-09-07 09:26:42 +00:00
else if ( ProfileRepository . CurrentVideoMode = = VIDEO_MODE . WINDOWS & & WinLibrary . GetLibrary ( ) . IsInstalled )
2021-03-07 04:11:46 +00:00
{
2021-09-07 09:26:42 +00:00
if ( WinLibrary . GetLibrary ( ) . IsPossibleConfig ( _windowsDisplayConfig ) )
{
2021-12-16 22:53:23 +00:00
SharedLogger . logger . Debug ( $"ProfileItem/IsPossibleRefresh: The Windows CCD profile {Name} is possible!" ) ;
2021-09-07 09:26:42 +00:00
_isPossible = true ;
2021-03-27 03:15:17 +00:00
2021-09-07 09:26:42 +00:00
}
else
{
2021-12-16 22:53:23 +00:00
SharedLogger . logger . Debug ( $"ProfileItem/IsPossibleRefresh: The Windows CCD profile {Name} is NOT possible!" ) ;
2021-09-07 09:26:42 +00:00
_isPossible = false ;
}
2021-03-07 04:11:46 +00:00
}
else
{
2021-12-16 22:53:23 +00:00
SharedLogger . logger . Warn ( $"ProfileItem/IsPossibleRefresh: We have a current video mode we don't understand, or it's not installed! The current video mode is {ProfileRepository.CurrentVideoMode}. The profile {Name} has a {VideoMode.ToString(" G ")} video mode and NVIDIALibrary IsInstalled is {NVIDIALibrary.GetLibrary().IsInstalled}, AMDLibrary IsInstalled is {AMDLibrary.GetLibrary().IsInstalled} and WinLibrary IsInstalled is {WinLibrary.GetLibrary().IsInstalled} " ) ;
2021-03-07 04:11:46 +00:00
_isPossible = false ;
}
}
2021-06-24 10:14:39 +00:00
2021-08-24 10:46:32 +00:00
// Actually set this profile active
2021-09-07 09:26:42 +00:00
public bool SetActive ( )
2021-08-24 10:46:32 +00:00
{
2021-09-19 08:56:58 +00:00
if ( VideoMode = = VIDEO_MODE . NVIDIA & & NVIDIALibrary . GetLibrary ( ) . IsInstalled )
2021-09-07 09:26:42 +00:00
{
NVIDIALibrary nvidiaLibrary = NVIDIALibrary . GetLibrary ( ) ;
WinLibrary winLibrary = WinLibrary . GetLibrary ( ) ;
if ( nvidiaLibrary . IsInstalled )
{
2021-10-24 08:29:53 +00:00
if ( ! winLibrary . IsActiveConfig ( _windowsDisplayConfig ) | | ! nvidiaLibrary . IsActiveConfig ( _nvidiaDisplayConfig ) )
2021-09-07 09:26:42 +00:00
{
if ( nvidiaLibrary . IsPossibleConfig ( _nvidiaDisplayConfig ) )
{
2021-12-16 22:53:23 +00:00
SharedLogger . logger . Trace ( $"ProfileItem/SetActive: The NVIDIA display settings within profile {Name} are possible to use right now, so we'll use attempt to use them." ) ;
2021-09-07 09:26:42 +00:00
bool itWorkedforNVIDIA = nvidiaLibrary . SetActiveConfig ( _nvidiaDisplayConfig ) ;
if ( itWorkedforNVIDIA )
{
2021-12-16 22:53:23 +00:00
SharedLogger . logger . Trace ( $"ProfileItem/SetActive: The NVIDIA display settings within profile {Name} were successfully applied." ) ;
2021-09-08 08:04:37 +00:00
2021-12-16 22:53:23 +00:00
/ * SharedLogger . logger . Trace ( $"ProfileItem/SetActive: Waiting 0.5 seconds to let the NVIDIA display change take place before setting the Windows CCD display settings" ) ;
2021-12-10 11:15:49 +00:00
System . Threading . Thread . Sleep ( 500 ) ; * /
2021-09-08 08:04:37 +00:00
2021-12-08 08:43:22 +00:00
// Lets update the screens so Windows knows whats happening
// NVIDIA makes such large changes to the available screens in windows, we need to do this.
winLibrary . UpdateActiveConfig ( ) ;
2022-01-30 07:24:36 +00:00
2021-09-07 09:26:42 +00:00
// 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,
2022-01-30 07:24:36 +00:00
// or if the display config we want to change to is a Mosaic config. So we just have to assume that it will work
2021-09-07 09:26:42 +00:00
bool itWorkedforWindows = winLibrary . SetActiveConfig ( _windowsDisplayConfig ) ;
if ( itWorkedforWindows )
{
2021-10-09 06:58:22 +00:00
bool itWorkedforNVIDIAColor = nvidiaLibrary . SetActiveConfigOverride ( _nvidiaDisplayConfig ) ;
2021-10-07 08:15:14 +00:00
if ( itWorkedforNVIDIAColor )
{
2021-12-16 22:53:23 +00:00
SharedLogger . logger . Trace ( $"ProfileItem/SetActive: The NVIDIA display settings that override windows within the profile {Name} were successfully applied." ) ;
2021-10-07 08:15:14 +00:00
return true ;
}
else
{
2021-12-16 22:53:23 +00:00
SharedLogger . logger . Trace ( $"ProfileItem/SetActive: The NVIDIA display settings that override windows within the profile {Name} were NOT applied correctly." ) ;
2021-10-07 08:15:14 +00:00
}
2021-09-07 09:26:42 +00:00
}
else
{
2021-12-16 22:53:23 +00:00
SharedLogger . logger . Trace ( $"ProfileItem/SetActive: The Windows CCD display settings within profile {Name} were NOT applied correctly." ) ;
2021-09-07 09:26:42 +00:00
}
}
else
{
2021-12-16 22:53:23 +00:00
SharedLogger . logger . Trace ( $"ProfileItem/SetActive: The NVIDIA display settings within profile {Name} were NOT applied correctly." ) ;
2021-09-07 09:26:42 +00:00
}
}
else
{
2021-12-16 22:53:23 +00:00
SharedLogger . logger . Error ( $"ProfileItem/SetActive: ERROR - Cannot apply the NVIDIA display config in profile {Name} as it is not currently possible to use it." ) ;
2021-09-07 09:26:42 +00:00
}
}
else
{
2021-12-16 22:53:23 +00:00
SharedLogger . logger . Info ( $"ProfileItem/SetActive: The display settings in profile {Name} are already installed. No need to install them again. Exiting." ) ;
2021-09-07 09:26:42 +00:00
}
}
}
2021-09-19 08:56:58 +00:00
else if ( VideoMode = = VIDEO_MODE . AMD & & AMDLibrary . GetLibrary ( ) . IsInstalled )
2021-09-07 09:26:42 +00:00
{
AMDLibrary amdLibrary = AMDLibrary . GetLibrary ( ) ;
WinLibrary winLibrary = WinLibrary . GetLibrary ( ) ;
if ( amdLibrary . IsInstalled )
{
2021-10-24 08:29:53 +00:00
if ( ! winLibrary . IsActiveConfig ( _windowsDisplayConfig ) | | ! amdLibrary . IsActiveConfig ( _amdDisplayConfig ) )
2021-09-07 09:26:42 +00:00
{
if ( amdLibrary . IsPossibleConfig ( _amdDisplayConfig ) )
{
2021-12-16 22:53:23 +00:00
SharedLogger . logger . Trace ( $"ProfileItem/SetActive: The AMD display settings within profile {Name} are possible to use right now, so we'll use attempt to use them." ) ;
2021-12-08 08:43:22 +00:00
bool itWorkedforAMD = amdLibrary . SetActiveConfig ( _amdDisplayConfig ) ;
2021-09-07 09:26:42 +00:00
2021-12-08 08:43:22 +00:00
if ( itWorkedforAMD )
2021-09-07 09:26:42 +00:00
{
2021-12-16 22:53:23 +00:00
SharedLogger . logger . Trace ( $"ProfileItem/SetActive: The AMD display settings within profile {Name} were successfully applied." ) ;
2021-09-08 08:04:37 +00:00
2021-12-16 22:53:23 +00:00
/ * SharedLogger . logger . Trace ( $"ProfileItem/SetActive: Waiting 0.5 seconds to let the AMD display change take place before setting the Windows CCD display settings" ) ;
2021-09-08 08:04:37 +00:00
System . Threading . Thread . Sleep ( 500 ) ;
2021-12-10 11:15:49 +00:00
* /
2021-12-08 08:43:22 +00:00
// Lets update the screens so Windows knows whats happening
2021-12-10 11:15:49 +00:00
// AMD makes such large changes to the available screens in windows, we need to do this.
2021-12-08 08:43:22 +00:00
winLibrary . UpdateActiveConfig ( ) ;
2021-09-07 09:26:42 +00:00
// Then let's try to also apply the windows changes
2021-12-10 11:15:49 +00:00
// 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 an Eyefinity config,
// or if the display config we want to change to is an Eyefinity config. So we just have to assume that it will work!
2021-09-07 09:26:42 +00:00
bool itWorkedforWindows = winLibrary . SetActiveConfig ( _windowsDisplayConfig ) ;
if ( itWorkedforWindows )
{
2021-10-09 06:58:22 +00:00
bool itWorkedforAMDColor = amdLibrary . SetActiveConfigOverride ( _amdDisplayConfig ) ;
2021-10-07 08:15:14 +00:00
if ( itWorkedforAMDColor )
{
2021-12-16 22:53:23 +00:00
SharedLogger . logger . Trace ( $"ProfileItem/SetActive: The AMD display settings that override windows within the profile {Name} were successfully applied." ) ;
2021-10-07 08:15:14 +00:00
return true ;
}
else
{
2021-12-16 22:53:23 +00:00
SharedLogger . logger . Trace ( $"ProfileItem/SetActive: The AMD display settings that override windows within the profile {Name} were NOT applied correctly." ) ;
2021-10-07 08:15:14 +00:00
}
2021-09-07 09:26:42 +00:00
}
else
{
2021-12-16 22:53:23 +00:00
SharedLogger . logger . Trace ( $"ProfileItem/SetActive: The Windows CCD display settings within profile {Name} were NOT applied correctly." ) ;
2021-09-07 09:26:42 +00:00
}
}
else
{
2021-12-16 22:53:23 +00:00
SharedLogger . logger . Trace ( $"ProfileItem/SetActive: The AMD display settings within profile {Name} were NOT applied correctly." ) ;
2021-09-07 09:26:42 +00:00
}
}
else
{
2021-12-16 22:53:23 +00:00
SharedLogger . logger . Error ( $"ProfileItem/SetActive: ERROR - Cannot apply the AMD display config in profile {Name} as it is not currently possible to use it." ) ;
2021-09-07 09:26:42 +00:00
}
}
else
{
2021-12-16 22:53:23 +00:00
SharedLogger . logger . Info ( $"ProfileItem/SetActive: The display settings in profile {Name} are already installed. No need to install them again. Exiting." ) ;
2021-09-07 09:26:42 +00:00
}
}
}
else if ( VideoMode = = VIDEO_MODE . WINDOWS )
{
WinLibrary winLibrary = WinLibrary . GetLibrary ( ) ;
if ( winLibrary . IsInstalled )
{
if ( ! winLibrary . IsActiveConfig ( _windowsDisplayConfig ) )
{
if ( winLibrary . SetActiveConfig ( _windowsDisplayConfig ) )
{
2021-12-16 22:53:23 +00:00
SharedLogger . logger . Trace ( $"ProfileItem/SetActive: The Windows CCD display settings within profile {Name} were successfully applied." ) ;
2021-09-07 09:26:42 +00:00
return true ;
}
else
{
2021-12-16 22:53:23 +00:00
SharedLogger . logger . Trace ( $"ProfileItem/SetActive: The Windows CCD display settings within profile {Name} were NOT applied correctly." ) ;
2021-09-07 09:26:42 +00:00
}
}
else
{
2021-12-16 22:53:23 +00:00
SharedLogger . logger . Info ( $"ProfileItem/SetActive: The display settings in profile {Name} are already installed. No need to install them again. Exiting." ) ;
2021-09-07 09:26:42 +00:00
}
}
}
2021-08-24 10:46:32 +00:00
return false ;
}
2021-09-07 09:26:42 +00:00
public List < ScreenPosition > GetScreenPositions ( )
2021-06-24 10:14:39 +00:00
{
2021-09-07 09:26:42 +00:00
if ( VideoMode = = VIDEO_MODE . NVIDIA )
{
return GetNVIDIAScreenPositions ( ) ;
}
else if ( VideoMode = = VIDEO_MODE . AMD )
{
return GetAMDScreenPositions ( ) ;
}
else if ( VideoMode = = VIDEO_MODE . WINDOWS )
{
return GetWindowsScreenPositions ( ) ;
}
2021-06-24 10:14:39 +00:00
return new List < ScreenPosition > ( ) ;
2022-02-07 01:43:20 +00:00
}
2021-09-07 09:26:42 +00:00
private List < ScreenPosition > GetNVIDIAScreenPositions ( )
{
// Set up some colours
Color primaryScreenColor = Color . FromArgb ( 0 , 174 , 241 ) ; // represents Primary screen blue
Color spannedScreenColor = Color . FromArgb ( 118 , 185 , 0 ) ; // represents NVIDIA Green
Color normalScreenColor = Color . FromArgb ( 155 , 155 , 155 ) ; // represents normal screen colour (gray)
// Now we create the screens structure from the AMD profile information
_screens = new List < ScreenPosition > ( ) ;
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-12-16 22:53:23 +00:00
// Now we need to check for Spanned screens (Surround)
2022-02-06 00:47:30 +00:00
if ( _nvidiaDisplayConfig . MosaicConfig . MosaicGridCount > 0 )
2021-09-07 09:26:42 +00:00
{
2022-02-06 00:47:30 +00:00
for ( int i = 0 ; i < _nvidiaDisplayConfig . MosaicConfig . MosaicGridCount ; i + + )
2021-09-07 09:26:42 +00:00
{
2022-02-06 00:47:30 +00:00
if ( _nvidiaDisplayConfig . MosaicConfig . IsMosaicEnabled )
2021-09-07 09:26:42 +00:00
{
2022-02-06 00:47:30 +00:00
ScreenPosition screen = new ScreenPosition ( ) ;
screen . Library = "NVIDIA" ;
if ( _nvidiaDisplayConfig . MosaicConfig . MosaicGridTopos [ i ] . DisplayCount > 1 )
2021-09-07 09:26:42 +00:00
{
2022-02-06 00:47:30 +00:00
// It's a spanned screen!
// Set some basics about the screen
screen . SpannedScreens = new List < SpannedScreenPosition > ( ) ;
screen . Name = "NVIDIA Surround/Mosaic" ;
screen . IsSpanned = true ;
screen . SpannedRows = ( int ) _nvidiaDisplayConfig . MosaicConfig . MosaicGridTopos [ i ] . Rows ;
screen . SpannedColumns = ( int ) _nvidiaDisplayConfig . MosaicConfig . MosaicGridTopos [ i ] . Columns ;
screen . Colour = spannedScreenColor ;
// This is a combined surround/mosaic screen
// We need to build the size of the screen to match it later so we check the MosaicViewports
uint minX = 0 ;
uint minY = 0 ;
uint maxX = 0 ;
uint maxY = 0 ;
uint overallX = 0 ;
uint overallY = 0 ;
int overallWidth = 0 ;
int overallHeight = 0 ;
for ( int j = 0 ; j < _nvidiaDisplayConfig . MosaicConfig . MosaicGridTopos [ i ] . DisplayCount ; j + + )
2021-09-07 09:26:42 +00:00
{
2022-02-06 00:47:30 +00:00
SpannedScreenPosition spannedScreen = new SpannedScreenPosition ( ) ;
spannedScreen . Name = _nvidiaDisplayConfig . MosaicConfig . MosaicGridTopos [ i ] . Displays [ j ] . DisplayId . ToString ( ) ;
spannedScreen . Colour = spannedScreenColor ;
2021-09-07 09:26:42 +00:00
2022-02-06 00:47:30 +00:00
// Calculate screen size
NV_RECT viewRect = _nvidiaDisplayConfig . MosaicConfig . MosaicViewports [ i ] [ j ] ;
if ( viewRect . Left < minX )
{
minX = viewRect . Left ;
}
if ( viewRect . Top < minY )
{
minY = viewRect . Top ;
}
if ( viewRect . Right > maxX )
{
maxX = viewRect . Right ;
}
if ( viewRect . Bottom > maxY )
{
maxY = viewRect . Bottom ;
}
uint width = viewRect . Right - viewRect . Left + 1 ;
uint height = viewRect . Bottom - viewRect . Top + 1 ;
spannedScreen . ScreenX = ( int ) viewRect . Left ;
spannedScreen . ScreenY = ( int ) viewRect . Top ;
spannedScreen . ScreenWidth = ( int ) width ;
spannedScreen . ScreenHeight = ( int ) height ;
// Figure out the overall figures for the screen
if ( viewRect . Left < overallX )
{
overallX = viewRect . Left ;
}
if ( viewRect . Top < overallY )
{
overallY = viewRect . Top ;
}
2021-09-07 09:26:42 +00:00
2022-02-06 00:47:30 +00:00
overallWidth = ( int ) maxX - ( int ) minX + 1 ;
overallHeight = ( int ) maxY - ( int ) minY + 1 ;
2021-09-07 09:26:42 +00:00
2022-02-06 00:47:30 +00:00
spannedScreen . Row = i + 1 ;
spannedScreen . Column = j + 1 ;
2022-02-05 22:52:47 +00:00
2022-02-06 00:47:30 +00:00
// Add the spanned screen to the screen
screen . SpannedScreens . Add ( spannedScreen ) ;
2021-09-07 09:26:42 +00:00
2022-02-06 00:47:30 +00:00
}
// Need to look for the Windows layout details now we know the size of this display
// Set some basics about the screen
try
2021-10-28 07:57:16 +00:00
{
2022-03-25 08:51:38 +00:00
UInt32 displayId = _nvidiaDisplayConfig . MosaicConfig . MosaicGridTopos [ i ] . Displays [ 0 ] . DisplayId ;
List < NV_DISPLAYCONFIG_PATH_INFO_V2 > displaySources = _nvidiaDisplayConfig . DisplayConfigs ;
2022-04-13 10:48:32 +00:00
bool breakOuterLoop = false ;
2022-03-25 08:51:38 +00:00
foreach ( var displaySource in displaySources )
2021-10-28 07:57:16 +00:00
{
2022-04-13 10:48:32 +00:00
foreach ( NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2 targetInfo in displaySource . TargetInfo )
{
if ( targetInfo . DisplayId = = displayId )
{
screen . Name = displayId . ToString ( ) ;
screen . ScreenX = displaySource . SourceModeInfo . Position . X ;
screen . ScreenY = displaySource . SourceModeInfo . Position . Y ;
screen . ScreenWidth = ( int ) displaySource . SourceModeInfo . Resolution . Width ;
screen . ScreenHeight = ( int ) displaySource . SourceModeInfo . Resolution . Height ;
breakOuterLoop = true ;
break ;
}
}
2022-03-25 08:51:38 +00:00
2022-04-13 10:48:32 +00:00
if ( breakOuterLoop )
{
break ;
}
2021-10-28 07:57:16 +00:00
}
}
2022-02-06 00:47:30 +00:00
catch ( KeyNotFoundException ex )
{
// Thrown if the Windows display doesn't match the NVIDIA display.
// Typically happens during configuration of a new Mosaic mode.
// If we hit this issue, then we just want to skip over it, as we can update it later when the user pushes the button.
// This only happens due to the auto detection stuff functionality we have built in to try and update as quickly as we can.
// So its something that we can safely ignore if we hit this exception as it is part of the expect behaviour
continue ;
}
catch ( Exception ex )
{
// Some other exception has occurred and we need to report it.
//screen.Name = targetId.ToString();
//screen.DisplayConnector = displayMode.DisplayConnector;
screen . ScreenX = ( int ) overallX ;
screen . ScreenY = ( int ) overallY ;
screen . ScreenWidth = ( int ) overallWidth ;
screen . ScreenHeight = ( int ) overallHeight ;
}
2021-10-28 07:57:16 +00:00
}
2022-02-06 00:47:30 +00:00
else
2021-09-07 09:26:42 +00:00
{
2022-02-06 00:47:30 +00:00
// It's a standalone screen
screen . SpannedScreens = new List < SpannedScreenPosition > ( ) ;
screen . Name = _nvidiaDisplayConfig . MosaicConfig . MosaicGridTopos [ i ] . Displays [ 0 ] . DisplayId . ToString ( ) ;
screen . IsSpanned = false ;
screen . SpannedRows = 1 ;
screen . SpannedColumns = 1 ;
screen . Colour = normalScreenColor ;
try
2021-09-07 09:26:42 +00:00
{
2022-04-13 10:48:32 +00:00
UInt32 displayId = _nvidiaDisplayConfig . MosaicConfig . MosaicGridTopos [ i ] . Displays [ 0 ] . DisplayId ;
2022-03-25 08:51:38 +00:00
List < NV_DISPLAYCONFIG_PATH_INFO_V2 > displaySources = _nvidiaDisplayConfig . DisplayConfigs ;
2022-04-13 10:48:32 +00:00
bool breakOuterLoop = false ;
2022-03-25 08:51:38 +00:00
foreach ( var displaySource in displaySources )
2022-02-05 22:52:47 +00:00
{
2022-04-13 10:48:32 +00:00
foreach ( NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2 targetInfo in displaySource . TargetInfo )
{
if ( targetInfo . DisplayId = = displayId )
{
screen . Name = displayId . ToString ( ) ;
screen . ScreenX = displaySource . SourceModeInfo . Position . X ;
screen . ScreenY = displaySource . SourceModeInfo . Position . Y ;
screen . ScreenWidth = ( int ) displaySource . SourceModeInfo . Resolution . Width ;
screen . ScreenHeight = ( int ) displaySource . SourceModeInfo . Resolution . Height ;
breakOuterLoop = true ;
break ;
}
}
2021-12-16 23:25:02 +00:00
2022-04-13 10:48:32 +00:00
if ( breakOuterLoop )
{
break ;
}
2022-02-05 22:52:47 +00:00
}
2021-10-16 21:44:03 +00:00
}
2022-02-06 00:47:30 +00:00
catch ( KeyNotFoundException ex )
{
// Thrown if the Windows display doesn't match the NVIDIA display.
// Typically happens during configuration of a new Mosaic mode.
// If we hit this issue, then we just want to skip over it, as we can update it later when the user pushes the button.
// This only happens due to the auto detection stuff functionality we have built in to try and update as quickly as we can.
// So its something that we can safely ignore if we hit this exception as it is part of the expect behaviour
continue ;
}
catch ( Exception ex )
{
// Some other exception has occurred and we need to report it.
SharedLogger . logger . Error ( ex , $"ProfileItem/GetNVIDIAScreenPositions: Unable to get the non-mosaic screen size from the Windows Display Config" ) ;
}
2021-10-16 21:44:03 +00:00
}
2022-02-06 00:47:30 +00:00
// If we're at the 0,0 coordinate then we're the primary monitor
if ( screen . ScreenX = = 0 & & screen . ScreenY = = 0 )
2022-02-05 22:52:47 +00:00
{
2022-02-06 00:47:30 +00:00
// Record we're primary screen
screen . IsPrimary = true ;
// Change the colour to be the primary colour, but only if it isn't a surround screen
if ( screen . Colour ! = spannedScreenColor )
{
screen . Colour = primaryScreenColor ;
}
2021-09-07 09:26:42 +00:00
}
2022-02-06 00:47:30 +00:00
// Force the taskbar edge to the bottom as it is an NVIDIA surround screen
2022-03-25 08:51:38 +00:00
screen . TaskBarEdge = TaskBarLayout . TaskBarEdge . Bottom ;
2021-12-16 22:53:23 +00:00
2022-02-06 00:47:30 +00:00
SharedLogger . logger . Trace ( $"ProfileItem/GetNVIDIAScreenPositions: Added a new NVIDIA Spanned Screen {screen.Name} ({screen.ScreenWidth}x{screen.ScreenHeight}) at position {screen.ScreenX},{screen.ScreenY}." ) ;
_screens . Add ( screen ) ;
}
else
2021-12-16 22:53:23 +00:00
{
2022-02-06 00:47:30 +00:00
// If mosaic isn't enabled then we fall back to the windows display config
2022-04-13 10:48:32 +00:00
/ * _screens = GetWindowsScreenPositions ( ) ;
2022-02-06 00:47:30 +00:00
for ( int s = 0 ; s < _screens . Count ; s + + )
2021-09-07 09:26:42 +00:00
{
2022-02-06 00:47:30 +00:00
ScreenPosition sp = _screens . ElementAt ( s ) ;
sp . Library = "NVIDIA" ;
2022-04-13 10:48:32 +00:00
} * /
try
{
List < NV_DISPLAYCONFIG_PATH_INFO_V2 > displaySources = _nvidiaDisplayConfig . DisplayConfigs ;
foreach ( var displaySource in displaySources )
{
foreach ( NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2 targetInfo in displaySource . TargetInfo )
{
ScreenPosition screen = new ScreenPosition ( ) ;
screen . Library = "NVIDIA" ;
// It's a normal screen
screen . SpannedScreens = new List < SpannedScreenPosition > ( ) ;
screen . Name = targetInfo . DisplayId . ToString ( ) ;
screen . IsSpanned = false ;
screen . SpannedRows = 1 ;
screen . SpannedColumns = 1 ;
screen . Colour = normalScreenColor ;
screen . ScreenX = displaySource . SourceModeInfo . Position . X ;
screen . ScreenY = displaySource . SourceModeInfo . Position . Y ;
screen . ScreenWidth = ( int ) displaySource . SourceModeInfo . Resolution . Width ;
screen . ScreenHeight = ( int ) displaySource . SourceModeInfo . Resolution . Height ;
// If we're at the 0,0 coordinate then we're the primary monitor
if ( screen . ScreenX = = 0 & & screen . ScreenY = = 0 )
{
// Record we're primary screen
screen . IsPrimary = true ;
// Change the colour to be the primary colour, but only if it isn't a surround screen
if ( screen . Colour ! = spannedScreenColor )
{
screen . Colour = primaryScreenColor ;
}
}
2022-04-14 23:46:46 +00:00
// Figure out the taskbar location for this screen
string windowsDisplayName = _nvidiaDisplayConfig . DisplayNames [ targetInfo . DisplayId . ToString ( ) ] ;
screen . TaskBarEdge = _windowsDisplayConfig . TaskBarLayout [ windowsDisplayName ] . Edge ;
2022-04-13 10:48:32 +00:00
SharedLogger . logger . Trace ( $"ProfileItem/GetNVIDIAScreenPositions: (1) Added a non NVIDIA Screen {screen.Name} ({screen.ScreenWidth}x{screen.ScreenHeight}) at position {screen.ScreenX},{screen.ScreenY}." ) ;
_screens . Add ( screen ) ;
}
}
}
catch ( KeyNotFoundException ex )
{
// Thrown if the Windows display doesn't match the NVIDIA display.
// Typically happens during configuration of a new Mosaic mode.
// If we hit this issue, then we just want to skip over it, as we can update it later when the user pushes the button.
// This only happens due to the auto detection stuff functionality we have built in to try and update as quickly as we can.
// So its something that we can safely ignore if we hit this exception as it is part of the expect behaviour
continue ;
}
catch ( Exception ex )
{
// Some other exception has occurred and we need to report it.
SharedLogger . logger . Error ( ex , $"ProfileItem/GetNVIDIAScreenPositions: Unable to get the non-mosaic screen size from the Windows Display Config" ) ;
2021-09-07 09:26:42 +00:00
}
}
}
}
2022-02-06 00:47:30 +00:00
else
{
// If mosaic isn't enabled then we fall back to the windows display config
2022-04-13 10:48:32 +00:00
/ * _screens = GetWindowsScreenPositions ( ) ;
2022-02-06 00:47:30 +00:00
for ( int s = 0 ; s < _screens . Count ; s + + )
{
ScreenPosition sp = _screens . ElementAt ( s ) ;
sp . Library = "NVIDIA" ;
2022-04-13 10:48:32 +00:00
} * /
try
{
List < NV_DISPLAYCONFIG_PATH_INFO_V2 > displaySources = _nvidiaDisplayConfig . DisplayConfigs ;
foreach ( var displaySource in displaySources )
{
foreach ( NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2 targetInfo in displaySource . TargetInfo )
{
ScreenPosition screen = new ScreenPosition ( ) ;
screen . Library = "NVIDIA" ;
// It's a normal screen
screen . SpannedScreens = new List < SpannedScreenPosition > ( ) ;
screen . Name = targetInfo . DisplayId . ToString ( ) ;
screen . IsSpanned = false ;
screen . SpannedRows = 1 ;
screen . SpannedColumns = 1 ;
screen . Colour = normalScreenColor ;
screen . ScreenX = displaySource . SourceModeInfo . Position . X ;
screen . ScreenY = displaySource . SourceModeInfo . Position . Y ;
screen . ScreenWidth = ( int ) displaySource . SourceModeInfo . Resolution . Width ;
screen . ScreenHeight = ( int ) displaySource . SourceModeInfo . Resolution . Height ;
// If we're at the 0,0 coordinate then we're the primary monitor
if ( screen . ScreenX = = 0 & & screen . ScreenY = = 0 )
{
// Record we're primary screen
screen . IsPrimary = true ;
// Change the colour to be the primary colour, but only if it isn't a surround screen
if ( screen . Colour ! = spannedScreenColor )
{
screen . Colour = primaryScreenColor ;
}
}
2022-04-14 23:46:46 +00:00
// Figure out the taskbar location for this screen
string windowsDisplayName = _nvidiaDisplayConfig . DisplayNames [ targetInfo . DisplayId . ToString ( ) ] ;
screen . TaskBarEdge = _windowsDisplayConfig . TaskBarLayout [ windowsDisplayName ] . Edge ;
2022-04-13 10:48:32 +00:00
SharedLogger . logger . Trace ( $"ProfileItem/GetNVIDIAScreenPositions: (2) Added a non NVIDIA Screen {screen.Name} ({screen.ScreenWidth}x{screen.ScreenHeight}) at position {screen.ScreenX},{screen.ScreenY}." ) ;
_screens . Add ( screen ) ;
}
}
}
catch ( KeyNotFoundException ex )
{
// Thrown if the Windows display doesn't match the NVIDIA display.
// Typically happens during configuration of a new Mosaic mode.
// If we hit this issue, then we just want to skip over it, as we can update it later when the user pushes the button.
// This only happens due to the auto detection stuff functionality we have built in to try and update as quickly as we can.
// So its something that we can safely ignore if we hit this exception as it is part of the expect behaviour
}
catch ( Exception ex )
{
// Some other exception has occurred and we need to report it.
SharedLogger . logger . Error ( ex , $"ProfileItem/GetNVIDIAScreenPositions: Unable to get the non-mosaic screen size from the Windows Display Config" ) ;
2022-02-06 00:47:30 +00:00
}
}
2021-09-07 09:26:42 +00:00
return _screens ;
}
private List < ScreenPosition > GetAMDScreenPositions ( )
2021-09-02 02:44:35 +00:00
{
2021-09-07 09:26:42 +00:00
// Set up some colours
Color primaryScreenColor = Color . FromArgb ( 0 , 174 , 241 ) ; // represents Primary screen blue
Color spannedScreenColor = Color . FromArgb ( 221 , 0 , 49 ) ; // represents AMD Red
Color normalScreenColor = Color . FromArgb ( 155 , 155 , 155 ) ; // represents normal screen colour (gray)
// Now we create the screens structure from the AMD profile information
_screens = new List < ScreenPosition > ( ) ;
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-12-16 22:53:23 +00:00
// Go through the AMD Eyefinity screens
2021-09-21 09:21:10 +00:00
if ( _amdDisplayConfig . SlsConfig . IsSlsEnabled )
2021-09-07 09:26:42 +00:00
{
2021-09-21 09:21:10 +00:00
for ( int i = 0 ; i < _amdDisplayConfig . DisplayMaps . Count ; i + + )
2021-09-07 09:26:42 +00:00
{
ScreenPosition screen = new ScreenPosition ( ) ;
2021-09-21 09:21:10 +00:00
screen . Library = "AMD" ;
2021-09-07 09:26:42 +00:00
screen . Colour = normalScreenColor ;
2021-09-21 09:21:10 +00:00
// This is multiple screens
screen . SpannedScreens = new List < SpannedScreenPosition > ( ) ;
screen . Name = "AMD Eyefinity" ;
//screen.IsSpanned = true;
screen . SpannedRows = _amdDisplayConfig . SlsConfig . SLSMapConfigs [ i ] . SLSMap . Grid . SLSGridRow ;
screen . SpannedColumns = _amdDisplayConfig . SlsConfig . SLSMapConfigs [ i ] . SLSMap . Grid . SLSGridColumn ;
2022-02-06 00:47:30 +00:00
screen . Colour = spannedScreenColor ;
2021-09-07 09:26:42 +00:00
2021-09-21 09:21:10 +00:00
//screen.Name = targetId.ToString();
//screen.DisplayConnector = displayMode.DisplayConnector;
screen . ScreenX = _amdDisplayConfig . DisplayMaps [ i ] . DisplayMode . XPos ;
screen . ScreenY = _amdDisplayConfig . DisplayMaps [ i ] . DisplayMode . YPos ;
screen . ScreenWidth = _amdDisplayConfig . DisplayMaps [ i ] . DisplayMode . XRes ;
screen . ScreenHeight = _amdDisplayConfig . DisplayMaps [ i ] . DisplayMode . YRes ;
// If we're at the 0,0 coordinate then we're the primary monitor
if ( screen . ScreenX = = 0 & & screen . ScreenY = = 0 )
{
// Record we're primary screen
screen . IsPrimary = true ;
// Change the colour to be the primary colour, but only if it isn't a surround screen
if ( screen . Colour ! = spannedScreenColor )
2021-09-07 09:26:42 +00:00
{
screen . Colour = primaryScreenColor ;
}
2021-12-16 22:53:23 +00:00
}
SharedLogger . logger . Trace ( $"ProfileItem/GetAMDScreenPositions: Added a new AMD Spanned Screen {screen.Name} ({screen.ScreenWidth}x{screen.ScreenHeight}) at position {screen.ScreenX},{screen.ScreenY}." ) ;
2021-09-07 09:26:42 +00:00
_screens . Add ( screen ) ;
}
}
2021-12-16 22:53:23 +00:00
// Next, go through the screens as Windows knows them, and then enhance the info with Eyefinity data if it applies
foreach ( var path in _windowsDisplayConfig . DisplayConfigPaths )
2021-09-07 09:26:42 +00:00
{
2021-12-16 22:53:23 +00:00
// For each path we go through and get the relevant info we need.
if ( _windowsDisplayConfig . DisplayConfigPaths . Length > 0 )
2021-09-07 09:26:42 +00:00
{
2021-12-16 23:25:02 +00:00
UInt64 adapterId = path . SourceInfo . AdapterId . Value ;
UInt32 sourceId = path . SourceInfo . Id ;
UInt32 targetId = path . TargetInfo . Id ;
2021-12-16 22:53:23 +00:00
// Set some basics about the screen
ScreenPosition screen = new ScreenPosition ( ) ;
screen . Library = "AMD" ;
2021-12-16 23:25:02 +00:00
//screen.AdapterName = adapterId.ToString();
2021-12-16 22:53:23 +00:00
screen . IsSpanned = false ;
screen . Colour = normalScreenColor ; // this is the default unless overridden by the primary screen
screen . IsClone = false ;
screen . ClonedCopies = 0 ;
2022-02-04 22:15:54 +00:00
try
{
2022-03-25 08:51:38 +00:00
screen . TaskBarEdge = _windowsDisplayConfig . TaskBarLayout . First ( tbr = > tbr . Value . RegKeyValue . Contains ( $"UID{targetId}" ) ) . Value . Edge ;
2022-02-04 22:15:54 +00:00
SharedLogger . logger . Trace ( $"ProfileItem/GetNVIDIAScreenPositions: Position of the taskbar on display {targetId} is on the {screen.TaskBarEdge } of the screen." ) ;
}
catch ( Exception ex )
{
// Guess that it is at the bottom (90% correct)
SharedLogger . logger . Error ( ex , $"ProfileItem/GetNVIDIAScreenPositions: Exception trying to get the position of the taskbar on display {targetId}" ) ;
2022-03-25 08:51:38 +00:00
screen . TaskBarEdge = TaskBarLayout . TaskBarEdge . Bottom ;
2022-02-04 22:15:54 +00:00
}
2022-03-25 08:51:38 +00:00
// Find out if this source is cloned
2021-12-16 22:53:23 +00:00
foreach ( var displaySource in _windowsDisplayConfig . DisplaySources )
{
2022-03-25 08:51:38 +00:00
// All of the items in the Value array are the same source, so we can just check the first one in the array!
if ( displaySource . Value [ 0 ] . SourceId = = sourceId )
2021-10-16 21:44:03 +00:00
{
2022-03-25 08:51:38 +00:00
// If there is more than one item in the array, then it's a cloned source!
2021-12-16 22:53:23 +00:00
if ( displaySource . Value . Count > 1 )
2021-10-16 21:44:03 +00:00
{
2021-12-16 22:53:23 +00:00
// We have a cloned display
screen . IsClone = true ;
screen . ClonedCopies = displaySource . Value . Count ;
2021-10-16 21:44:03 +00:00
}
2021-12-16 22:53:23 +00:00
break ;
2021-10-16 21:44:03 +00:00
}
2021-12-16 22:53:23 +00:00
}
2021-09-07 09:26:42 +00:00
2021-12-16 22:53:23 +00:00
// Go through the screens as Windows knows them, and then enhance the info with Mosaic data if it applies
foreach ( DISPLAYCONFIG_MODE_INFO displayMode in _windowsDisplayConfig . DisplayConfigModes )
{
// Find the matching Display Config Source Mode
2021-12-16 23:25:02 +00:00
if ( displayMode . InfoType = = DISPLAYCONFIG_MODE_INFO_TYPE . DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE & & displayMode . Id = = sourceId & & displayMode . AdapterId . Value = = adapterId )
2021-09-07 09:26:42 +00:00
{
2021-12-16 22:53:23 +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 ;
// If we're at the 0,0 coordinate then we're the primary monitor
if ( screen . ScreenX = = 0 & & screen . ScreenY = = 0 )
2021-09-07 09:26:42 +00:00
{
2021-12-16 22:53:23 +00:00
screen . IsPrimary = true ;
screen . Colour = primaryScreenColor ;
2021-09-07 09:26:42 +00:00
}
2021-12-16 22:53:23 +00:00
break ;
2021-09-07 09:26:42 +00:00
}
2021-12-16 22:53:23 +00:00
}
// Decide if this screen is one we've had earlier, and if so, skip it
if ( _screens . Any ( s = > s . ScreenX = = screen . ScreenX & & s . ScreenY = = screen . ScreenY & & s . ScreenWidth = = screen . ScreenWidth & & s . ScreenHeight = = screen . ScreenHeight ) )
{
SharedLogger . logger . Trace ( $"ProfileItem/GetAMDScreenPositions: We've already got the {screen.Name} ({screen.ScreenWidth}x{screen.ScreenHeight}) screen from the AMD driver, so skipping it from the Windows driver." ) ;
continue ;
}
2021-09-07 09:26:42 +00:00
2021-12-16 22:53:23 +00:00
foreach ( ADVANCED_HDR_INFO_PER_PATH hdrInfo in _windowsDisplayConfig . DisplayHDRStates )
{
// Find the matching HDR information
if ( hdrInfo . Id = = targetId )
2021-09-07 09:26:42 +00:00
{
2021-12-16 22:53:23 +00:00
// HDR information
if ( hdrInfo . AdvancedColorInfo . AdvancedColorSupported )
2021-09-07 09:26:42 +00:00
{
2021-12-16 22:53:23 +00:00
screen . HDRSupported = true ;
if ( hdrInfo . AdvancedColorInfo . AdvancedColorEnabled )
2021-09-07 09:26:42 +00:00
{
2021-12-16 22:53:23 +00:00
screen . HDREnabled = true ;
2021-09-07 09:26:42 +00:00
}
else
{
screen . HDREnabled = false ;
}
2021-12-16 22:53:23 +00:00
}
else
{
screen . HDRSupported = false ;
screen . HDREnabled = false ;
2021-09-07 09:26:42 +00:00
}
2021-12-16 22:53:23 +00:00
break ;
2021-09-07 09:26:42 +00:00
}
}
2021-12-16 22:53:23 +00:00
SharedLogger . logger . Trace ( $"ProfileItem/GetAMDScreenPositions: Added a new Screen {screen.Name} ({screen.ScreenWidth}x{screen.ScreenHeight}) at position {screen.ScreenX},{screen.ScreenY}." ) ;
_screens . Add ( screen ) ;
2021-09-07 09:26:42 +00:00
}
}
return _screens ;
}
private List < ScreenPosition > GetWindowsScreenPositions ( )
{
// Set up some colours
Color primaryScreenColor = Color . FromArgb ( 0 , 174 , 241 ) ; // represents Primary screen blue
Color normalScreenColor = Color . FromArgb ( 155 , 155 , 155 ) ; // represents normal screen colour (gray)
// Now we create the screens structure from the AMD profile information
_screens = new List < ScreenPosition > ( ) ;
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 ;
}
foreach ( var path in _windowsDisplayConfig . DisplayConfigPaths )
{
// For each path we go through and get the relevant info we need.
if ( _windowsDisplayConfig . DisplayConfigPaths . Length > 0 )
{
2021-12-16 23:25:02 +00:00
UInt64 adapterId = path . SourceInfo . AdapterId . Value ;
UInt32 sourceId = path . SourceInfo . Id ;
UInt32 targetId = path . TargetInfo . Id ;
2021-09-07 09:26:42 +00:00
// Set some basics about the screen
ScreenPosition screen = new ScreenPosition ( ) ;
screen . Library = "WINDOWS" ;
2021-12-16 23:25:02 +00:00
//screen.AdapterName = adapterId.ToString();
2021-09-07 09:26:42 +00:00
screen . IsSpanned = false ;
screen . Colour = normalScreenColor ; // this is the default unless overridden by the primary screen
2021-10-16 21:44:03 +00:00
screen . IsClone = false ;
screen . ClonedCopies = 0 ;
2022-02-04 22:15:54 +00:00
try
{
2022-03-25 08:51:38 +00:00
screen . TaskBarEdge = _windowsDisplayConfig . TaskBarLayout . First ( tbr = > tbr . Value . RegKeyValue . Contains ( $"UID{targetId}" ) ) . Value . Edge ;
2022-02-04 22:15:54 +00:00
SharedLogger . logger . Trace ( $"ProfileItem/GetNVIDIAScreenPositions: Position of the taskbar on display {targetId} is on the {screen.TaskBarEdge } of the screen." ) ;
}
catch ( Exception ex )
{
// Guess that it is at the bottom (90% correct)
SharedLogger . logger . Error ( ex , $"ProfileItem/GetNVIDIAScreenPositions: Exception trying to get the position of the taskbar on display {targetId}" ) ;
2022-03-25 08:51:38 +00:00
screen . TaskBarEdge = TaskBarLayout . TaskBarEdge . Bottom ;
2022-02-04 22:15:54 +00:00
}
2022-03-25 08:51:38 +00:00
// Find out if this source is cloned
2021-10-16 21:44:03 +00:00
foreach ( var displaySource in _windowsDisplayConfig . DisplaySources )
{
2022-03-25 08:51:38 +00:00
// All of the items in the Value array are the same source, so we can just check the first one in the array!
if ( displaySource . Value [ 0 ] . SourceId = = sourceId )
2021-10-16 21:44:03 +00:00
{
2022-03-25 08:51:38 +00:00
// If there is more than one item in the array, then it's a cloned source!
2021-10-16 21:44:03 +00:00
if ( displaySource . Value . Count > 1 )
{
// We have a cloned display
screen . IsClone = true ;
screen . ClonedCopies = displaySource . Value . Count ;
}
break ;
}
}
2021-09-07 09:26:42 +00:00
// Go through the screens as Windows knows them, and then enhance the info with Mosaic data if it applies
foreach ( DISPLAYCONFIG_MODE_INFO displayMode in _windowsDisplayConfig . DisplayConfigModes )
{
// Find the matching Display Config Source Mode
2021-12-16 23:25:02 +00:00
if ( displayMode . InfoType = = DISPLAYCONFIG_MODE_INFO_TYPE . DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE & & displayMode . Id = = sourceId & & displayMode . AdapterId . Value = = adapterId )
2021-09-07 09:26:42 +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 ;
// If we're at the 0,0 coordinate then we're the primary monitor
if ( screen . ScreenX = = 0 & & screen . ScreenY = = 0 )
{
screen . IsPrimary = true ;
screen . Colour = primaryScreenColor ;
}
break ;
}
}
foreach ( ADVANCED_HDR_INFO_PER_PATH hdrInfo in _windowsDisplayConfig . DisplayHDRStates )
{
// Find the matching HDR information
if ( hdrInfo . Id = = targetId )
{
// HDR information
if ( hdrInfo . AdvancedColorInfo . AdvancedColorSupported )
{
screen . HDRSupported = true ;
if ( hdrInfo . AdvancedColorInfo . AdvancedColorEnabled )
{
screen . HDREnabled = true ;
}
else
{
screen . HDREnabled = false ;
}
}
else
{
screen . HDRSupported = false ;
screen . HDREnabled = false ;
}
break ;
}
}
2022-02-11 20:18:03 +00:00
// Now we try to set the taskbar positions
if ( screen . IsPrimary )
{
// If the screen is the primary screen, then we check if we need to use the StuckRect 'Settings' reg keys
// rather than the MMStuckRect reg keys
try
{
2022-03-29 21:56:24 +00:00
screen . TaskBarEdge = _windowsDisplayConfig . TaskBarLayout . First ( tb = > tb . Value . RegKeyValue . Contains ( "Settings" ) ) . Value . Edge ;
2022-02-11 20:18:03 +00:00
SharedLogger . logger . Trace ( $"ProfileItem/GetNVIDIAScreenPositions: Position of the taskbar on the primary display {targetId} is on the {screen.TaskBarEdge } of the screen." ) ;
}
catch ( Exception ex )
{
// Guess that it is at the bottom (90% correct)
SharedLogger . logger . Error ( ex , $"ProfileItem/GetNVIDIAScreenPositions: Exception trying to get the position of the taskbar on primary display {targetId}" ) ;
2022-03-29 21:56:24 +00:00
screen . TaskBarEdge = TaskBarLayout . TaskBarEdge . Bottom ;
2022-02-11 20:18:03 +00:00
}
}
else
{
try
{
2022-03-29 21:56:24 +00:00
screen . TaskBarEdge = _windowsDisplayConfig . TaskBarLayout . First ( tbr = > tbr . Value . RegKeyValue . Contains ( $"UID{targetId}" ) ) . Value . Edge ;
2022-02-11 20:18:03 +00:00
SharedLogger . logger . Trace ( $"ProfileItem/GetNVIDIAScreenPositions: Position of the taskbar on display {targetId} is on the {screen.TaskBarEdge } of the screen." ) ;
}
catch ( Exception ex )
{
// Guess that it is at the bottom (90% correct)
SharedLogger . logger . Error ( ex , $"ProfileItem/GetNVIDIAScreenPositions: Exception trying to get the position of the taskbar on display {targetId}" ) ;
2022-03-29 21:56:24 +00:00
screen . TaskBarEdge = TaskBarLayout . TaskBarEdge . Bottom ;
2022-02-11 20:18:03 +00:00
}
}
2021-12-16 22:53:23 +00:00
SharedLogger . logger . Trace ( $"ProfileItem/GetWindowsScreenPositions: Added a new Screen {screen.Name} ({screen.ScreenWidth}x{screen.ScreenHeight}) at position {screen.ScreenX},{screen.ScreenY}." ) ;
2021-09-07 09:26:42 +00:00
_screens . Add ( screen ) ;
}
}
return _screens ;
}
2021-09-02 02:44:35 +00:00
2021-09-04 08:58:08 +00:00
public int CompareTo ( ProfileItem other )
{
int result = CompareToValues ( other ) ;
// If comparison based solely on values
// returns zero, indicating that two instances
// are equal in those fields they have in common,
// only then we break the tie by comparing
// data types of the two instances.
if ( result = = 0 )
result = CompareTypes ( other ) ;
return result ;
}
protected virtual int CompareToValues ( ProfileItem other )
{
if ( object . ReferenceEquals ( other , null ) )
return 1 ; // All instances are greater than null
// Base class simply compares Mark properties
return Name . CompareTo ( other . Name ) ;
2021-09-02 02:44:35 +00:00
}
2021-09-04 08:58:08 +00:00
protected int CompareTypes ( ProfileItem other )
{
// Base type is considered less than derived type
// when two instances have the same values of
// base fields.
// Instances of two distinct derived types are
// ordered by comparing full names of their
// types when base fields are equal.
// This is consistent comparison rule for all
// instances of the two derived types.
int result = 0 ;
Type thisType = this . GetType ( ) ;
Type otherType = other . GetType ( ) ;
if ( otherType . IsSubclassOf ( thisType ) )
result = - 1 ; // other is subclass of this class
else if ( thisType . IsSubclassOf ( otherType ) )
result = 1 ; // this is subclass of other class
else if ( thisType ! = otherType )
result = thisType . FullName . CompareTo ( otherType . FullName ) ;
// cut the tie with a test that returns
// the same value for all objects
return result ;
}
2021-09-07 09:26:42 +00:00
2021-09-06 10:08:22 +00:00
// The object specific Equals
public bool Equals ( ProfileItem other )
2021-09-02 02:44:35 +00:00
{
2021-09-06 10:08:22 +00:00
// Check references
if ( ReferenceEquals ( null , other ) ) return false ;
if ( ReferenceEquals ( this , other ) ) return true ;
2021-09-05 09:00:36 +00:00
2021-09-06 10:08:22 +00:00
// Check the object fields
2021-09-05 09:00:36 +00:00
// ProfileDisplayIdentifiers may be the same but in different order within the array, so we need to handle
2021-09-19 08:56:58 +00:00
// that fact.
2021-09-07 09:26:42 +00:00
return NVIDIADisplayConfig . Equals ( other . NVIDIADisplayConfig ) & &
2021-09-19 08:56:58 +00:00
AMDDisplayConfig . Equals ( other . AMDDisplayConfig ) & &
2021-09-07 09:26:42 +00:00
WindowsDisplayConfig . Equals ( other . WindowsDisplayConfig ) & &
ProfileDisplayIdentifiers . SequenceEqual ( other . ProfileDisplayIdentifiers ) ;
2021-09-02 02:44:35 +00:00
}
2021-09-06 10:08:22 +00:00
// The public override for the Object.Equals
2021-09-07 09:26:42 +00:00
public override bool Equals ( Object obj )
2021-09-06 10:08:22 +00:00
{
// Check references
if ( ReferenceEquals ( null , obj ) ) return false ;
if ( ReferenceEquals ( this , obj ) ) return true ;
// If different types then can't be true
if ( obj . GetType ( ) = = this . GetType ( ) ) return false ;
2021-09-07 10:08:54 +00:00
if ( ! ( obj is ProfileItem ) ) return false ;
2021-09-06 10:08:22 +00:00
// Check the object fields as this must the same object as obj, and we need to test in more detail
return Equals ( ( ProfileItem ) obj ) ;
}
2021-09-02 02:44:35 +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-09-07 09:26:42 +00:00
return ( NVIDIADisplayConfig , AMDDisplayConfig , WindowsDisplayConfig , ProfileDisplayIdentifiers ) . GetHashCode ( ) ;
2021-09-02 02:44:35 +00:00
}
public static bool operator = = ( ProfileItem lhs , ProfileItem rhs )
{
2021-09-06 10:08:22 +00:00
/ * if ( object . ReferenceEquals ( lhs , rhs ) )
2021-09-04 04:32:42 +00:00
return true ;
2021-09-02 02:44:35 +00:00
2021-09-04 04:32:42 +00:00
if ( ! object . ReferenceEquals ( lhs , null ) & &
! object . ReferenceEquals ( rhs , null ) & &
lhs . Equals ( rhs ) )
return true ;
2021-09-06 10:08:22 +00:00
return false ; * /
return Equals ( lhs , rhs ) ;
2021-09-02 02:44:35 +00:00
}
2021-09-06 10:08:22 +00:00
public static bool operator ! = ( ProfileItem lhs , ProfileItem rhs )
{
return ! Equals ( lhs , rhs ) ;
}
2021-09-02 03:09:06 +00:00
// IMPORTANT - This ProfileItem ToString function is required to make the Profile ImageListView work properly! DO NOT DELETE!
public override string ToString ( )
{
return ( Name ? ? Language . UN_TITLED_PROFILE ) ;
}
2021-10-09 05:42:50 +00:00
2022-01-17 08:07:48 +00:00
public string CreateCommand ( )
{
return $"{Application.ExecutablePath} {DisplayMagicianStartupAction.ChangeProfile} \" { UUID } \ "" ;
}
2020-05-13 11:04:18 +00:00
}
2021-09-02 02:44:35 +00:00
}
2020-05-13 11:04:18 +00:00