diff --git a/modules/juce_gui_basics/components/juce_Component.cpp b/modules/juce_gui_basics/components/juce_Component.cpp index 224e3b492d..b98e355b14 100644 --- a/modules/juce_gui_basics/components/juce_Component.cpp +++ b/modules/juce_gui_basics/components/juce_Component.cpp @@ -57,14 +57,57 @@ Component* Component::currentlyFocusedComponent = nullptr; class HierarchyChecker { public: - HierarchyChecker (Component* comp, const MouseEvent& originalEvent) - : me (originalEvent) + /* Creates a bail-out checker for comp and its ancestors, that will return true from + shouldBailOut() if all of comp's ancestors are destroyed. + @param comp a safe pointer to a component. The pointer will be updated to point + to the nearest non-null ancestor on each call to shouldBailOut. + */ + HierarchyChecker (Component::SafePointer* comp, const MouseEvent& originalEvent) + : closestAncestor (*comp), + me (originalEvent) { - for (; comp != nullptr; comp = comp->getParentComponent()) - hierarchy.emplace_back (comp); + for (Component* c = *comp; c != nullptr; c = c->getParentComponent()) + hierarchy.emplace_back (c); } Component* nearestNonNullParent() const + { + return closestAncestor; + } + + /* Searches for the closest ancestor, and returns true if the closest ancestor is nullptr. */ + bool shouldBailOut() const + { + closestAncestor = findNearestNonNullParent(); + return closestAncestor == nullptr; + } + + MouseEvent eventWithNearestParent() const + { + return { me.source, + me.position.toFloat(), + me.mods, + me.pressure, me.orientation, me.rotation, + me.tiltX, me.tiltY, + closestAncestor, + closestAncestor, + me.eventTime, + me.mouseDownPosition.toFloat(), + me.mouseDownTime, + me.getNumberOfClicks(), + me.mouseWasDraggedSinceMouseDown() }; + } + + template + void forEach (Callback&& callback) + { + for (auto& item : hierarchy) + if (item != nullptr) + callback (*item); + } + +private: + Component* findNearestNonNullParent() const { for (auto& comp : hierarchy) if (comp != nullptr) @@ -73,28 +116,7 @@ public: return nullptr; } - bool shouldBailOut() const - { - return nearestNonNullParent() == nullptr; - } - - MouseEvent eventWithNearestParent() const - { - auto* comp = nearestNonNullParent(); - return { me.source, - me.position.toFloat(), - me.mods, - me.pressure, me.orientation, me.rotation, - me.tiltX, me.tiltY, - comp, comp, - me.eventTime, - me.mouseDownPosition.toFloat(), - me.mouseDownTime, - me.getNumberOfClicks(), - me.mouseWasDraggedSinceMouseDown() }; - } - -private: + Component::SafePointer& closestAncestor; std::vector> hierarchy; const MouseEvent me; }; @@ -2083,33 +2105,36 @@ void Component::removeMouseListener (MouseListener* listenerToRemove) } //============================================================================== -void Component::internalMouseEnter (MouseInputSource source, Point relativePos, Time time) +void Component::internalMouseEnter (SafePointer target, MouseInputSource source, Point relativePos, Time time) { - if (isCurrentlyBlockedByAnotherModalComponent()) + if (target->isCurrentlyBlockedByAnotherModalComponent()) { // if something else is modal, always just show a normal mouse cursor source.showMouseCursor (MouseCursor::NormalCursor); return; } - if (flags.repaintOnMouseActivityFlag) - repaint(); + if (target->flags.repaintOnMouseActivityFlag) + target->repaint(); const auto me = makeMouseEvent (source, detail::PointerState().withPosition (relativePos), source.getCurrentModifiers(), - this, - this, + target, + target, time, relativePos, time, 0, false); - HierarchyChecker checker (this, me); - mouseEnter (me); + HierarchyChecker checker (&target, me); + target->mouseEnter (me); - flags.cachedMouseInsideComponent = true; + if (checker.shouldBailOut()) + return; + + target->flags.cachedMouseInsideComponent = true; if (checker.shouldBailOut()) return; @@ -2118,33 +2143,33 @@ void Component::internalMouseEnter (MouseInputSource source, Point relati MouseListenerList::sendMouseEvent (checker, &MouseListener::mouseEnter); } -void Component::internalMouseExit (MouseInputSource source, Point relativePos, Time time) +void Component::internalMouseExit (SafePointer target, MouseInputSource source, Point relativePos, Time time) { - if (isCurrentlyBlockedByAnotherModalComponent()) + if (target->isCurrentlyBlockedByAnotherModalComponent()) { // if something else is modal, always just show a normal mouse cursor source.showMouseCursor (MouseCursor::NormalCursor); return; } - if (flags.repaintOnMouseActivityFlag) - repaint(); + if (target->flags.repaintOnMouseActivityFlag) + target->repaint(); - flags.cachedMouseInsideComponent = false; + target->flags.cachedMouseInsideComponent = false; const auto me = makeMouseEvent (source, detail::PointerState().withPosition (relativePos), source.getCurrentModifiers(), - this, - this, + target, + target, time, relativePos, time, 0, false); - HierarchyChecker checker (this, me); - mouseExit (me); + HierarchyChecker checker (&target, me); + target->mouseExit (me); if (checker.shouldBailOut()) return; @@ -2153,7 +2178,8 @@ void Component::internalMouseExit (MouseInputSource source, Point relativ MouseListenerList::sendMouseEvent (checker, &MouseListener::mouseExit); } -void Component::internalMouseDown (MouseInputSource source, +void Component::internalMouseDown (SafePointer target, + MouseInputSource source, const detail::PointerState& relativePointerState, Time time) { @@ -2162,27 +2188,27 @@ void Component::internalMouseDown (MouseInputSource source, const auto me = makeMouseEvent (source, relativePointerState, source.getCurrentModifiers(), - this, - this, + target, + target, time, relativePointerState.position, time, source.getNumberOfMultipleClicks(), false); - HierarchyChecker checker (this, me); + HierarchyChecker checker (&target, me); - if (isCurrentlyBlockedByAnotherModalComponent()) + if (target->isCurrentlyBlockedByAnotherModalComponent()) { - flags.mouseDownWasBlocked = true; - internalModalInputAttempt(); + target->flags.mouseDownWasBlocked = true; + target->internalModalInputAttempt(); if (checker.shouldBailOut()) return; // If processing the input attempt has exited the modal loop, we'll allow the event // to be delivered.. - if (isCurrentlyBlockedByAnotherModalComponent()) + if (target->isCurrentlyBlockedByAnotherModalComponent()) { // allow blocked mouse-events to go to global listeners.. desktop.getMouseListeners().callChecked (checker, [&] (MouseListener& l) { l.mouseDown (checker.eventWithNearestParent()); }); @@ -2190,28 +2216,26 @@ void Component::internalMouseDown (MouseInputSource source, } } - flags.mouseDownWasBlocked = false; + target->flags.mouseDownWasBlocked = false; - for (auto* c = this; c != nullptr; c = c->parentComponent) + checker.forEach ([] (auto& comp) { - if (c->isBroughtToFrontOnMouseClick()) - { - c->toFront (true); - - if (checker.shouldBailOut()) - return; - } - } - - grabKeyboardFocusInternal (focusChangedByMouseClick, true, FocusChangeDirection::unknown); + if (comp.isBroughtToFrontOnMouseClick()) + comp.toFront (true); + }); if (checker.shouldBailOut()) return; - if (flags.repaintOnMouseActivityFlag) - repaint(); + target->grabKeyboardFocusInternal (focusChangedByMouseClick, true, FocusChangeDirection::unknown); - mouseDown (me); + if (checker.shouldBailOut()) + return; + + if (target->flags.repaintOnMouseActivityFlag) + target->repaint(); + + target->mouseDown (me); if (checker.shouldBailOut()) return; @@ -2221,25 +2245,28 @@ void Component::internalMouseDown (MouseInputSource source, MouseListenerList::sendMouseEvent (checker, &MouseListener::mouseDown); } -void Component::internalMouseUp (MouseInputSource source, +void Component::internalMouseUp (SafePointer target, + MouseInputSource source, const detail::PointerState& relativePointerState, Time time, const ModifierKeys oldModifiers) { + const auto originalTarget = target; + const auto me = makeMouseEvent (source, relativePointerState, oldModifiers, - this, - this, + target, + target, time, - getLocalPoint (nullptr, source.getLastMouseDownPosition()), + target->getLocalPoint (nullptr, source.getLastMouseDownPosition()), source.getLastMouseDownTime(), source.getNumberOfMultipleClicks(), source.isLongPressOrDrag()); - HierarchyChecker checker (this, me); + HierarchyChecker checker (&target, me); - if (flags.mouseDownWasBlocked && isCurrentlyBlockedByAnotherModalComponent()) + if (target->flags.mouseDownWasBlocked && target->isCurrentlyBlockedByAnotherModalComponent()) { // Global listeners still need to know about the mouse up auto& desktop = Desktop::getInstance(); @@ -2247,10 +2274,10 @@ void Component::internalMouseUp (MouseInputSource source, return; } - if (flags.repaintOnMouseActivityFlag) - repaint(); + if (target->flags.repaintOnMouseActivityFlag) + target->repaint(); - mouseUp (me); + target->mouseUp (me); if (checker.shouldBailOut()) return; @@ -2266,8 +2293,8 @@ void Component::internalMouseUp (MouseInputSource source, // check for double-click if (me.getNumberOfClicks() >= 2) { - if (checker.nearestNonNullParent() == this) - mouseDoubleClick (checker.eventWithNearestParent()); + if (target == originalTarget) + target->mouseDoubleClick (checker.eventWithNearestParent()); if (checker.shouldBailOut()) return; @@ -2277,24 +2304,24 @@ void Component::internalMouseUp (MouseInputSource source, } } -void Component::internalMouseDrag (MouseInputSource source, const detail::PointerState& relativePointerState, Time time) +void Component::internalMouseDrag (SafePointer target, MouseInputSource source, const detail::PointerState& relativePointerState, Time time) { - if (! isCurrentlyBlockedByAnotherModalComponent()) + if (! target->isCurrentlyBlockedByAnotherModalComponent()) { const auto me = makeMouseEvent (source, relativePointerState, source.getCurrentModifiers(), - this, - this, + target, + target, time, - getLocalPoint (nullptr, source.getLastMouseDownPosition()), + target->getLocalPoint (nullptr, source.getLastMouseDownPosition()), source.getLastMouseDownTime(), source.getNumberOfMultipleClicks(), source.isLongPressOrDrag()); - HierarchyChecker checker (this, me); + HierarchyChecker checker (&target, me); - mouseDrag (me); + target->mouseDrag (me); if (checker.shouldBailOut()) return; @@ -2304,11 +2331,11 @@ void Component::internalMouseDrag (MouseInputSource source, const detail::Pointe } } -void Component::internalMouseMove (MouseInputSource source, Point relativePos, Time time) +void Component::internalMouseMove (SafePointer target, MouseInputSource source, Point relativePos, Time time) { auto& desktop = Desktop::getInstance(); - if (isCurrentlyBlockedByAnotherModalComponent()) + if (target->isCurrentlyBlockedByAnotherModalComponent()) { // allow blocked mouse-events to go to global listeners.. desktop.sendMouseMove(); @@ -2318,17 +2345,17 @@ void Component::internalMouseMove (MouseInputSource source, Point relativ const auto me = makeMouseEvent (source, detail::PointerState().withPosition (relativePos), source.getCurrentModifiers(), - this, - this, + target, + target, time, relativePos, time, 0, false); - HierarchyChecker checker (this, me); + HierarchyChecker checker (&target, me); - mouseMove (me); + target->mouseMove (me); if (checker.shouldBailOut()) return; @@ -2338,7 +2365,7 @@ void Component::internalMouseMove (MouseInputSource source, Point relativ } } -void Component::internalMouseWheel (MouseInputSource source, Point relativePos, +void Component::internalMouseWheel (SafePointer target, MouseInputSource source, Point relativePos, Time time, const MouseWheelDetails& wheel) { auto& desktop = Desktop::getInstance(); @@ -2346,24 +2373,24 @@ void Component::internalMouseWheel (MouseInputSource source, Point relati const auto me = makeMouseEvent (source, detail::PointerState().withPosition (relativePos), source.getCurrentModifiers(), - this, - this, + target, + target, time, relativePos, time, 0, false); - HierarchyChecker checker (this, me); + HierarchyChecker checker (&target, me); - if (isCurrentlyBlockedByAnotherModalComponent()) + if (target->isCurrentlyBlockedByAnotherModalComponent()) { // allow blocked mouse-events to go to global listeners.. desktop.mouseListeners.callChecked (checker, [&] (MouseListener& l) { l.mouseWheelMove (me, wheel); }); } else { - mouseWheelMove (me, wheel); + target->mouseWheelMove (me, wheel); if (checker.shouldBailOut()) return; @@ -2375,7 +2402,7 @@ void Component::internalMouseWheel (MouseInputSource source, Point relati } } -void Component::internalMagnifyGesture (MouseInputSource source, Point relativePos, +void Component::internalMagnifyGesture (SafePointer target, MouseInputSource source, Point relativePos, Time time, float amount) { auto& desktop = Desktop::getInstance(); @@ -2383,24 +2410,24 @@ void Component::internalMagnifyGesture (MouseInputSource source, Point re const auto me = makeMouseEvent (source, detail::PointerState().withPosition (relativePos), source.getCurrentModifiers(), - this, - this, + target, + target, time, relativePos, time, 0, false); - HierarchyChecker checker (this, me); + HierarchyChecker checker (&target, me); - if (isCurrentlyBlockedByAnotherModalComponent()) + if (target->isCurrentlyBlockedByAnotherModalComponent()) { // allow blocked mouse-events to go to global listeners.. desktop.mouseListeners.callChecked (checker, [&] (MouseListener& l) { l.mouseMagnify (me, amount); }); } else { - mouseMagnify (me, amount); + target->mouseMagnify (me, amount); if (checker.shouldBailOut()) return; diff --git a/modules/juce_gui_basics/components/juce_Component.h b/modules/juce_gui_basics/components/juce_Component.h index 14a103a1be..620952f538 100644 --- a/modules/juce_gui_basics/components/juce_Component.h +++ b/modules/juce_gui_basics/components/juce_Component.h @@ -2692,14 +2692,14 @@ private: uint8 componentTransparency = 0; //============================================================================== - void internalMouseEnter (MouseInputSource, Point, Time); - void internalMouseExit (MouseInputSource, Point, Time); - void internalMouseDown (MouseInputSource, const detail::PointerState&, Time); - void internalMouseUp (MouseInputSource, const detail::PointerState&, Time, ModifierKeys oldModifiers); - void internalMouseDrag (MouseInputSource, const detail::PointerState&, Time); - void internalMouseMove (MouseInputSource, Point, Time); - void internalMouseWheel (MouseInputSource, Point, Time, const MouseWheelDetails&); - void internalMagnifyGesture (MouseInputSource, Point, Time, float); + static void internalMouseEnter (SafePointer, MouseInputSource, Point, Time); + static void internalMouseExit (SafePointer, MouseInputSource, Point, Time); + static void internalMouseDown (SafePointer, MouseInputSource, const detail::PointerState&, Time); + static void internalMouseUp (SafePointer, MouseInputSource, const detail::PointerState&, Time, ModifierKeys oldModifiers); + static void internalMouseDrag (SafePointer, MouseInputSource, const detail::PointerState&, Time); + static void internalMouseMove (SafePointer, MouseInputSource, Point, Time); + static void internalMouseWheel (SafePointer, MouseInputSource, Point, Time, const MouseWheelDetails&); + static void internalMagnifyGesture (SafePointer, MouseInputSource, Point, Time, float); void internalBroughtToFront(); void internalKeyboardFocusGain (FocusChangeType, const WeakReference&, FocusChangeDirection); void internalKeyboardFocusGain (FocusChangeType); diff --git a/modules/juce_gui_basics/detail/juce_ComponentHelpers.h b/modules/juce_gui_basics/detail/juce_ComponentHelpers.h index e1892731e1..f63c11b12d 100644 --- a/modules/juce_gui_basics/detail/juce_ComponentHelpers.h +++ b/modules/juce_gui_basics/detail/juce_ComponentHelpers.h @@ -259,7 +259,7 @@ struct ComponentHelpers for (auto& ms : Desktop::getInstance().getMouseSources()) if (auto* c = ms.getComponentUnderMouse()) if (modalWouldBlockComponent (*c, &modal)) - (c->*function) (ms, SH::screenPosToLocalPos (*c, ms.getScreenPosition()), Time::getCurrentTime()); + function (c, ms, SH::screenPosToLocalPos (*c, ms.getScreenPosition()), Time::getCurrentTime()); } class ModalComponentManagerChangeNotifier diff --git a/modules/juce_gui_basics/detail/juce_MouseInputSourceImpl.h b/modules/juce_gui_basics/detail/juce_MouseInputSourceImpl.h index 5001a4158e..68b68ce56c 100644 --- a/modules/juce_gui_basics/detail/juce_MouseInputSourceImpl.h +++ b/modules/juce_gui_basics/detail/juce_MouseInputSourceImpl.h @@ -117,68 +117,76 @@ public: void sendMouseEnter (Component& comp, const detail::PointerState& pointerState, Time time) { JUCE_MOUSE_EVENT_DBG ("enter", pointerState.position) - comp.internalMouseEnter (MouseInputSource (this), - SH::screenPosToLocalPos (comp, pointerState.position), - time); + Component::internalMouseEnter (&comp, + MouseInputSource (this), + SH::screenPosToLocalPos (comp, pointerState.position), + time); } void sendMouseExit (Component& comp, const detail::PointerState& pointerState, Time time) { JUCE_MOUSE_EVENT_DBG ("exit", pointerState.position) - comp.internalMouseExit (MouseInputSource (this), - SH::screenPosToLocalPos (comp, pointerState.position), - time); + Component::internalMouseExit (&comp, + MouseInputSource (this), + SH::screenPosToLocalPos (comp, pointerState.position), + time); } void sendMouseMove (Component& comp, const detail::PointerState& pointerState, Time time) { JUCE_MOUSE_EVENT_DBG ("move", pointerState.position) - comp.internalMouseMove (MouseInputSource (this), - SH::screenPosToLocalPos (comp, pointerState.position), - time); + Component::internalMouseMove (&comp, + MouseInputSource (this), + SH::screenPosToLocalPos (comp, pointerState.position), + time); } void sendMouseDown (Component& comp, const detail::PointerState& pointerState, Time time) { JUCE_MOUSE_EVENT_DBG ("down", pointerState.position) - comp.internalMouseDown (MouseInputSource (this), - pointerState.withPosition (SH::screenPosToLocalPos (comp, pointerState.position)), - time); + Component::internalMouseDown (&comp, + MouseInputSource (this), + pointerState.withPosition (SH::screenPosToLocalPos (comp, pointerState.position)), + time); } void sendMouseDrag (Component& comp, const detail::PointerState& pointerState, Time time) { JUCE_MOUSE_EVENT_DBG ("drag", pointerState.position) - comp.internalMouseDrag (MouseInputSource (this), - pointerState.withPosition (SH::screenPosToLocalPos (comp, pointerState.position)), - time); + Component::internalMouseDrag (&comp, + MouseInputSource (this), + pointerState.withPosition (SH::screenPosToLocalPos (comp, pointerState.position)), + time); } void sendMouseUp (Component& comp, const detail::PointerState& pointerState, Time time, ModifierKeys oldMods) { JUCE_MOUSE_EVENT_DBG ("up", pointerState.position) - comp.internalMouseUp (MouseInputSource (this), - pointerState.withPosition (SH::screenPosToLocalPos (comp, pointerState.position)), - time, - oldMods); + Component::internalMouseUp (&comp, + MouseInputSource (this), + pointerState.withPosition (SH::screenPosToLocalPos (comp, pointerState.position)), + time, + oldMods); } void sendMouseWheel (Component& comp, Point screenPos, Time time, const MouseWheelDetails& wheel) { JUCE_MOUSE_EVENT_DBG ("wheel", screenPos) - comp.internalMouseWheel (MouseInputSource (this), - SH::screenPosToLocalPos (comp, screenPos), - time, - wheel); + Component::internalMouseWheel (&comp, + MouseInputSource (this), + SH::screenPosToLocalPos (comp, screenPos), + time, + wheel); } void sendMagnifyGesture (Component& comp, Point screenPos, Time time, float amount) { JUCE_MOUSE_EVENT_DBG ("magnify", screenPos) - comp.internalMagnifyGesture (MouseInputSource (this), - SH::screenPosToLocalPos (comp, screenPos), - time, - amount); + Component::internalMagnifyGesture (&comp, + MouseInputSource (this), + SH::screenPosToLocalPos (comp, screenPos), + time, + amount); } #undef JUCE_MOUSE_EVENT_DBG