diff --git a/ReactCommon/fabric/events/EventEmitter.cpp b/ReactCommon/fabric/events/EventEmitter.cpp index 5b9e469aa..7961f964c 100644 --- a/ReactCommon/fabric/events/EventEmitter.cpp +++ b/ReactCommon/fabric/events/EventEmitter.cpp @@ -63,13 +63,24 @@ void EventEmitter::dispatchEvent( priority); } -void EventEmitter::setEnabled(bool enabled) const { - bool alreadyEnabled = eventTarget_ != nullptr; - if (enabled == alreadyEnabled) { +void EventEmitter::enable() const { + enableCounter_++; + toggleEventTargetOwnership_(); +} + +void EventEmitter::disable() const { + enableCounter_--; + toggleEventTargetOwnership_(); +} + +void EventEmitter::toggleEventTargetOwnership_() const { + bool shouldBeRetained = enableCounter_ > 0; + bool alreadyBeRetained = eventTarget_ != nullptr; + if (shouldBeRetained == alreadyBeRetained) { return; } - if (enabled) { + if (shouldBeRetained) { eventTarget_ = weakEventTarget_.lock(); weakEventTarget_.reset(); } else { @@ -78,9 +89,5 @@ void EventEmitter::setEnabled(bool enabled) const { } } -bool EventEmitter::getEnabled() const { - return eventTarget_ != nullptr; -} - } // namespace react } // namespace facebook diff --git a/ReactCommon/fabric/events/EventEmitter.h b/ReactCommon/fabric/events/EventEmitter.h index a3220eaed..1a51b982a 100644 --- a/ReactCommon/fabric/events/EventEmitter.h +++ b/ReactCommon/fabric/events/EventEmitter.h @@ -53,13 +53,15 @@ class EventEmitter { virtual ~EventEmitter() = default; /* - * Indicates that an event can be delivered to `eventTarget`. - * Callsite must acquire `DispatchMutex` to access those methods. - * The `setEnabled` operation is not guaranteed: sometimes `EventEmitter` - * can be re-enabled after disabling, sometimes not. + * `DispatchMutex` must be acquired before calling. + * Enables/disables event emitter. + * Enabled event emitter retains a pointer to `eventTarget` strongly (as + * `std::shared_ptr`) whereas disabled one weakly (as `std::weak_ptr`). + * The enable state is additive; a number of `enable` calls should be equal to + * a number of `disable` calls to release the event target. */ - void setEnabled(bool enabled) const; - bool getEnabled() const; + void enable() const; + void disable() const; protected: #ifdef ANDROID @@ -78,10 +80,13 @@ class EventEmitter { const EventPriority &priority = EventPriority::AsynchronousBatched) const; private: + void toggleEventTargetOwnership_() const; + mutable SharedEventTarget eventTarget_; mutable WeakEventTarget weakEventTarget_; Tag tag_; WeakEventDispatcher eventDispatcher_; + mutable int enableCounter_{0}; }; } // namespace react diff --git a/ReactCommon/fabric/uimanager/ShadowTree.cpp b/ReactCommon/fabric/uimanager/ShadowTree.cpp index 4207206a7..efa1de855 100644 --- a/ReactCommon/fabric/uimanager/ShadowTree.cpp +++ b/ReactCommon/fabric/uimanager/ShadowTree.cpp @@ -181,14 +181,14 @@ void ShadowTree::toggleEventEmitters( std::lock_guard lock(EventEmitter::DispatchMutex()); for (const auto &mutation : mutations) { - if (mutation.type == ShadowViewMutation::Delete) { - mutation.oldChildShadowView.eventEmitter->setEnabled(false); + if (mutation.type == ShadowViewMutation::Create) { + mutation.newChildShadowView.eventEmitter->enable(); } } for (const auto &mutation : mutations) { - if (mutation.type == ShadowViewMutation::Create) { - mutation.newChildShadowView.eventEmitter->setEnabled(true); + if (mutation.type == ShadowViewMutation::Delete) { + mutation.oldChildShadowView.eventEmitter->disable(); } } }