Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose UIManager from Scheduler #33545

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions React/Fabric/RCTScheduler.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@

#import <react/renderer/componentregistry/ComponentDescriptorFactory.h>
#import <react/renderer/core/ComponentDescriptor.h>
#import <react/renderer/core/EventListener.h>
#import <react/renderer/core/LayoutConstraints.h>
#import <react/renderer/core/LayoutContext.h>
#import <react/renderer/mounting/MountingCoordinator.h>
#import <react/renderer/scheduler/SchedulerToolbox.h>
#import <react/renderer/scheduler/SurfaceHandler.h>
#import <react/renderer/uimanager/UIManager.h>
#import <react/utils/ContextContainer.h>

NS_ASSUME_NONNULL_BEGIN
Expand Down Expand Up @@ -47,6 +49,7 @@ NS_ASSUME_NONNULL_BEGIN
@interface RCTScheduler : NSObject

@property (atomic, weak, nullable) id<RCTSchedulerDelegate> delegate;
@property (readonly, nullable) facebook::react::UIManager const *uiManager;

- (instancetype)initWithToolbox:(facebook::react::SchedulerToolbox)toolbox;

Expand All @@ -64,6 +67,10 @@ NS_ASSUME_NONNULL_BEGIN

- (void)animationTick;

- (void)addEventListener:(std::shared_ptr<facebook::react::EventListener> const &)listener;

- (void)removeEventListener:(std::shared_ptr<facebook::react::EventListener> const &)listener;

@end

NS_ASSUME_NONNULL_END
15 changes: 15 additions & 0 deletions React/Fabric/RCTScheduler.mm
Original file line number Diff line number Diff line change
Expand Up @@ -193,4 +193,19 @@ - (void)onAllAnimationsComplete
}
}

- (void)addEventListener:(std::shared_ptr<EventListener> const &)listener
{
return _scheduler->addEventListener(listener);
}

- (void)removeEventListener:(std::shared_ptr<EventListener> const &)listener
{
return _scheduler->removeEventListener(listener);
}

- (facebook::react::UIManager const *)uiManager
{
return _scheduler->getUIManager().get();
}

@end
2 changes: 2 additions & 0 deletions React/Fabric/RCTSurfacePresenter.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ NS_ASSUME_NONNULL_BEGIN
@class RCTFabricSurface;
@class RCTImageLoader;
@class RCTMountingManager;
@class RCTScheduler;

/**
* Coordinates presenting of React Native Surfaces and represents application
Expand Down Expand Up @@ -53,6 +54,7 @@ NS_ASSUME_NONNULL_BEGIN
- (void)unregisterSurface:(RCTFabricSurface *)surface;

@property (readonly) RCTMountingManager *mountingManager;
@property (readonly, nullable) RCTScheduler *scheduler;

/*
* Allow callers to initialize a new fabric surface without adding Fabric as a Buck dependency.
Expand Down
10 changes: 5 additions & 5 deletions React/Fabric/RCTSurfacePresenter.mm
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ - (RCTMountingManager *)mountingManager
return _mountingManager;
}

- (RCTScheduler *_Nullable)_scheduler
- (RCTScheduler *_Nullable)scheduler
{
std::lock_guard<std::mutex> lock(_schedulerAccessMutex);
return _scheduler;
Expand Down Expand Up @@ -151,15 +151,15 @@ - (void)setRuntimeExecutor:(RuntimeExecutor)runtimeExecutor
- (void)registerSurface:(RCTFabricSurface *)surface
{
[_surfaceRegistry registerSurface:surface];
RCTScheduler *scheduler = [self _scheduler];
RCTScheduler *scheduler = [self scheduler];
if (scheduler) {
[scheduler registerSurface:surface.surfaceHandler];
}
}

- (void)unregisterSurface:(RCTFabricSurface *)surface
{
RCTScheduler *scheduler = [self _scheduler];
RCTScheduler *scheduler = [self scheduler];
if (scheduler) {
[scheduler unregisterSurface:surface.surfaceHandler];
}
Expand Down Expand Up @@ -188,7 +188,7 @@ - (UIView *)findComponentViewWithTag_DO_NOT_USE_DEPRECATED:(NSInteger)tag

- (BOOL)synchronouslyUpdateViewOnUIThread:(NSNumber *)reactTag props:(NSDictionary *)props
{
RCTScheduler *scheduler = [self _scheduler];
RCTScheduler *scheduler = [self scheduler];
if (!scheduler) {
return NO;
}
Expand All @@ -212,7 +212,7 @@ - (BOOL)synchronouslyUpdateViewOnUIThread:(NSNumber *)reactTag props:(NSDictiona

- (void)setupAnimationDriverWithSurfaceHandler:(facebook::react::SurfaceHandler const &)surfaceHandler
{
[[self _scheduler] setupAnimationDriver:surfaceHandler];
[[self scheduler] setupAnimationDriver:surfaceHandler];
}

- (BOOL)suspend
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ class Binding : public jni::HybridClass<Binding>,

static void registerNatives();

std::shared_ptr<Scheduler> getScheduler();

private:
void setConstraints(
jint surfaceId,
Expand Down Expand Up @@ -133,7 +135,6 @@ class Binding : public jni::HybridClass<Binding>,
std::shared_ptr<FabricMountingManager> mountingManager_;
std::shared_ptr<Scheduler> scheduler_;

std::shared_ptr<Scheduler> getScheduler();
std::shared_ptr<FabricMountingManager> verifyMountingManager(
std::string const &locationHint);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

#include "JFabricUIManager.h"

namespace facebook::react {

Binding *JFabricUIManager::getBinding() {
static const auto bindingField =
javaClassStatic()->getField<Binding::javaobject>("mBinding");

return getFieldValue(bindingField)->cthis();
}
} // namespace facebook::react
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

#pragma once

#include <fbjni/fbjni.h>
#include "Binding.h"

using namespace facebook::jni;

namespace facebook::react {

class JFabricUIManager : public JavaClass<JFabricUIManager> {
public:
static constexpr auto kJavaDescriptor =
"Lcom/facebook/react/fabric/FabricUIManager;";

Binding *getBinding();
};

} // namespace facebook::react
21 changes: 21 additions & 0 deletions ReactCommon/react/renderer/core/EventDispatcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ EventDispatcher::EventDispatcher(

void EventDispatcher::dispatchEvent(RawEvent &&rawEvent, EventPriority priority)
const {
// Allows the event listener to interrupt default event dispatch
if (eventListeners_.willDispatchEvent(rawEvent)) {
return;
}
getEventQueue(priority).enqueueEvent(std::move(rawEvent));
}

Expand All @@ -46,6 +50,10 @@ void EventDispatcher::dispatchStateUpdate(
}

void EventDispatcher::dispatchUniqueEvent(RawEvent &&rawEvent) const {
// Allows the event listener to interrupt default event dispatch
if (eventListeners_.willDispatchEvent(rawEvent)) {
return;
}
asynchronousBatchedQueue_->enqueueUniqueEvent(std::move(rawEvent));
}

Expand All @@ -62,5 +70,18 @@ const EventQueue &EventDispatcher::getEventQueue(EventPriority priority) const {
}
}

void EventDispatcher::addListener(
const std::shared_ptr<EventListener const> &listener) const {
eventListeners_.addListener(listener);
}

/*
* Removes provided event listener to the event dispatcher.
*/
void EventDispatcher::removeListener(
const std::shared_ptr<EventListener const> &listener) const {
eventListeners_.removeListener(listener);
}

} // namespace react
} // namespace facebook
15 changes: 15 additions & 0 deletions ReactCommon/react/renderer/core/EventDispatcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include <react/renderer/core/BatchedEventQueue.h>
#include <react/renderer/core/EventBeat.h>
#include <react/renderer/core/EventListener.h>
#include <react/renderer/core/EventPriority.h>
#include <react/renderer/core/EventQueueProcessor.h>
#include <react/renderer/core/StateUpdate.h>
Expand Down Expand Up @@ -52,13 +53,27 @@ class EventDispatcher {
void dispatchStateUpdate(StateUpdate &&stateUpdate, EventPriority priority)
const;

#pragma mark - Event listeners
/*
* Adds provided event listener to the event dispatcher.
*/
void addListener(const std::shared_ptr<EventListener const> &listener) const;

/*
* Removes provided event listener to the event dispatcher.
*/
void removeListener(
const std::shared_ptr<EventListener const> &listener) const;

private:
EventQueue const &getEventQueue(EventPriority priority) const;

std::unique_ptr<UnbatchedEventQueue> synchronousUnbatchedQueue_;
std::unique_ptr<BatchedEventQueue> synchronousBatchedQueue_;
std::unique_ptr<UnbatchedEventQueue> asynchronousUnbatchedQueue_;
std::unique_ptr<BatchedEventQueue> asynchronousBatchedQueue_;

mutable EventListenerContainer eventListeners_;
};

} // namespace react
Expand Down
39 changes: 39 additions & 0 deletions ReactCommon/react/renderer/core/EventListener.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

#include "EventListener.h"

namespace facebook::react {

bool EventListenerContainer::willDispatchEvent(const RawEvent &event) {
std::shared_lock<butter::shared_mutex> lock(mutex_);

bool handled = false;
for (auto const &listener : eventListeners_) {
handled = handled || listener->operator()(event);
}
return handled;
}

void EventListenerContainer::addListener(
const std::shared_ptr<EventListener const> &listener) {
std::unique_lock<butter::shared_mutex> lock(mutex_);

eventListeners_.push_back(listener);
}

void EventListenerContainer::removeListener(
const std::shared_ptr<EventListener const> &listener) {
std::unique_lock<butter::shared_mutex> lock(mutex_);

auto it = std::find(eventListeners_.begin(), eventListeners_.end(), listener);
if (it != eventListeners_.end()) {
eventListeners_.erase(it);
}
}

} // namespace facebook::react
44 changes: 44 additions & 0 deletions ReactCommon/react/renderer/core/EventListener.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

#pragma once

#include <string>

#include <react/renderer/core/RawEvent.h>

#include <butter/mutex.h>

namespace facebook {
namespace react {

/**
* Listener for events dispatched to JS runtime.
* Return `true` to interrupt default dispatch to JS event emitter, `false` to
* pass through to default handlers.
*/
using EventListener = std::function<bool(const RawEvent &event)>;

class EventListenerContainer {
public:
/*
* Invoke listeners in this container with the event.
* Returns true if event was handled by the listener, false to continue
* default dispatch.
*/
bool willDispatchEvent(const RawEvent &event);

void addListener(const std::shared_ptr<EventListener const> &listener);
void removeListener(const std::shared_ptr<EventListener const> &listener);

private:
butter::shared_mutex mutex_;
std::vector<std::shared_ptr<EventListener const>> eventListeners_;
};

} // namespace react
} // namespace facebook
18 changes: 18 additions & 0 deletions ReactCommon/react/renderer/scheduler/Scheduler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -368,5 +368,23 @@ ContextContainer::Shared Scheduler::getContextContainer() const {
return contextContainer_;
}

std::shared_ptr<UIManager> Scheduler::getUIManager() const {
return uiManager_;
}

void Scheduler::addEventListener(
const std::shared_ptr<EventListener const> &listener) {
if (eventDispatcher_->has_value()) {
eventDispatcher_->value().addListener(listener);
}
}

void Scheduler::removeEventListener(
const std::shared_ptr<EventListener const> &listener) {
if (eventDispatcher_->has_value()) {
eventDispatcher_->value().removeListener(listener);
}
}

} // namespace react
} // namespace facebook
9 changes: 9 additions & 0 deletions ReactCommon/react/renderer/scheduler/Scheduler.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <react/renderer/components/root/RootComponentDescriptor.h>
#include <react/renderer/core/ComponentDescriptor.h>
#include <react/renderer/core/EventEmitter.h>
#include <react/renderer/core/EventListener.h>
#include <react/renderer/core/LayoutConstraints.h>
#include <react/renderer/mounting/MountingOverrideDelegate.h>
#include <react/renderer/scheduler/InspectorData.h>
Expand Down Expand Up @@ -107,6 +108,14 @@ class Scheduler final : public UIManagerDelegate {
#pragma mark - ContextContainer
ContextContainer::Shared getContextContainer() const;

#pragma mark - UIManager
std::shared_ptr<UIManager> getUIManager() const;

#pragma mark - Event listeners
void addEventListener(const std::shared_ptr<EventListener const> &listener);
void removeEventListener(
const std::shared_ptr<EventListener const> &listener);

private:
friend class SurfaceHandler;

Expand Down