Desktop::getInstance assert on Windows with high-DPI monitor on left of primary

I’m testing my plugin in the non-DPI-aware Steinberg VST validator tool on a Windows machine with multiple displays connected. My plugin calls juce::Desktop::getInstance() which always triggers the following assert in void Displays::updateToLogical():

// All of the nodes should have a parent
jassert (node.parent != nullptr);

I think I’ve tracked down the problem to my particular arrangement of displays. My primary display is a low DPI monitor with the text scaling set to 100%, and to its left is the high DPI laptop monitor with the text scaling set to 250%.

The following code in processDisplay (DisplayNode* currentNode, Array<DisplayNode>& allNodes) is supposed to find the parent for the secondary display:

        // If the displays are touching on any side
        if (otherPhysicalArea.getX() == physicalArea.getRight()  || otherPhysicalArea.getRight() == physicalArea.getX()
            || otherPhysicalArea.getY() == physicalArea.getBottom() || otherPhysicalArea.getBottom() == physicalArea.getY())
        {
            node.parent = currentNode;
            children.add (&node);
        }

As this is a plugin rather than a standalone application, the setDPIAwareness call in juce_win32_Windowing.cpp never sets up any of the DPI-aware functions and the scale for the high-DPI monitor is defaulted to the system DPI in enumMonitorsProc.

At the time of the call to juce::Desktop::getInstance() the displays are in the following state:

Display [0] // primary, low DPI
isMain	        true
totalArea	    {pos={x=0 y=0 } w=1920 h=1200 }
userArea	    {pos={x=0 y=0 } w=1920 h=1160 }
topLeftPhysical	{x=0 y=0 }
scale	        1.0000000000000000
dpi	            96.000000000000000
isRoot	        true

Display [1] // secondary, to the left of the primary, high DPI
isMain	        false
totalArea	    {pos={x=-3840 y=0 } w=1536 h=864 }
userArea	    {pos={x=-3840 y=0 } w=1536 h=864 }
topLeftPhysical {x=0 y=0 }
scale	        1.0000000000000000
dpi	            96.000000000000000
isRoot	        false

The position of display 1 is based on actual pixels but the width & height reflect the 250% scaling factor set up for that display. In JUCE, the right edge of display 1 is deemed not to be touching the left edge of display 0, no parent is thus set and the assert fires.

The assert is more of an distraction when debugging than anything else, but I do wonder if the parent not being set up correctly might also have other implications I’m not aware of?

Thanks for reporting. The issue is that in a non DPI-aware process the MONITORINFO struct will contain virtualised coordinates for the monitor bounds but will only report a DPI of 96, so there’s no way to get the actual physical bounds of the monitor (which is what the updateToLogical() method relies on). What we should be doing is checking the DPI awareness of the process and using that to determine whether we call updateToLogical() or not as in a non DPI-aware process we can just rely on all the win32 coordinate methods being virtualised. We’ve added this to develop here:

Thanks @ed95.