DropShadow getting missplaced when using two screen with different screen scaling on windows

To reproduce this you have to have at least two screen with different scaling set in the windows settings. Your app have to be on the right screen.
As you can see on the following image, the dropshadow which is supposed to be on the left of the popupmenu (and thus on the left screen), is getting placed floating around nowhere in the middle of the image. The issue disappears when I offset the popupmenu by 10 pixels to give the drop shadow the room to stay on the same screen as the main app.

I’m struggling to reproduce this issue. Can you get it to trigger with the JUCE MenusDemo example? Are you definitely using the very latest version of JUCE from the develop branch? It may also be useful to see how your screens are arranged.

I’ve tried testing with two screens, both with different scaling factors. I’ve then tried opening menus so that their X position exactly matches the coordinate of a screen edge. I’m not seeing any misplaced shadows when opening menus in this way.

In order to investigate further, it would be really helpful if you could provide a minimal code example which demonstrates the issue.

I did manage to reproduce it with the MenusDemo by setting JUCE_WIN_PER_MONITOR_DPI_AWARE to 0.

I still can’t reproduce the issue, even with that preprocessor definition set to 0.

Are you definitely using the very latest version of JUCE from the develop branch?

What are the scale factors of your left and right screens?

Please could you provide a detailed set of step-by-step instructions which reliably trigger the issue?

Yep I tried again with the DemoRunner running the latest develop branch.
The setup to reproduce is as following :

  • Put your right screen to a lower scaling than the right one (here I have 200% on the left one and 175% on the right one)
  • Move the DemoRunner window just at the left border of the right screen. and click on the menu.

Thanks, I’ve spent a few hours debugging this now but haven’t managed to find a solution so far.

I wrote the following test program. On my system, I have the primary display on the right, so this program causes a group of four windows to oscillate between the left and right displays. Clicking on the main app window toggles transparency on the other windows.

I see that when the windows are opaque, the bounds update as expected, and the group of windows stays locked in a square configuration. When the windows are transparent, their sizes and positions are modified as they cross the boundary onto the left display, so that the windows no longer form a square. The weird part is that we’re passing exactly the same coordinates to SetWindowPos in both cases, so the OS appears to interpret the coordinates differently for transparent windows. This seems to be the same behaviour we’re seeing with the shadow windows, which are transparent, and which have incorrect locations.

Unfortunately, this behaviour doesn’t seem to be documented anywhere, so I’m not sure how to work around it in a robust way.

struct MyComp : public juce::Component
{
    MyComp()
    {
        setVisible (true);
        setSize (100, 100);
        addToDesktop (juce::ComponentPeer::windowIgnoresMouseClicks
                            | juce::ComponentPeer::windowIsTemporary
                            | juce::ComponentPeer::windowIgnoresKeyPresses);
    }

    void paint (juce::Graphics& g) override { g.setColour (juce::Colours::cyan); g.drawRect (getLocalBounds(), 2); }
};

class MainComponent   : public juce::Component,
                        private juce::Timer
{
public:
    MainComponent()
    {
        setSize (600, 400);
        startTimerHz (30);
    }

    void paint (juce::Graphics& g) override
    {
        g.fillAll (getLookAndFeel().findColour (juce::ResizableWindow::backgroundColourId));

        g.setFont (juce::Font (16.0f));
        g.setColour (juce::Colours::white);
        g.drawText ("Hello World!", getLocalBounds(), juce::Justification::centred, true);
    }

    void mouseDown (const juce::MouseEvent&) override
    {
        for (auto* comp : { &a, &b, &c, &d})
            comp->setOpaque (! comp->isOpaque());
    }

private:
    void timerCallback() override
    {
        const auto offset = static_cast<int> (std::sin (juce::MathConstants<float>::twoPi * phase) * 250);
        a.setTopLeftPosition ({ offset - 100, 900 });
        b.setTopLeftPosition ({ offset, 900 });
        c.setTopLeftPosition ({ offset - 100, 1000 });
        d.setTopLeftPosition ({ offset, 1000 });

        phase += 0.002f;
        phase -= floor (phase);
    }

    MyComp a, b, c, d;
    float phase = 0.4f;

    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainComponent)
};

With opaque windows:

With transparent windows: