1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-11 23:54:18 +00:00

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

This commit is contained in:
attila 2022-06-20 11:23:53 +02:00
parent 3acc71f7df
commit 6c24b32bcd
2 changed files with 85 additions and 28 deletions

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));

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)
};