Windows Main Display Detection Incorrect


#1

Currently, JUCE sets the first found display/monitor as the main one. This is incorrect on Windows since any monitor can be set as the main one.

Here's a patch to get the right info:

//==============================================================================
struct WindowsMonitor
{
    WindowsMonitor (bool main, Rectangle<int> rect)
      : isMain (main),
        bounds (rect)
    {
    }
    bool isMain;
    Rectangle<int> bounds;
};

static BOOL CALLBACK enumMonitorsProc (HMONITOR hm, HDC, LPRECT r, LPARAM userInfo)
{
    MONITORINFO info = { 0 };
    info.cbSize = sizeof (info);
    GetMonitorInfo (hm, &info);
    const bool isMain = (info.dwFlags & 0x0000001 /* MONITORINFOF_PRIMARY */) != 0;
    Array<WindowsMonitor>* const monitorCoords = (Array<WindowsMonitor>*) userInfo;
    monitorCoords->add (WindowsMonitor (isMain, rectangleFromRECT (*r)));
    return TRUE;
}

void Desktop::Displays::findDisplays (float masterScale)
{
    setDPIAwareness();
    Array<WindowsMonitor> monitors;
    EnumDisplayMonitors (0, 0, &enumMonitorsProc, (LPARAM) &monitors);
    if (monitors.size() == 0)
        monitors.add (WindowsMonitor (true, rectangleFromRECT (getWindowRect (GetDesktopWindow()))));
    RECT workArea;
    SystemParametersInfo (SPI_GETWORKAREA, 0, &workArea, 0);
    const double dpi = getDPI(); // (this has only one value for all monitors)
    for (int i = 0; i < monitors.size(); ++i)
    {
        Display d;
        d.userArea  = d.totalArea = monitors.getReference(i).bounds / masterScale;
        d.isMain    = monitors.getReference(i).isMain;
        d.scale     = masterScale;
        d.dpi       = dpi;
        if (d.isMain)
            d.userArea = d.userArea.getIntersection (rectangleFromRECT (workArea) / masterScale);
        displays.add (d);
    }
}

#2

Cool, thanks!


#3

Ah, I didn't see getMainDisplay() - that would appear to need to be fixed up, too:

const Desktop::Displays::Display& Desktop::Displays::getMainDisplay() const noexcept
{
    for (int i = 0; i < displays.size(); ++i)
        if (displays.getReference (i).isMain)
            return displays.getReference (i);

    return displays.getReference (0);
}

#4

Ah no - that method is correct, but the list is supposed to always be sorted so that the main monitor is first. I didn't notice that you deleted that logic from the scanning code - I've put it back in there now.