From 2c2c21ebc98b0f8b172f9c1d97449ebf4b561844 Mon Sep 17 00:00:00 2001 From: attila Date: Mon, 16 May 2022 17:10:12 +0200 Subject: [PATCH] Linux: Fix sporadic positioning error after window creation --- .../components/juce_Component.cpp | 10 +++++ .../native/juce_linux_Windowing.cpp | 38 +++++++++++++++---- 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/modules/juce_gui_basics/components/juce_Component.cpp b/modules/juce_gui_basics/components/juce_Component.cpp index 4bbffea726..e2a42bab0b 100644 --- a/modules/juce_gui_basics/components/juce_Component.cpp +++ b/modules/juce_gui_basics/components/juce_Component.cpp @@ -752,6 +752,16 @@ void Component::addToDesktop (int styleWanted, void* nativeWindowToAttachTo) peer->setConstrainer (currentConstrainer); repaint(); + + #if JUCE_LINUX + // Creating the peer Image on Linux will change the reported position of the window. If + // the Image creation is interleaved with the coming configureNotifyEvents the window + // will appear in the wrong position. To avoid this, we force the Image creation here, + // before handling any of the configureNotifyEvents. The Linux implementation of + // performAnyPendingRepaintsNow() will force update the peer position if necessary. + peer->performAnyPendingRepaintsNow(); + #endif + internalHierarchyChanged(); if (auto* handler = getAccessibilityHandler()) diff --git a/modules/juce_gui_basics/native/juce_linux_Windowing.cpp b/modules/juce_gui_basics/native/juce_linux_Windowing.cpp index a3c7762c87..e828e69c41 100644 --- a/modules/juce_gui_basics/native/juce_linux_Windowing.cpp +++ b/modules/juce_gui_basics/native/juce_linux_Windowing.cpp @@ -92,14 +92,8 @@ public: } //============================================================================== - void setBounds (const Rectangle& newBounds, bool isNowFullScreen) override + void forceSetBounds (const Rectangle& correctedNewBounds, bool isNowFullScreen) { - const auto correctedNewBounds = newBounds.withSize (jmax (1, newBounds.getWidth()), - jmax (1, newBounds.getHeight())); - - if (bounds == correctedNewBounds && fullScreen == isNowFullScreen) - return; - bounds = correctedNewBounds; updateScaleFactorFromNewBounds (bounds, false); @@ -120,6 +114,15 @@ public: } } + void setBounds (const Rectangle& newBounds, bool isNowFullScreen) override + { + const auto correctedNewBounds = newBounds.withSize (jmax (1, newBounds.getWidth()), + jmax (1, newBounds.getHeight())); + + if (bounds != correctedNewBounds || fullScreen != isNowFullScreen) + forceSetBounds (correctedNewBounds, isNowFullScreen); + } + Point getScreenPosition (bool physical) const { auto physicalParentPosition = XWindowSystem::getInstance()->getPhysicalParentScreenPosition(); @@ -437,12 +440,31 @@ private: if (! totalArea.isEmpty()) { - if (image.isNull() || image.getWidth() < totalArea.getWidth() + const auto wasImageNull = image.isNull(); + + if (wasImageNull || image.getWidth() < totalArea.getWidth() || image.getHeight() < totalArea.getHeight()) { image = XWindowSystem::getInstance()->createImage (isSemiTransparentWindow, totalArea.getWidth(), totalArea.getHeight(), useARGBImagesForRendering); + if (wasImageNull) + { + // After calling createImage() XWindowSystem::getWindowBounds() will return + // changed coordinates that look like the result of some position + // defaulting mechanism. If we handle a configureNotifyEvent after + // createImage() and before we would issue new, valid coordinates, we will + // apply these default, unwanted coordinates to our window. To avoid that + // we immediately send another positioning message to guarantee that the + // next configureNotifyEvent will read valid values. + // + // This issue only occurs right after peer creation, when the image is + // null. Updating when only the width or height is changed would lead to + // incorrect behaviour. + peer.forceSetBounds (ScalingHelpers::scaledScreenPosToUnscaled (peer.component, + peer.component.getBoundsInParent()), + peer.isFullScreen()); + } } startTimer (repaintTimerPeriod);