Skip to content

Commit

Permalink
Fixed broken equality testing when cloned display or after reboot
Browse files Browse the repository at this point in the history
Turns out that Windows reorders some of the displays after cloning or while cloning or after a reboot. The equality testing wasn't taking care of that properly. It does now. I implemented equality test for lists which is order agnostic; it doesn't care what order the items are in the lists, it just cares that the objects are in both lists, and that there aren't any extra items in the list.

This change should fix #113 and #114.
  • Loading branch information
terrymacdonald committed Jun 2, 2022
1 parent 0d430ce commit 6725efa
Show file tree
Hide file tree
Showing 3 changed files with 183 additions and 12 deletions.
67 changes: 64 additions & 3 deletions NVIDIAInfo/NVAPI.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Emit;
using System.Runtime.InteropServices;
Expand Down Expand Up @@ -2258,12 +2259,25 @@ public struct NV_DISPLAYCONFIG_PATH_INFO_V2 : IEquatable<NV_DISPLAYCONFIG_PATH_I
public override bool Equals(object obj) => obj is NV_DISPLAYCONFIG_PATH_INFO_V2 other && this.Equals(other);

public bool Equals(NV_DISPLAYCONFIG_PATH_INFO_V2 other)
=> Version == other.Version &&
{
if(!(Version == other.Version &&
SourceId == other.SourceId &&
TargetInfoCount == other.TargetInfoCount &&
TargetInfo.SequenceEqual(other.TargetInfo) &&
SourceModeInfo.Equals(other.SourceModeInfo) &&
Flags == other.Flags;
Flags == other.Flags))
{
return false;
}

// Now we need to go through the HDR states comparing vaues, as the order changes if there is a cloned display
if (!NVImport.EqualButDifferentOrder<NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2>(TargetInfo, other.TargetInfo))
{
return false;
}

return true;

}

public override Int32 GetHashCode()
{
Expand Down Expand Up @@ -7032,5 +7046,52 @@ public static NVAPI_STATUS NvAPI_DRS_RestoreProfileDefaultSetting(NvDRSSessionHa

// NVAPI_INTERFACE NvAPI_DRS_DeleteProfile(NvDRSSessionHandle hSession, NvDRSProfileHandle hProfile)

public static bool EqualButDifferentOrder<T>(IList<T> list1, IList<T> list2)
{

if (list1.Count != list2.Count)
{
return false;
}

// Now we need to go through the list1, checking that all it's items are in list2
foreach (T item1 in list1)
{
bool foundIt = false;
foreach (T item2 in list2)
{
if (item1.Equals(item2))
{
foundIt = true;
break;
}
}
if (!foundIt)
{
return false;
}
}

// Now we need to go through the list2, checking that all it's items are in list1
foreach (T item2 in list2)
{
bool foundIt = false;
foreach (T item1 in list1)
{
if (item1.Equals(item2))
{
foundIt = true;
break;
}
}
if (!foundIt)
{
return false;
}
}

return true;
}

}
}
64 changes: 61 additions & 3 deletions NVIDIAInfo/NVIDIALibrary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -170,14 +170,25 @@ public struct NVIDIA_DISPLAY_CONFIG : IEquatable<NVIDIA_DISPLAY_CONFIG>
public override bool Equals(object obj) => obj is NVIDIA_DISPLAY_CONFIG other && this.Equals(other);

public bool Equals(NVIDIA_DISPLAY_CONFIG other)
=> IsCloned == other.IsCloned &&
{
if (!(IsCloned == other.IsCloned &&
IsOptimus == other.IsOptimus &&
PhysicalAdapters.SequenceEqual(other.PhysicalAdapters) &&
MosaicConfig.Equals(other.MosaicConfig) &&
DisplayConfigs.SequenceEqual(other.DisplayConfigs) &&
DRSSettings.SequenceEqual(other.DRSSettings) &&
DisplayIdentifiers.SequenceEqual(other.DisplayIdentifiers);
DisplayIdentifiers.SequenceEqual(other.DisplayIdentifiers)))
{
return false;
}

// Now we need to go through the display configscomparing values, as the order changes if there is a cloned display
if (!NVIDIALibrary.EqualButDifferentOrder<NV_DISPLAYCONFIG_PATH_INFO_V2>(DisplayConfigs, other.DisplayConfigs))
{
return false;
}

return true;
}

public override int GetHashCode()
{
Expand Down Expand Up @@ -4306,6 +4317,53 @@ public static bool Arrays2DEqual(int[][] a1, int[][] a2)
return false;
}
}

public static bool EqualButDifferentOrder<T>(IList<T> list1, IList<T> list2)
{

if (list1.Count != list2.Count)
{
return false;
}

// Now we need to go through the list1, checking that all it's items are in list2
foreach (T item1 in list1)
{
bool foundIt = false;
foreach (T item2 in list2)
{
if (item1.Equals(item2))
{
foundIt = true;
break;
}
}
if (!foundIt)
{
return false;
}
}

// Now we need to go through the list2, checking that all it's items are in list1
foreach (T item2 in list2)
{
bool foundIt = false;
foreach (T item1 in list1)
{
if (item1.Equals(item2))
{
foundIt = true;
break;
}
}
if (!foundIt)
{
return false;
}
}

return true;
}
}


Expand Down
64 changes: 58 additions & 6 deletions NVIDIAInfo/WinLibrary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,15 @@ public struct DISPLAY_SOURCE : IEquatable<DISPLAY_SOURCE>

public override bool Equals(object obj) => obj is DISPLAY_SOURCE other && this.Equals(other);
public bool Equals(DISPLAY_SOURCE other)
=> SourceId.Equals(other.SourceId) &&
TargetId.Equals(other.TargetId) &&
=> //SourceId.Equals(other.SourceId) && // Source ID needs to be ignored in this case, as windows moves the source ids around :(
TargetId.Equals(other.TargetId) &&
DevicePath.Equals(other.DevicePath) &&
SourceDpiScalingRel.Equals(other.SourceDpiScalingRel);
//=> true;
public override int GetHashCode()
{
//return 300;
return (SourceId, TargetId, DevicePath, SourceDpiScalingRel).GetHashCode();
//return (SourceId, TargetId, DevicePath, SourceDpiScalingRel).GetHashCode(); // Source ID needs to be ignored in this case, as windows moves the source ids around :(
return (TargetId, DevicePath, SourceDpiScalingRel).GetHashCode();
}

public static bool operator ==(DISPLAY_SOURCE lhs, DISPLAY_SOURCE rhs) => lhs.Equals(rhs);
Expand Down Expand Up @@ -90,8 +90,7 @@ public bool Equals(WINDOWS_DISPLAY_CONFIG other)
{
if (!(IsCloned == other.IsCloned &&
DisplayConfigPaths.SequenceEqual(other.DisplayConfigPaths) &&
DisplayConfigModes.SequenceEqual(other.DisplayConfigModes) &&
DisplayHDRStates.SequenceEqual(other.DisplayHDRStates) &&
DisplayConfigModes.SequenceEqual(other.DisplayConfigModes) &&
// The dictionary keys sometimes change after returning from NVIDIA Surround, so we need to only focus on comparing the values of the GDISettings.
// Additionally, we had to disable the DEviceKey from the equality testing within the GDI library itself as that waould also change after changing back from NVIDIA surround
// This still allows us to detect when refresh rates change, which will allow DisplayMagician to detect profile differences.
Expand All @@ -101,6 +100,12 @@ public bool Equals(WINDOWS_DISPLAY_CONFIG other)
return false;
}

// Now we need to go through the HDR states comparing vaues, as the order changes if there is a cloned display
if (!WinLibrary.EqualButDifferentOrder<ADVANCED_HDR_INFO_PER_PATH>(DisplayHDRStates, other.DisplayHDRStates))
{
return false;
}

// Now we need to go through the values to make sure they are the same, but ignore the keys (as they change after each reboot!)
for (int i = 0; i < DisplaySources.Count; i++)
{
Expand Down Expand Up @@ -2361,6 +2366,53 @@ private static void RefreshTrayArea(IntPtr windowHandle)
Utils.SendMessage(windowHandle, Utils.WM_MOUSEMOVE, 0, (y << 16) + x);
}

public static bool EqualButDifferentOrder<T>(IList<T> list1, IList<T> list2)
{

if (list1.Count != list2.Count)
{
return false;
}

// Now we need to go through the list1, checking that all it's items are in list2
foreach (T item1 in list1)
{
bool foundIt = false;
foreach (T item2 in list2)
{
if (item1.Equals(item2))
{
foundIt = true;
break;
}
}
if (!foundIt)
{
return false;
}
}

// Now we need to go through the list2, checking that all it's items are in list1
foreach (T item2 in list2)
{
bool foundIt = false;
foreach (T item1 in list1)
{
if (item1.Equals(item2))
{
foundIt = true;
break;
}
}
if (!foundIt)
{
return false;
}
}

return true;
}

}

[global::System.Serializable]
Expand Down

0 comments on commit 6725efa

Please sign in to comment.