From f8d38edcd412d96534cc18058437818b5232356e Mon Sep 17 00:00:00 2001 From: reuk Date: Thu, 20 Jul 2023 13:42:56 +0100 Subject: [PATCH] X11: Use the _NET_WM_STATE_HIDDEN property to determine whether peers are visible on-screen Running under Gnome, calling ComponentPeer::forceSetBounds immediately after creating a new peer causes the peer to emit a visibility-changed event because the window manager sometimes reports that the new window is in IconicState. _NET_WM_STATE_HIDDEN seems to more accurately reflect whether the window is really minimised or off-screen. --- .../native/juce_Windowing_linux.cpp | 3 +- .../native/juce_XWindowSystem_linux.cpp | 79 +++++++++---------- .../native/juce_XWindowSystem_linux.h | 2 + 3 files changed, 41 insertions(+), 43 deletions(-) diff --git a/modules/juce_gui_basics/native/juce_Windowing_linux.cpp b/modules/juce_gui_basics/native/juce_Windowing_linux.cpp index c73b07dd02..06880521a1 100644 --- a/modules/juce_gui_basics/native/juce_Windowing_linux.cpp +++ b/modules/juce_gui_basics/native/juce_Windowing_linux.cpp @@ -464,8 +464,7 @@ private: // 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 (detail::ScalingHelpers::scaledScreenPosToUnscaled (peer.component, - peer.component.getBoundsInParent()), + peer.forceSetBounds (detail::ScalingHelpers::scaledScreenPosToUnscaled (peer.component, peer.component.getBoundsInParent()), peer.isFullScreen()); } } diff --git a/modules/juce_gui_basics/native/juce_XWindowSystem_linux.cpp b/modules/juce_gui_basics/native/juce_XWindowSystem_linux.cpp index 0940ef3334..d75a6f8f39 100644 --- a/modules/juce_gui_basics/native/juce_XWindowSystem_linux.cpp +++ b/modules/juce_gui_basics/native/juce_XWindowSystem_linux.cpp @@ -1932,23 +1932,9 @@ void XWindowSystem::setMinimised (::Window windowH, bool shouldBeMinimised) cons } } -bool XWindowSystem::isMinimised (::Window windowH) const +bool XWindowSystem::isMinimised (::Window w) const { - jassert (windowH != 0); - - XWindowSystemUtilities::ScopedXLock xLock; - XWindowSystemUtilities::GetXProperty prop (display, windowH, atoms.state, 0, 64, false, atoms.state); - - if (prop.success && prop.actualType == atoms.state - && prop.actualFormat == 32 && prop.numItems > 0) - { - unsigned long state; - memcpy (&state, prop.data, sizeof (unsigned long)); - - return state == IconicState; - } - - return false; + return isHidden (w); } void XWindowSystem::setMaximised (::Window windowH, bool shouldBeMaximised) const @@ -3732,35 +3718,46 @@ void XWindowSystem::handleGravityNotify (LinuxComponentPeer* peer) const peer->handleMovedOrResized(); } +bool XWindowSystem::isIconic (Window w) const +{ + jassert (w != 0); + + XWindowSystemUtilities::ScopedXLock xLock; + XWindowSystemUtilities::GetXProperty prop (display, w, atoms.state, 0, 64, false, atoms.state); + + if (prop.success && prop.actualType == atoms.state + && prop.actualFormat == 32 && prop.numItems > 0) + { + unsigned long state; + memcpy (&state, prop.data, sizeof (unsigned long)); + + return state == IconicState; + } + + return false; +} + +bool XWindowSystem::isHidden (Window w) const +{ + XWindowSystemUtilities::ScopedXLock xLock; + XWindowSystemUtilities::GetXProperty prop (display, w, atoms.windowState, 0, 128, false, XA_ATOM); + + if (! (prop.success && prop.actualFormat == 32 && prop.actualType == XA_ATOM)) + return false; + + const auto* data = unalignedPointerCast (prop.data); + const auto end = data + prop.numItems; + + return std::find (data, end, atoms.windowStateHidden) != end; +} + void XWindowSystem::propertyNotifyEvent (LinuxComponentPeer* peer, const XPropertyEvent& event) const { - const auto isStateChangeEvent = [&] + if ((event.atom == atoms.state && isIconic (event.window)) + || (event.atom == atoms.windowState && isHidden (event.window))) { - if (event.atom != atoms.state) - return false; - - return isMinimised (event.window); - }; - - const auto isHidden = [&] - { - if (event.atom != atoms.windowState) - return false; - - XWindowSystemUtilities::ScopedXLock xLock; - XWindowSystemUtilities::GetXProperty prop (display, event.window, atoms.windowState, 0, 128, false, XA_ATOM); - - if (! (prop.success && prop.actualFormat == 32 && prop.actualType == XA_ATOM)) - return false; - - const auto* data = unalignedPointerCast (prop.data); - const auto end = data + prop.numItems; - - return std::find (data, end, atoms.windowStateHidden) != end; - }; - - if (isStateChangeEvent() || isHidden()) dismissBlockingModals (peer); + } if (event.atom == XWindowSystemUtilities::Atoms::getIfExists (display, "_NET_FRAME_EXTENTS")) peer->updateBorderSize(); diff --git a/modules/juce_gui_basics/native/juce_XWindowSystem_linux.h b/modules/juce_gui_basics/native/juce_XWindowSystem_linux.h index 7fd30a8473..4c906a73ee 100644 --- a/modules/juce_gui_basics/native/juce_XWindowSystem_linux.h +++ b/modules/juce_gui_basics/native/juce_XWindowSystem_linux.h @@ -294,6 +294,8 @@ private: void updateModifierMappings() const; long getUserTime (::Window) const; + bool isHidden (Window) const; + bool isIconic (Window) const; void initialiseXSettings();