Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
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
40 changes: 26 additions & 14 deletions shell/platform/darwin/macos/framework/Headers/FLEEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,34 +26,46 @@ FLUTTER_EXPORT
/**
* Initializes an engine with the given viewController.
*
* @param viewController The view controller associated with this engine. If nil, the engine
* will be run headless.
* @param labelPrefix Currently unused; in the future, may be used for labelling threads
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would it help to name this "theadLabelPrefix"?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm deliberately using the same name as iOS, since I am hoping to merge the public engine header between macOS and iOS sometime soon.

* as with the iOS FlutterEngine.
* @param project The project configuration. If nil, a default FLEDartProject will be used.
*/
- (nonnull instancetype)initWithViewController:(nullable FLEViewController*)viewController
project:(nullable FLEDartProject*)project
NS_DESIGNATED_INITIALIZER;
- (nonnull instancetype)initWithName:(nonnull NSString*)labelPrefix
project:(nullable FLEDartProject*)project;

/**
* Runs `main()` from this engine's project.
* Initializes an engine with the given viewController.
*
* @return YES if the engine launched successfully.
* @param labelPrefix Currently unused; in the future, may be used for labelling threads
* as with the iOS FlutterEngine.
* @param project The project configuration. If nil, a default FLEDartProject will be used.
*/
- (BOOL)run;
- (nonnull instancetype)initWithName:(nonnull NSString*)labelPrefix
project:(nullable FLEDartProject*)project
allowHeadlessExecution:(BOOL)allowHeadlessExecution NS_DESIGNATED_INITIALIZER;

- (nonnull instancetype)init NS_UNAVAILABLE;

/**
* The `FLEDartProject` associated with this engine. If nil, a default will be used for `run`.
* Runs a Dart program on an Isolate from the main Dart library (i.e. the library that
* contains `main()`).
*
* The first call to this method will create a new Isolate. Subsequent calls will return
* immediately.
*
* TODO(stuartmorgan): Remove this once FLEViewController takes the project as an initializer
* argument. Blocked on currently needing to create it from a XIB due to the view issues
* described in https://github.com/google/flutter-desktop-embedding/issues/10.
* @param entrypoint The name of a top-level function from the same Dart
* library that contains the app's main() function. If this is nil, it will
* default to `main()`. If it is not the app's main() function, that function
* must be decorated with `@pragma(vm:entry-point)` to ensure the method is not
* tree-shaken by the Dart compiler.
* @return YES if the call succeeds in creating and running a Flutter Engine instance; NO otherwise.
*/
@property(nonatomic, nullable) FLEDartProject* project;
- (BOOL)runWithEntrypoint:(nullable NSString*)entrypoint;

/**
* The `FLEViewController` associated with this engine, if any.
*/
@property(nonatomic, nullable, readonly, weak) FLEViewController* viewController;
@property(nonatomic, nullable, weak) FLEViewController* viewController;

/**
* The `FlutterBinaryMessenger` for communicating with this engine.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,16 @@ FLUTTER_EXPORT
@property(nonatomic) FlutterMouseTrackingMode mouseTrackingMode;

/**
* Launches the Flutter engine with the provided project.
* Initializes a controller that will run the given project.
*
* @param project The project to run in this view controller. If nil, a default `FLEDartProject`
* will be used.
* @return YES if the engine launched successfully.
*/
- (BOOL)launchEngineWithProject:(nullable FLEDartProject*)project;
- (nonnull instancetype)initWithProject:(nullable FLEDartProject*)project NS_DESIGNATED_INITIALIZER;

- (nonnull instancetype)initWithNibName:(nullable NSString*)nibNameOrNil
bundle:(nullable NSBundle*)nibBundleOrNil
NS_DESIGNATED_INITIALIZER;
- (nonnull instancetype)initWithCoder:(nonnull NSCoder*)nibNameOrNil NS_DESIGNATED_INITIALIZER;

@end
93 changes: 76 additions & 17 deletions shell/platform/darwin/macos/framework/Source/FLEEngine.mm
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ - (bool)engineCallbackOnMakeResourceCurrent;
*/
- (void)engineCallbackOnPlatformMessage:(const FlutterPlatformMessage*)message;

/**
* Shuts the Flutter engine if it is running.
*/
- (void)shutDownEngine;

@end

#pragma mark -
Expand Down Expand Up @@ -120,38 +125,46 @@ @implementation FLEEngine {
// The embedding-API-level engine object.
FlutterEngine _engine;

// The project being run by this engine.
FLEDartProject* _project;

// The context provided to the Flutter engine for resource loading.
NSOpenGLContext* _resourceContext;

// A mapping of channel names to the registered handlers for those channels.
NSMutableDictionary<NSString*, FlutterBinaryMessageHandler>* _messageHandlers;

// Whether the engine can continue running after the view controller is removed.
BOOL _allowHeadlessExecution;
}

- (instancetype)init {
return [self initWithViewController:nil project:nil];
- (instancetype)initWithName:(NSString*)labelPrefix project:(FLEDartProject*)project {
return [self initWithName:labelPrefix project:project allowHeadlessExecution:YES];
}

- (instancetype)initWithViewController:(FLEViewController*)viewController
project:(FLEDartProject*)project {
- (instancetype)initWithName:(NSString*)labelPrefix
project:(FLEDartProject*)project
allowHeadlessExecution:(BOOL)allowHeadlessExecution {
self = [super init];
NSAssert(self, @"Super init cannot be nil");

_viewController = viewController;
_project = project ?: [[FLEDartProject alloc] init];
_messageHandlers = [[NSMutableDictionary alloc] init];

return self;
}

- (void)dealloc {
if (FlutterEngineShutdown(_engine) == kSuccess) {
_engine = NULL;
}
[self shutDownEngine];
}

- (void)setProject:(FLEDartProject*)project {
_project = project ?: [[FLEDartProject alloc] init];
}
- (BOOL)runWithEntrypoint:(NSString*)entrypoint {
if (self.running) {
return NO;
}

- (BOOL)run {
if (_engine != NULL) {
if (!_allowHeadlessExecution && !_viewController) {
NSLog(@"Attempted to run an engine with no view controller without headless mode enabled.");
return NO;
}

Expand All @@ -175,16 +188,27 @@ - (BOOL)run {
flutterArguments.command_line_argc = static_cast<int>(arguments.size());
flutterArguments.command_line_argv = &arguments[0];
flutterArguments.platform_message_callback = (FlutterPlatformMessageCallback)OnPlatformMessage;
flutterArguments.custom_dart_entrypoint = entrypoint.UTF8String;

FlutterEngineResult result = FlutterEngineRun(
FLUTTER_ENGINE_VERSION, &rendererConfig, &flutterArguments, (__bridge void*)(self), &_engine);
if (result != kSuccess) {
NSLog(@"Failed to start Flutter engine: error %d", result);
return NO;
}
[self updateWindowMetrics];
return YES;
}

- (void)setViewController:(FLEViewController*)controller {
_viewController = controller;
if (!controller && !_allowHeadlessExecution) {
[self shutDownEngine];
_resourceContext = nil;
}
[self updateWindowMetrics];
}

- (id<FlutterBinaryMessenger>)binaryMessenger {
// TODO(stuartmorgan): Switch to FlutterBinaryMessengerRelay to avoid plugins
// keeping the engine alive.
Expand All @@ -193,11 +217,33 @@ - (BOOL)run {

#pragma mark - Framework-internal methods

- (void)updateWindowMetricsWithSize:(CGSize)size pixelRatio:(double)pixelRatio {
- (BOOL)running {
return _engine != nullptr;
}

- (NSOpenGLContext*)resourceContext {
if (!_resourceContext) {
NSOpenGLPixelFormatAttribute attributes[] = {
NSOpenGLPFAColorSize, 24, NSOpenGLPFAAlphaSize, 8, NSOpenGLPFADoubleBuffer, 0,
};
NSOpenGLPixelFormat* pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes];
_resourceContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:nil];
}
return _resourceContext;
}

- (void)updateWindowMetrics {
if (!_engine) {
return;
}
NSView* view = _viewController.view;
CGSize scaledSize = [view convertRectToBacking:view.bounds].size;
double pixelRatio = view.bounds.size.width == 0 ? 1 : scaledSize.width / view.bounds.size.width;

const FlutterWindowMetricsEvent event = {
.struct_size = sizeof(event),
.width = static_cast<size_t>(size.width),
.height = static_cast<size_t>(size.height),
.width = static_cast<size_t>(scaledSize.width),
.height = static_cast<size_t>(scaledSize.height),
.pixel_ratio = pixelRatio,
};
FlutterEngineSendWindowMetricsEvent(_engine, &event);
Expand Down Expand Up @@ -237,7 +283,7 @@ - (bool)engineCallbackOnMakeResourceCurrent {
if (!_viewController.flutterView) {
return false;
}
[_viewController makeResourceContextCurrent];
[self.resourceContext makeCurrentContext];
return true;
}

Expand Down Expand Up @@ -269,6 +315,19 @@ - (void)engineCallbackOnPlatformMessage:(const FlutterPlatformMessage*)message {
}
}

/**
* Note: Called from dealloc. Should not use accessors or other methods.
*/
- (void)shutDownEngine {
if (_engine) {
FlutterEngineResult result = FlutterEngineShutdown(_engine);
if (result != kSuccess) {
NSLog(@"Failed to shut down Flutter engine: error %d", result);
}
}
_engine = nullptr;
}

#pragma mark - FlutterBinaryMessenger

- (void)sendOnChannel:(nonnull NSString*)channel message:(nullable NSData*)message {
Expand Down
20 changes: 15 additions & 5 deletions shell/platform/darwin/macos/framework/Source/FLEEngine_Internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,27 @@

#import "flutter/shell/platform/darwin/macos/framework/Headers/FLEEngine.h"

#import <Cocoa/Cocoa.h>

#import "flutter/shell/platform/embedder/embedder.h"

@interface FLEEngine ()

/**
* Informs the engine that the display region's size has changed.
*
* @param size The size of the display, in pixels.
* @param pixelRatio The number of pixels per screen coordinate.
* True if the engine is currently running.
*/
@property(nonatomic, readonly) BOOL running;

/**
* The resource context used by the engine for texture uploads. FlutterViews associated with this
* engine should be created to share with this context.
*/
@property(nonatomic, readonly, nullable) NSOpenGLContext* resourceContext;

/**
* Informs the engine that the associated view controller's view size has changed.
*/
- (void)updateWindowMetricsWithSize:(CGSize)size pixelRatio:(double)pixelRatio;
- (void)updateWindowMetrics;

/**
* Dispatches the given pointer event data to engine.
Expand Down
Loading