Browse Source

DropShadower: Fix temporarily missing shadows, disable timer for non-desktop windows

v7.0.9
attila 3 years ago
parent
commit
6c24b32bcd
2 changed files with 85 additions and 28 deletions
  1. +82
    -28
      modules/juce_gui_basics/misc/juce_DropShadower.cpp
  2. +3
    -0
      modules/juce_gui_basics/misc/juce_DropShadower.h

+ 82
- 28
modules/juce_gui_basics/misc/juce_DropShadower.cpp View File

@@ -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<void()> 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> component;
const bool isWindows = (SystemStats::getOperatingSystemType() & SystemStats::Windows) != 0;
bool hasReasonToHide = false;
std::map<void*, std::function<void()>> 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<DropShadower> deletionChecker { static_cast<DropShadower*> (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<ComponentWithWeakReference> 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<ParentVisibilityChangedListener> (*owner,
static_cast<ComponentListener&> (*this));
virtualDesktopWatcher = std::make_unique<VirtualDesktopWatcher> (*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));


+ 3
- 0
modules/juce_gui_basics/misc/juce_DropShadower.h View File

@@ -77,6 +77,9 @@ private:
class ParentVisibilityChangedListener;
std::unique_ptr<ParentVisibilityChangedListener> visibilityChangedListener;
class VirtualDesktopWatcher;
std::unique_ptr<VirtualDesktopWatcher> virtualDesktopWatcher;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DropShadower)
JUCE_DECLARE_WEAK_REFERENCEABLE (DropShadower)
};


Loading…
Cancel
Save