diff --git a/ReactCommon/fabric/core/events/EventDispatcher.h b/ReactCommon/fabric/core/events/EventDispatcher.h index 354e35ed477..40e5184a212 100644 --- a/ReactCommon/fabric/core/events/EventDispatcher.h +++ b/ReactCommon/fabric/core/events/EventDispatcher.h @@ -28,12 +28,16 @@ class EventDispatcher { public: + virtual EventTarget createEventTarget(const InstanceHandle &instanceHandle) const = 0; + + virtual void releaseEventTarget(const EventTarget &eventTarget) const = 0; + /* * Dispatches "raw" event using some event-delivery infrastructure. */ virtual void dispatchEvent( - const InstanceHandle &instanceHandle, - const std::string &name, + const EventTarget &eventTarget, + const std::string &type, const folly::dynamic &payload, const EventPriority &priority ) const = 0; diff --git a/ReactCommon/fabric/core/events/EventHandlers.cpp b/ReactCommon/fabric/core/events/EventHandlers.cpp index 6980b3e7c10..3d4ecc80488 100644 --- a/ReactCommon/fabric/core/events/EventHandlers.cpp +++ b/ReactCommon/fabric/core/events/EventHandlers.cpp @@ -17,6 +17,10 @@ EventHandlers::EventHandlers(const InstanceHandle &instanceHandle, const Tag &ta tag_(tag), eventDispatcher_(eventDispatcher) {} +EventHandlers::~EventHandlers() { + releaseEventTargetIfNeeded(); +} + void EventHandlers::dispatchEvent( const std::string &type, const folly::dynamic &payload, @@ -27,13 +31,39 @@ void EventHandlers::dispatchEvent( return; } + createEventTargetIfNeeded(); + // Mixing `target` into `payload`. assert(payload.isObject()); folly::dynamic extendedPayload = folly::dynamic::object("target", tag_); extendedPayload.merge_patch(payload); // TODO(T29610783): Reconsider using dynamic dispatch here. - eventDispatcher->dispatchEvent(instanceHandle_, type, extendedPayload, priority); + eventDispatcher->dispatchEvent(eventTarget_, type, extendedPayload, priority); +} + +void EventHandlers::createEventTargetIfNeeded() const { + std::lock_guard lock(mutex_); + + if (eventTarget_) { + return; + } + + auto &&eventDispatcher = eventDispatcher_.lock(); + assert(eventDispatcher); + eventTarget_ = eventDispatcher->createEventTarget(instanceHandle_); +} + +void EventHandlers::releaseEventTargetIfNeeded() const { + std::lock_guard lock(mutex_); + + if (!eventTarget_) { + return; + } + + auto &&eventDispatcher = eventDispatcher_.lock(); + assert(eventDispatcher); + eventDispatcher->releaseEventTarget(eventTarget_); } } // namespace react diff --git a/ReactCommon/fabric/core/events/EventHandlers.h b/ReactCommon/fabric/core/events/EventHandlers.h index f2ae16fd6f0..b55db7dc7e4 100644 --- a/ReactCommon/fabric/core/events/EventHandlers.h +++ b/ReactCommon/fabric/core/events/EventHandlers.h @@ -7,6 +7,7 @@ #pragma once #include +#include #include #include @@ -20,8 +21,6 @@ class EventHandlers; using SharedEventHandlers = std::shared_ptr; - - /* * Base class for all particular typed event handlers. * Stores `InstanceHandle` identifying a particular component and the pointer @@ -32,8 +31,8 @@ using SharedEventHandlers = std::shared_ptr; class EventHandlers { public: - virtual ~EventHandlers() = default; EventHandlers(const InstanceHandle &instanceHandle, const Tag &tag, const SharedEventDispatcher &eventDispatcher); + virtual ~EventHandlers(); protected: @@ -49,9 +48,14 @@ protected: private: + void createEventTargetIfNeeded() const; + void releaseEventTargetIfNeeded() const; + InstanceHandle instanceHandle_; Tag tag_; std::weak_ptr eventDispatcher_; + mutable EventTarget eventTarget_ {nullptr}; + mutable std::mutex mutex_; }; } // namespace react diff --git a/ReactCommon/fabric/uimanager/Scheduler.cpp b/ReactCommon/fabric/uimanager/Scheduler.cpp index d20e1f1b0a8..5a488f4da47 100644 --- a/ReactCommon/fabric/uimanager/Scheduler.cpp +++ b/ReactCommon/fabric/uimanager/Scheduler.cpp @@ -23,10 +23,14 @@ namespace facebook { namespace react { Scheduler::Scheduler() { - eventDispatcher_ = std::make_shared(); - auto componentDescriptorRegistry = ComponentDescriptorFactory::buildRegistry(eventDispatcher_); + auto &&eventDispatcher = std::make_shared(); + auto &&componentDescriptorRegistry = ComponentDescriptorFactory::buildRegistry(eventDispatcher); + uiManager_ = std::make_shared(componentDescriptorRegistry); uiManager_->setDelegate(this); + + eventDispatcher->setUIManager(uiManager_); + eventDispatcher_ = eventDispatcher; } Scheduler::~Scheduler() { diff --git a/ReactCommon/fabric/uimanager/Scheduler.h b/ReactCommon/fabric/uimanager/Scheduler.h index b63fbf666e2..6b6fae79dc1 100644 --- a/ReactCommon/fabric/uimanager/Scheduler.h +++ b/ReactCommon/fabric/uimanager/Scheduler.h @@ -73,7 +73,7 @@ private: SchedulerDelegate *delegate_; std::shared_ptr uiManager_; std::unordered_map shadowTreeRegistry_; - std::shared_ptr eventDispatcher_; + SharedSchedulerEventDispatcher eventDispatcher_; }; } // namespace react diff --git a/ReactCommon/fabric/uimanager/SchedulerEventDispatcher.cpp b/ReactCommon/fabric/uimanager/SchedulerEventDispatcher.cpp index ad9f4413636..5cd608667b6 100644 --- a/ReactCommon/fabric/uimanager/SchedulerEventDispatcher.cpp +++ b/ReactCommon/fabric/uimanager/SchedulerEventDispatcher.cpp @@ -10,13 +10,37 @@ namespace facebook { namespace react { +// TODO(T29874519): Get rid of "top" prefix once and for all. +/* + * Capitalizes the first letter of the event type and adds "top" prefix + * (e.g. "layout" becames "topLayout"). + */ +static std::string normalizeEventType(const std::string &type) { + std::string prefixedType = type; + prefixedType[0] = toupper(prefixedType[0]); + prefixedType.insert(0, "top"); + return prefixedType; +} + +void SchedulerEventDispatcher::setUIManager(std::shared_ptr uiManager) { + uiManager_ = uiManager; +} + +EventTarget SchedulerEventDispatcher::createEventTarget(const InstanceHandle &instanceHandle) const { + return uiManager_->createEventTarget(instanceHandle); +} + +void SchedulerEventDispatcher::releaseEventTarget(const EventTarget &eventTarget) const { + uiManager_->releaseEventTarget(eventTarget); +} + void SchedulerEventDispatcher::dispatchEvent( - const InstanceHandle &instanceHandle, - const std::string &name, + const EventTarget &eventTarget, + const std::string &type, const folly::dynamic &payload, const EventPriority &priority ) const { - // Some future magic here. + uiManager_->dispatchEvent(eventTarget, normalizeEventType(type), payload); } } // namespace react diff --git a/ReactCommon/fabric/uimanager/SchedulerEventDispatcher.h b/ReactCommon/fabric/uimanager/SchedulerEventDispatcher.h index 17cd7610951..d7f6e190c0f 100644 --- a/ReactCommon/fabric/uimanager/SchedulerEventDispatcher.h +++ b/ReactCommon/fabric/uimanager/SchedulerEventDispatcher.h @@ -9,11 +9,16 @@ #include #include +#include #include namespace facebook { namespace react { +class SchedulerEventDispatcher; + +using SharedSchedulerEventDispatcher = std::shared_ptr; + /* * Concrete EventDispatcher. */ @@ -22,12 +27,24 @@ class SchedulerEventDispatcher final: public: + void setUIManager(std::shared_ptr uiManager); + +#pragma mark - EventDispatcher + + EventTarget createEventTarget(const InstanceHandle &instanceHandle) const override; + + void releaseEventTarget(const EventTarget &eventTarget) const override; + void dispatchEvent( - const InstanceHandle &instanceHandle, - const std::string &name, + const EventTarget &eventTarget, + const std::string &type, const folly::dynamic &payload, const EventPriority &priority ) const override; + +private: + + std::shared_ptr uiManager_; }; } // namespace react