From 6c24b32bcd024c1478c3919375cbbf222a259de1 Mon Sep 17 00:00:00 2001 From: attila Date: Mon, 20 Jun 2022 11:23:53 +0200 Subject: [PATCH] DropShadower: Fix temporarily missing shadows, disable timer for non-desktop windows --- .../misc/juce_DropShadower.cpp | 110 +++++++++++++----- .../juce_gui_basics/misc/juce_DropShadower.h | 3 + 2 files changed, 85 insertions(+), 28 deletions(-) diff --git a/modules/juce_gui_basics/misc/juce_DropShadower.cpp b/modules/juce_gui_basics/misc/juce_DropShadower.cpp index 44604f2cfb..384331d12d 100644 --- a/modules/juce_gui_basics/misc/juce_DropShadower.cpp +++ b/modules/juce_gui_basics/misc/juce_DropShadower.cpp @@ -86,20 +86,87 @@ private: JUCE_DECLARE_NON_COPYABLE (ShadowWindow) }; -class DropShadower::ParentVisibilityChangedListener : public ComponentListener, - private Timer +class DropShadower::VirtualDesktopWatcher final : public ComponentListener, + private Timer +{ +public: + //============================================================================== + VirtualDesktopWatcher (Component& c) : component (&c) + { + component->addComponentListener (this); + update(); + } + + ~VirtualDesktopWatcher() override + { + stopTimer(); + + if (auto* c = component.get()) + c->removeComponentListener (this); + } + + bool shouldHideDropShadow() const + { + return hasReasonToHide; + } + + void addListener (void* listener, std::function cb) + { + listeners[listener] = std::move (cb); + } + + void removeListener (void* listener) + { + listeners.erase (listener); + } + + //============================================================================== + void componentParentHierarchyChanged (Component& c) override + { + if (component.get() == &c) + update(); + } + +private: + //============================================================================== + void update() + { + const auto newHasReasonToHide = [this]() + { + if (! component.wasObjectDeleted() && isWindows && component->isOnDesktop()) + { + startTimerHz (5); + return ! isWindowOnCurrentVirtualDesktop (component->getWindowHandle()); + } + + stopTimer(); + return false; + }(); + + if (std::exchange (hasReasonToHide, newHasReasonToHide) != newHasReasonToHide) + for (auto& l : listeners) + l.second(); + } + + void timerCallback() override + { + update(); + } + + //============================================================================== + WeakReference component; + const bool isWindows = (SystemStats::getOperatingSystemType() & SystemStats::Windows) != 0; + bool hasReasonToHide = false; + std::map> listeners; +}; + +class DropShadower::ParentVisibilityChangedListener : public ComponentListener { public: ParentVisibilityChangedListener (Component& r, ComponentListener& l) : root (&r), listener (&l) { updateParentHierarchy(); - - if ((SystemStats::getOperatingSystemType() & SystemStats::Windows) != 0) - { - isOnVirtualDesktop = isWindowOnCurrentVirtualDesktop (root->getWindowHandle()); - startTimerHz (5); - } } ~ParentVisibilityChangedListener() override @@ -121,8 +188,6 @@ public: updateParentHierarchy(); } - bool isWindowOnVirtualDesktop() const noexcept { return isOnVirtualDesktop; } - private: class ComponentWithWeakReference { @@ -165,26 +230,9 @@ private: withDifference (observedComponents, lastSeenComponents, [this] (auto& comp) { comp.addComponentListener (this); }); } - void timerCallback() override - { - WeakReference deletionChecker { static_cast (listener) }; - - const auto wasOnVirtualDesktop = std::exchange (isOnVirtualDesktop, - isWindowOnCurrentVirtualDesktop (root->getWindowHandle())); - - // on Windows, isWindowOnCurrentVirtualDesktop() may cause synchronous messages to be dispatched - // to the HWND so we need to check if the shadower is still valid after calling - if (deletionChecker == nullptr) - return; - - if (isOnVirtualDesktop != wasOnVirtualDesktop) - listener->componentVisibilityChanged (*root); - } - Component* root = nullptr; ComponentListener* listener = nullptr; std::set observedComponents; - bool isOnVirtualDesktop = true; JUCE_DECLARE_NON_COPYABLE (ParentVisibilityChangedListener) JUCE_DECLARE_NON_MOVEABLE (ParentVisibilityChangedListener) @@ -195,6 +243,9 @@ DropShadower::DropShadower (const DropShadow& ds) : shadow (ds) {} DropShadower::~DropShadower() { + if (virtualDesktopWatcher != nullptr) + virtualDesktopWatcher->removeListener (this); + if (owner != nullptr) { owner->removeComponentListener (this); @@ -228,6 +279,9 @@ void DropShadower::setOwner (Component* componentToFollow) visibilityChangedListener = std::make_unique (*owner, static_cast (*this)); + virtualDesktopWatcher = std::make_unique (*owner); + virtualDesktopWatcher->addListener (this, [this]() { updateShadows(); }); + updateShadows(); } } @@ -286,7 +340,7 @@ void DropShadower::updateShadows() && owner->isShowing() && owner->getWidth() > 0 && owner->getHeight() > 0 && (Desktop::canUseSemiTransparentWindows() || owner->getParentComponent() != nullptr) - && (visibilityChangedListener != nullptr && visibilityChangedListener->isWindowOnVirtualDesktop())) + && (virtualDesktopWatcher == nullptr || ! virtualDesktopWatcher->shouldHideDropShadow())) { while (shadowWindows.size() < 4) shadowWindows.add (new ShadowWindow (owner, shadow)); diff --git a/modules/juce_gui_basics/misc/juce_DropShadower.h b/modules/juce_gui_basics/misc/juce_DropShadower.h index 816b785275..08ad6b15cc 100644 --- a/modules/juce_gui_basics/misc/juce_DropShadower.h +++ b/modules/juce_gui_basics/misc/juce_DropShadower.h @@ -77,6 +77,9 @@ private: class ParentVisibilityChangedListener; std::unique_ptr visibilityChangedListener; + class VirtualDesktopWatcher; + std::unique_ptr virtualDesktopWatcher; + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DropShadower) JUCE_DECLARE_WEAK_REFERENCEABLE (DropShadower) };