5#import "flutter/shell/platform/darwin/macos/framework/Headers/FlutterEngine.h"
6#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h"
12#include "flutter/common/constants.h"
13#include "flutter/shell/platform/common/app_lifecycle_state.h"
14#include "flutter/shell/platform/common/engine_switches.h"
15#include "flutter/shell/platform/embedder/embedder.h"
17#import "flutter/shell/platform/darwin/common/framework/Source/FlutterBinaryMessengerRelay.h"
18#import "flutter/shell/platform/darwin/macos/framework/Headers/FlutterAppDelegate.h"
19#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterAppDelegate_Internal.h"
20#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterCompositor.h"
21#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterDartProject_Internal.h"
22#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterDisplayLink.h"
23#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterMenuPlugin.h"
24#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterMouseCursorPlugin.h"
25#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterPlatformViewController.h"
26#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterRenderer.h"
27#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterTimeConverter.h"
28#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterVSyncWaiter.h"
29#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterViewController_Internal.h"
30#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterViewEngineProvider.h"
47 flutterLocale.
language_code = [[locale objectForKey:NSLocaleLanguageCode] UTF8String];
48 flutterLocale.
country_code = [[locale objectForKey:NSLocaleCountryCode] UTF8String];
49 flutterLocale.
script_code = [[locale objectForKey:NSLocaleScriptCode] UTF8String];
50 flutterLocale.
variant_code = [[locale objectForKey:NSLocaleVariantCode] UTF8String];
56 @"NSApplicationDidChangeAccessibilityEnhancedUserInterfaceNotification";
68- (instancetype)initWithConnection:(NSNumber*)connection
77- (instancetype)initWithConnection:(NSNumber*)connection
80 NSAssert(
self,
@"Super init cannot be nil");
109@property(nonatomic, readonly)
161- (void)postMainThreadTask:(
FlutterTask)task targetTimeInNanoseconds:(uint64_t)targetTime;
167- (void)loadAOTData:(NSString*)assetsDir;
196 _acceptingRequests = NO;
198 _terminator = terminator ? terminator : ^(
id sender) {
201 [[NSApplication sharedApplication] terminate:sender];
203 id<NSApplicationDelegate> appDelegate = [[NSApplication sharedApplication] delegate];
204 if ([appDelegate respondsToSelector:
@selector(setTerminationHandler:)]) {
213- (void)handleRequestAppExitMethodCall:(NSDictionary<NSString*,
id>*)arguments
215 NSString*
type = arguments[@"type"];
221 FlutterAppExitType exitType =
222 [type isEqualTo:@"cancelable"] ? kFlutterAppExitTypeCancelable : kFlutterAppExitTypeRequired;
224 [
self requestApplicationTermination:[NSApplication sharedApplication]
231- (void)requestApplicationTermination:(
id)sender
232 exitType:(FlutterAppExitType)type
234 _shouldTerminate = YES;
235 if (![
self acceptingRequests]) {
238 type = kFlutterAppExitTypeRequired;
241 case kFlutterAppExitTypeCancelable: {
245 [_engine sendOnChannel:kFlutterPlatformChannel
247 binaryReply:^(NSData* _Nullable reply) {
248 NSAssert(_terminator, @"terminator shouldn't be nil");
250 if ([decoded_reply isKindOfClass:[
FlutterError class]]) {
252 NSLog(@"Method call returned error[%@]: %@ %@", [error code], [error message],
257 if (![decoded_reply isKindOfClass:[NSDictionary class]]) {
258 NSLog(@"Call to System.requestAppExit returned an unexpected object: %@",
263 NSDictionary* replyArgs = (NSDictionary*)decoded_reply;
264 if ([replyArgs[@"response"] isEqual:@"exit"]) {
266 } else if ([replyArgs[@"response"] isEqual:@"cancel"]) {
267 _shouldTerminate = NO;
275 case kFlutterAppExitTypeRequired:
276 NSAssert(
_terminator,
@"terminator shouldn't be nil");
289 return [[NSPasteboard generalPasteboard] clearContents];
292- (NSString*)stringForType:(NSPasteboardType)dataType {
293 return [[NSPasteboard generalPasteboard] stringForType:dataType];
296- (
BOOL)setString:(nonnull NSString*)string forType:(nonnull NSPasteboardType)dataType {
297 return [[NSPasteboard generalPasteboard] setString:string forType:dataType];
308- (instancetype)initWithPlugin:(nonnull NSString*)pluginKey
322 NSString* _pluginKey;
328- (instancetype)initWithPlugin:(NSString*)pluginKey flutterEngine:(
FlutterEngine*)flutterEngine {
331 _pluginKey = [pluginKey copy];
333 _publishedValue = [NSNull null];
338#pragma mark - FlutterPluginRegistrar
349 return [
self viewForIdentifier:kFlutterImplicitViewId];
354 if (controller == nil) {
357 if (!controller.viewLoaded) {
363- (void)addMethodCallDelegate:(nonnull
id<FlutterPlugin>)delegate
366 [delegate handleMethodCall:call result:result];
371 id<NSApplicationDelegate> appDelegate = [[NSApplication sharedApplication] delegate];
373 id<FlutterAppLifecycleProvider> lifeCycleProvider =
374 static_cast<id<FlutterAppLifecycleProvider>
>(appDelegate);
375 [lifeCycleProvider addApplicationLifecycleDelegate:delegate];
376 [_flutterEngine.pluginAppDelegates addPointer:(__bridge void*)delegate];
381 withId:(nonnull NSString*)factoryId {
382 [[_flutterEngine platformViewController] registerViewFactory:factory withId:factoryId];
385- (void)publish:(NSObject*)value {
386 _publishedValue =
value;
389- (NSString*)lookupKeyForAsset:(NSString*)asset {
393- (NSString*)lookupKeyForAsset:(NSString*)asset fromPackage:(NSString*)package {
400#pragma mark - Static methods provided to engine configuration
478- (instancetype)initWithName:(NSString*)labelPrefix project:(
FlutterDartProject*)project {
479 return [
self initWithName:labelPrefix project:project allowHeadlessExecution:YES];
486 pthread_t thread = pthread_self();
489 if (!pthread_getschedparam(thread, &
policy, ¶m)) {
491 pthread_setschedparam(thread,
policy, ¶m);
493 pthread_set_qos_class_self_np(QOS_CLASS_USER_INTERACTIVE, 0);
497- (instancetype)initWithName:(NSString*)labelPrefix
499 allowHeadlessExecution:(
BOOL)allowHeadlessExecution {
501 NSAssert(
self,
@"Super init cannot be nil");
508 _pluginAppDelegates = [NSPointerArray weakObjectsPointerArray];
509 _pluginRegistrars = [[NSMutableDictionary alloc] init];
512 _semanticsEnabled = NO;
514 _isResponseValid = [[NSMutableArray alloc] initWithCapacity:1];
515 [_isResponseValid addObject:@YES];
523 NSNotificationCenter* notificationCenter = [NSNotificationCenter defaultCenter];
524 [notificationCenter addObserver:self
525 selector:@selector(sendUserLocales)
526 name:NSCurrentLocaleDidChangeNotification
531 [
self setUpPlatformViewChannel];
532 [
self setUpAccessibilityChannel];
533 [
self setUpNotificationCenterListeners];
534 id<NSApplicationDelegate> appDelegate = [[NSApplication sharedApplication] delegate];
538 id<FlutterAppLifecycleProvider> lifecycleProvider =
539 static_cast<id<FlutterAppLifecycleProvider>
>(appDelegate);
540 [lifecycleProvider addApplicationLifecycleDelegate:self];
542 _terminationHandler = nil;
551 id<NSApplicationDelegate> appDelegate = [[NSApplication sharedApplication] delegate];
553 id<FlutterAppLifecycleProvider> lifecycleProvider =
554 static_cast<id<FlutterAppLifecycleProvider>
>(appDelegate);
555 [lifecycleProvider removeApplicationLifecycleDelegate:self];
560 for (id<FlutterAppLifecycleDelegate> delegate in _pluginAppDelegates) {
562 [lifecycleProvider removeApplicationLifecycleDelegate:delegate];
568 for (NSString* pluginName in _pluginRegistrars) {
569 [_pluginRegistrars[pluginName] publish:[NSNull null]];
571 @
synchronized(_isResponseValid) {
572 [_isResponseValid removeAllObjects];
573 [_isResponseValid addObject:@NO];
575 [
self shutDownEngine];
577 _embedderAPI.CollectAOTData(
_aotData);
581- (
BOOL)runWithEntrypoint:(NSString*)entrypoint {
587 NSLog(
@"Attempted to run an engine with no view controller without headless mode enabled.");
591 [
self addInternalPlugins];
594 std::vector<const char*>
argv = {[
self.executableName UTF8String]};
595 std::vector<std::string> switches =
self.switches;
599 std::find(switches.begin(), switches.end(),
"--enable-impeller=true") != switches.end()) {
600 switches.push_back(
"--enable-impeller=true");
604 [](
const std::string& arg) ->
const char* { return arg.c_str(); });
606 std::vector<const char*> dartEntrypointArgs;
607 for (NSString* argument in [
_project dartEntrypointArguments]) {
608 dartEntrypointArgs.push_back([argument UTF8String]);
634 std::cout << tag <<
": ";
636 std::cout <<
message << std::endl;
639 static size_t sTaskRunnerIdentifiers = 0;
643 .runs_task_on_current_thread_callback = [](
void*
user_data) ->
bool {
644 return [[NSThread currentThread] isMainThread];
646 .post_task_callback = [](
FlutterTask task, uint64_t target_time_nanos,
649 targetTimeInNanoseconds:target_time_nanos];
651 .identifier = ++sTaskRunnerIdentifiers,
655 .platform_task_runner = &cocoa_task_runner_description,
656 .thread_priority_setter = SetThreadPriority};
659 [
self loadAOTData:_project.assetsPath];
664 flutterArguments.
compositor = [
self createFlutterCompositor];
680 NSLog(
@"Failed to initialize Flutter engine: error %d",
result);
686 NSLog(
@"Failed to run an initialized engine: error %d",
result);
690 [
self sendUserLocales];
693 NSEnumerator* viewControllerEnumerator = [_viewControllers objectEnumerator];
695 while ((nextViewController = [viewControllerEnumerator nextObject])) {
696 [
self updateWindowMetricsForViewController:nextViewController];
699 [
self updateDisplayConfig];
702 [
self sendInitialSettings];
706- (void)loadAOTData:(NSString*)assetsDir {
707 if (!_embedderAPI.RunsAOTCompiledDartCode()) {
711 BOOL isDirOut =
false;
712 NSFileManager* fileManager = [NSFileManager defaultManager];
716 NSString* elfPath = [NSString pathWithComponents:@[ assetsDir, @"app_elf_snapshot.so" ]];
718 if (![fileManager fileExistsAtPath:elfPath isDirectory:&isDirOut]) {
724 source.elf_path = [elfPath cStringUsingEncoding:NSUTF8StringEncoding];
728 NSLog(
@"Failed to load AOT data from: %@", elfPath);
734 NSAssert(controller != nil,
@"The controller must not be nil.");
735 NSAssert(controller.
engine == nil,
736 @"The FlutterViewController is unexpectedly attached to "
737 @"engine %@ before initialization.",
740 @"The requested view ID is occupied.");
741 [_viewControllers setObject:controller forKey:@(viewIdentifier)];
745 NSAssert(controller.
viewIdentifier == viewIdentifier,
@"Failed to assign view ID.");
749 NSAssert(controller.
attached,
@"The FlutterViewController should switch to the attached mode "
750 @"after it is added to a FlutterEngine.");
752 @"The FlutterViewController was added to %@, but its engine unexpectedly became %@.",
755 if (controller.viewLoaded) {
756 [
self viewControllerViewDidLoad:controller];
765 block:^(CFTimeInterval timestamp, CFTimeInterval targetTimestamp,
768 uint64_t targetTimeNanos =
770 FlutterEngine* engine = weakSelf;
776 [engine->_threadSynchronizer performOnPlatformThread:^{
777 engine->_embedderAPI.OnVsync(_engine, baton, timeNanos, targetTimeNanos);
783 [_vsyncWaiters setObject:waiter forKey:@(viewController.viewIdentifier)];
791 if (controller != nil) {
794 @"The FlutterViewController unexpectedly stays attached after being removed. "
795 @"In unit tests, this is likely because either the FlutterViewController or "
796 @"the FlutterEngine is mocked. Please subclass these classes instead.");
798 [_viewControllers removeObjectForKey:@(viewIdentifier)];
800 [_vsyncWaiters removeObjectForKey:@(viewIdentifier)];
804- (void)shutDownIfNeeded {
806 [
self shutDownEngine];
812 NSAssert(controller == nil || controller.
viewIdentifier == viewIdentifier,
813 @"The stored controller has unexpected view ID.");
819 [_viewControllers objectForKey:@(kFlutterImplicitViewId)];
820 if (currentController == controller) {
824 if (currentController == nil && controller != nil) {
826 NSAssert(controller.
engine == nil,
827 @"Failed to set view controller to the engine: "
828 @"The given FlutterViewController is already attached to an engine %@. "
829 @"If you wanted to create an FlutterViewController and set it to an existing engine, "
830 @"you should use FlutterViewController#init(engine:, nibName, bundle:) instead.",
832 [
self registerViewController:controller forIdentifier:kFlutterImplicitViewId];
833 }
else if (currentController != nil && controller == nil) {
835 @"The default controller has an unexpected ID %llu", currentController.
viewIdentifier);
837 [
self deregisterViewControllerForIdentifier:kFlutterImplicitViewId];
838 [
self shutDownIfNeeded];
842 @"Failed to set view controller to the engine: "
843 @"The engine already has an implicit view controller %@. "
844 @"If you wanted to make the implicit view render in a different window, "
845 @"you should attach the current view controller to the window instead.",
851 return [
self viewControllerForIdentifier:kFlutterImplicitViewId];
868 config, backing_store_out);
877 ->Present(
info->view_id,
info->layers,
info->layers_count);
889#pragma mark - Framework-internal methods
894 NSAssert(
self.viewController == nil,
895 @"The engine already has a view controller for the implicit view.");
896 self.viewController = controller;
900 [
self deregisterViewControllerForIdentifier:viewController.viewIdentifier];
901 [
self shutDownIfNeeded];
908- (void)updateDisplayConfig:(NSNotification*)notification {
909 [
self updateDisplayConfig];
912- (NSArray<NSScreen*>*)screens {
913 return [NSScreen screens];
916- (void)updateDisplayConfig {
921 std::vector<FlutterEngineDisplay> displays;
922 for (NSScreen* screen : [
self screens]) {
923 CGDirectDisplayID displayID =
924 static_cast<CGDirectDisplayID
>([screen.deviceDescription[@"NSScreenNumber"] integerValue]);
926 double devicePixelRatio = screen.backingScaleFactor;
931 display.
width =
static_cast<size_t>(screen.frame.size.width) * devicePixelRatio;
932 display.
height =
static_cast<size_t>(screen.frame.size.height) * devicePixelRatio;
935 CVDisplayLinkRef displayLinkRef = nil;
936 CVReturn
error = CVDisplayLinkCreateWithCGDisplay(displayID, &displayLinkRef);
939 CVTime nominal = CVDisplayLinkGetNominalOutputVideoRefreshPeriod(displayLinkRef);
940 if (!(nominal.flags & kCVTimeIsIndefinite)) {
941 double refreshRate =
static_cast<double>(nominal.timeScale) / nominal.timeValue;
944 CVDisplayLinkRelease(displayLinkRef);
949 displays.push_back(display);
952 displays.data(), displays.size());
955- (void)onSettingsChanged:(NSNotification*)notification {
957 NSString* brightness =
958 [[NSUserDefaults standardUserDefaults] stringForKey:@"AppleInterfaceStyle"];
959 [_settingsChannel sendMessage:@{
960 @"platformBrightness" : [brightness isEqualToString:@"Dark"] ? @"dark" : @"light",
962 @"textScaleFactor" : @1.0,
963 @"alwaysUse24HourFormat" : @false
967- (void)sendInitialSettings {
969 [[NSDistributedNotificationCenter defaultCenter]
971 selector:@selector(onSettingsChanged:)
972 name:@"AppleInterfaceThemeChangedNotification"
974 [
self onSettingsChanged:nil];
981- (nonnull NSString*)executableName {
982 return [[[NSProcessInfo processInfo] arguments] firstObject] ?:
@"Flutter";
990 @"The provided view controller is not attached to this engine.");
992 CGRect scaledBounds = [view convertRectToBacking:view.bounds];
993 CGSize scaledSize = scaledBounds.size;
994 double pixelRatio = view.bounds.size.width == 0 ? 1 : scaledSize.width / view.bounds.size.width;
995 auto displayId = [view.window.screen.deviceDescription[@"NSScreenNumber"] integerValue];
998 .
width =
static_cast<size_t>(scaledSize.width),
999 .height =
static_cast<size_t>(scaledSize.height),
1000 .pixel_ratio = pixelRatio,
1001 .
left =
static_cast<size_t>(scaledBounds.origin.x),
1002 .top =
static_cast<size_t>(scaledBounds.origin.y),
1003 .display_id =
static_cast<uint64_t
>(displayId),
1006 _embedderAPI.SendWindowMetricsEvent(
_engine, &windowMetricsEvent);
1016 userData:(
void*)userData {
1020- (void)setSemanticsEnabled:(
BOOL)enabled {
1021 if (_semanticsEnabled == enabled) {
1024 _semanticsEnabled = enabled;
1027 NSEnumerator* viewControllerEnumerator = [_viewControllers objectEnumerator];
1029 while ((nextViewController = [viewControllerEnumerator nextObject])) {
1033 _embedderAPI.UpdateSemanticsEnabled(
_engine, _semanticsEnabled);
1037 toTarget:(uint16_t)target
1038 withData:(
fml::MallocMapping)data {
1046#pragma mark - Private methods
1048- (void)sendUserLocales {
1049 if (!
self.running) {
1054 NSMutableArray<NSLocale*>* locales = [NSMutableArray array];
1055 std::vector<FlutterLocale> flutterLocales;
1056 flutterLocales.reserve(locales.count);
1057 for (NSString* localeID in [NSLocale preferredLanguages]) {
1058 NSLocale* locale = [[NSLocale alloc] initWithLocaleIdentifier:localeID];
1059 [locales addObject:locale];
1063 std::vector<const FlutterLocale*> flutterLocaleList;
1064 flutterLocaleList.reserve(flutterLocales.size());
1066 std::back_inserter(flutterLocaleList),
1067 [](
const auto& arg) ->
const auto* { return &arg; });
1068 _embedderAPI.UpdateLocales(
_engine, flutterLocaleList.data(), flutterLocaleList.size());
1072 NSData* messageData = nil;
1073 if (
message->message_size > 0) {
1074 messageData = [NSData dataWithBytesNoCopy:(void*)message->message
1075 length:message->message_size
1078 NSString* channel = @(
message->channel);
1081 NSMutableArray* isResponseValid =
self.isResponseValid;
1083 _embedderAPI.SendPlatformMessageResponse;
1085 @
synchronized(isResponseValid) {
1086 if (![isResponseValid[0] boolValue]) {
1090 if (responseHandle) {
1091 sendPlatformMessageResponse(weakSelf->_engine, responseHandle,
1092 static_cast<const uint8_t*
>(response.bytes), response.length);
1093 responseHandle = NULL;
1095 NSLog(
@"Error: Message responses can be sent only once. Ignoring duplicate response "
1104 handlerInfo.
handler(messageData, binaryResponseHandler);
1106 binaryResponseHandler(nil);
1110- (void)engineCallbackOnPreEngineRestart {
1111 NSEnumerator* viewControllerEnumerator = [_viewControllers objectEnumerator];
1113 while ((nextViewController = [viewControllerEnumerator nextObject])) {
1118- (void)onVSync:(uintptr_t)baton {
1130- (void)shutDownEngine {
1135 [_threadSynchronizer shutdown];
1140 NSLog(
@"Could not de-initialize the Flutter engine: error %d",
result);
1144 CFRelease((CFTypeRef)
self);
1148 NSLog(
@"Failed to shut down Flutter engine: error %d",
result);
1153- (void)setUpPlatformViewChannel {
1160 [_platformViewsChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
1161 [[weakSelf platformViewController] handleMethodCall:call result:result];
1165- (void)setUpAccessibilityChannel {
1171 [_accessibilityChannel setMessageHandler:^(id message, FlutterReply reply) {
1172 [weakSelf handleAccessibilityEvent:message];
1175- (void)setUpNotificationCenterListeners {
1176 NSNotificationCenter*
center = [NSNotificationCenter defaultCenter];
1178 [center addObserver:self
1179 selector:@selector(onAccessibilityStatusChanged:)
1180 name:kEnhancedUserInterfaceNotification
1182 [center addObserver:self
1183 selector:@selector(applicationWillTerminate:)
1184 name:NSApplicationWillTerminateNotification
1186 [center addObserver:self
1187 selector:@selector(windowDidChangeScreen:)
1188 name:NSWindowDidChangeScreenNotification
1190 [center addObserver:self
1191 selector:@selector(updateDisplayConfig:)
1192 name:NSApplicationDidChangeScreenParametersNotification
1196- (void)addInternalPlugins {
1209 [_platformChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
1210 [weakSelf handleMethodCall:call result:result];
1214- (void)didUpdateMouseCursor:(NSCursor*)cursor {
1218 [_lastViewWithPointerEvent didUpdateMouseCursor:cursor];
1221- (void)applicationWillTerminate:(NSNotification*)notification {
1222 [
self shutDownEngine];
1225- (void)windowDidChangeScreen:(NSNotification*)notification {
1228 NSEnumerator* viewControllerEnumerator = [_viewControllers objectEnumerator];
1230 while ((nextViewController = [viewControllerEnumerator nextObject])) {
1231 [
self updateWindowMetricsForViewController:nextViewController];
1235- (void)onAccessibilityStatusChanged:(NSNotification*)notification {
1236 BOOL enabled = [notification.userInfo[kEnhancedUserInterfaceKey] boolValue];
1237 NSEnumerator* viewControllerEnumerator = [_viewControllers objectEnumerator];
1239 while ((nextViewController = [viewControllerEnumerator nextObject])) {
1243 self.semanticsEnabled = enabled;
1245- (void)handleAccessibilityEvent:(NSDictionary<NSString*,
id>*)annotatedEvent {
1246 NSString*
type = annotatedEvent[@"type"];
1247 if ([
type isEqualToString:
@"announce"]) {
1248 NSString*
message = annotatedEvent[@"data"][@"message"];
1249 NSNumber* assertiveness = annotatedEvent[@"data"][@"assertiveness"];
1254 NSAccessibilityPriorityLevel priority = [assertiveness isEqualToNumber:@1]
1255 ? NSAccessibilityPriorityHigh
1256 : NSAccessibilityPriorityMedium;
1258 [
self announceAccessibilityMessage:message withPriority:priority];
1262- (void)announceAccessibilityMessage:(NSString*)message
1263 withPriority:(NSAccessibilityPriorityLevel)priority {
1264 NSAccessibilityPostNotificationWithUserInfo(
1266 NSAccessibilityAnnouncementRequestedNotification,
1267 @{NSAccessibilityAnnouncementKey :
message, NSAccessibilityPriorityKey : @(priority)});
1270 if ([
call.method isEqualToString:
@"SystemNavigator.pop"]) {
1271 [[NSApplication sharedApplication] terminate:self];
1273 }
else if ([
call.method isEqualToString:
@"SystemSound.play"]) {
1274 [
self playSystemSound:call.arguments];
1276 }
else if ([
call.method isEqualToString:
@"Clipboard.getData"]) {
1278 }
else if ([
call.method isEqualToString:
@"Clipboard.setData"]) {
1279 [
self setClipboardData:call.arguments];
1281 }
else if ([
call.method isEqualToString:
@"Clipboard.hasStrings"]) {
1282 result(@{
@"value" : @([
self clipboardHasStrings])});
1283 }
else if ([
call.method isEqualToString:
@"System.exitApplication"]) {
1284 if ([
self terminationHandler] == nil) {
1289 [NSApp terminate:self];
1292 [[
self terminationHandler] handleRequestAppExitMethodCall:call.arguments result:result];
1294 }
else if ([
call.method isEqualToString:
@"System.initializationComplete"]) {
1295 if ([
self terminationHandler] != nil) {
1296 [
self terminationHandler].acceptingRequests = YES;
1304- (void)playSystemSound:(NSString*)soundType {
1305 if ([soundType isEqualToString:
@"SystemSoundType.alert"]) {
1310- (NSDictionary*)getClipboardData:(NSString*)format {
1312 NSString* stringInPasteboard = [
self.pasteboard stringForType:NSPasteboardTypeString];
1313 return stringInPasteboard == nil ? nil : @{
@"text" : stringInPasteboard};
1318- (void)setClipboardData:(NSDictionary*)data {
1320 [
self.pasteboard clearContents];
1321 if (
text && ![
text isEqual:[NSNull null]]) {
1322 [
self.pasteboard setString:text forType:NSPasteboardTypeString];
1326- (
BOOL)clipboardHasStrings {
1327 return [
self.pasteboard stringForType:NSPasteboardTypeString].length > 0;
1330- (
std::vector<std::string>)switches {
1338#pragma mark - FlutterAppLifecycleDelegate
1341 NSString* nextState =
1342 [[NSString alloc] initWithCString:flutter::AppLifecycleStateToString(state)];
1343 [
self sendOnChannel:kFlutterLifecycleChannel
1344 message:[nextState dataUsingEncoding:NSUTF8StringEncoding]];
1351- (void)handleWillBecomeActive:(NSNotification*)notification {
1354 [
self setApplicationState:flutter::AppLifecycleState::kHidden];
1356 [
self setApplicationState:flutter::AppLifecycleState::kResumed];
1364- (void)handleWillResignActive:(NSNotification*)notification {
1367 [
self setApplicationState:flutter::AppLifecycleState::kHidden];
1369 [
self setApplicationState:flutter::AppLifecycleState::kInactive];
1377- (void)handleDidChangeOcclusionState:(NSNotification*)notification {
1378 NSApplicationOcclusionState occlusionState = [[NSApplication sharedApplication] occlusionState];
1379 if (occlusionState & NSApplicationOcclusionStateVisible) {
1382 [
self setApplicationState:flutter::AppLifecycleState::kResumed];
1384 [
self setApplicationState:flutter::AppLifecycleState::kInactive];
1388 [
self setApplicationState:flutter::AppLifecycleState::kHidden];
1392#pragma mark - FlutterBinaryMessenger
1394- (void)sendOnChannel:(nonnull NSString*)channel message:(nullable NSData*)message {
1395 [
self sendOnChannel:channel message:message binaryReply:nil];
1398- (void)sendOnChannel:(NSString*)channel
1399 message:(NSData* _Nullable)message
1406 auto captures = std::make_unique<Captures>();
1408 auto message_reply = [](
const uint8_t*
data,
size_t data_size,
void*
user_data) {
1409 auto captures =
reinterpret_cast<Captures*
>(
user_data);
1410 NSData* reply_data = nil;
1411 if (
data !=
nullptr && data_size > 0) {
1412 reply_data = [NSData dataWithBytes:static_cast<const void*>(data) length:data_size];
1414 captures->reply(reply_data);
1419 _engine, message_reply, captures.get(), &response_handle);
1421 NSLog(
@"Failed to create a FlutterPlatformMessageResponseHandle (%d)", create_result);
1429 .channel = [channel UTF8String],
1431 .message_size =
message.length,
1432 .response_handle = response_handle,
1437 NSLog(
@"Failed to send message to Flutter engine on channel '%@' (%d).", channel,
1441 if (response_handle !=
nullptr) {
1443 _embedderAPI.PlatformMessageReleaseResponseHandle(
_engine, response_handle);
1445 NSLog(
@"Failed to release the response handle (%d).", release_result);
1451 binaryMessageHandler:
1456 handler:[handler copy]];
1463 NSString* foundChannel = nil;
1466 if ([handlerInfo.
connection isEqual:@(connection)]) {
1472 [_messengerHandlers removeObjectForKey:foundChannel];
1476#pragma mark - FlutterPluginRegistry
1479 id<FlutterPluginRegistrar> registrar =
self.pluginRegistrars[pluginName];
1483 self.pluginRegistrars[pluginName] = registrarImpl;
1484 registrar = registrarImpl;
1489- (nullable NSObject*)valuePublishedByPlugin:(NSString*)pluginName {
1490 return self.pluginRegistrars[pluginName].publishedValue;
1493#pragma mark - FlutterTextureRegistrar
1496 return [_renderer registerTexture:texture];
1499- (
BOOL)registerTextureWithID:(int64_t)textureId {
1500 return _embedderAPI.RegisterExternalTexture(
_engine, textureId) ==
kSuccess;
1503- (void)textureFrameAvailable:(int64_t)textureID {
1504 [_renderer textureFrameAvailable:textureID];
1507- (
BOOL)markTextureFrameAvailable:(int64_t)textureID {
1508 return _embedderAPI.MarkExternalTextureFrameAvailable(
_engine, textureID) ==
kSuccess;
1511- (void)unregisterTexture:(int64_t)textureID {
1512 [_renderer unregisterTexture:textureID];
1515- (
BOOL)unregisterTextureWithID:(int64_t)textureID {
1516 return _embedderAPI.UnregisterExternalTexture(
_engine, textureID) ==
kSuccess;
1519#pragma mark - Task runner integration
1525 NSLog(
@"Could not post a task to the Flutter engine.");
1530- (void)postMainThreadTask:(
FlutterTask)task targetTimeInNanoseconds:(uint64_t)targetTime {
1533 [weakSelf runTaskOnEmbedder:task];
1536 const auto engine_time = _embedderAPI.GetCurrentTime();
1537 if (targetTime <= engine_time) {
1538 dispatch_async(dispatch_get_main_queue(), worker);
1541 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, targetTime - engine_time),
1542 dispatch_get_main_queue(), worker);
1547- (
flutter::FlutterCompositor*)macOSCompositor {
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
NS_ASSUME_NONNULL_BEGIN typedef void(^ FlutterBinaryReply)(NSData *_Nullable reply)
void(^ FlutterBinaryMessageHandler)(NSData *_Nullable message, FlutterBinaryReply reply)
int64_t FlutterBinaryMessengerConnection
void(^ FlutterResult)(id _Nullable result)
FLUTTER_DARWIN_EXPORT NSObject const * FlutterMethodNotImplemented
FlutterBinaryMessengerConnection _connection
static void round(SkPoint *p)
static bool left(const SkPoint &p0, const SkPoint &p1)
static SkScalar center(float pos0, float pos1)
int find(T *array, int N, T item)
NSInteger clearContents()
FlutterEngineResult FlutterEngineGetProcAddresses(FlutterEngineProcTable *table)
Gets the table of engine function pointers.
static constexpr FlutterViewId kFlutterImplicitViewId
@ kFlutterEngineAOTDataSourceTypeElfPath
void(* FlutterPlatformMessageCallback)(const FlutterPlatformMessage *, void *)
struct _FlutterEngine * FLUTTER_API_SYMBOL(FlutterEngine)
@ kFlutterEngineDisplaysUpdateTypeStartup
FlutterThreadPriority
Valid values for priority of Thread.
@ kDisplay
Suitable for threads which generate data for the display.
@ kRaster
Suitable for thread which raster data.
void(* FlutterKeyEventCallback)(bool, void *)
FlutterEngineResult(* FlutterEngineSendPlatformMessageResponseFnPtr)(FLUTTER_API_SYMBOL(FlutterEngine) engine, const FlutterPlatformMessageResponseHandle *handle, const uint8_t *data, size_t data_length)
#define FLUTTER_ENGINE_VERSION
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
const uint8_t uint32_t uint32_t GError ** error
uint32_t uint32_t * format
HWND(* FlutterPlatformViewFactory)(const FlutterPlatformViewCreationParameters *)
#define FML_DCHECK(condition)
FlutterEngineTerminationHandler * terminationHandler
instancetype messageChannelWithName:binaryMessenger:codec:(NSString *name,[binaryMessenger] NSObject< FlutterBinaryMessenger > *messenger,[codec] NSObject< FlutterMessageCodec > *codec)
void(* rootIsolateCreateCallback)(void *_Nullable)
NSString * lookupKeyForAsset:fromPackage:(NSString *asset,[fromPackage] NSString *package)
NSString * lookupKeyForAsset:(NSString *asset)
instancetype displayLinkWithView:(NSView *view)
FlutterBinaryMessageHandler handler
NSObject * publishedValue
FlutterViewController * viewControllerForIdentifier:(FlutterViewIdentifier viewIdentifier)
NSMutableDictionary< NSString *, FlutterEngineRegistrar * > * pluginRegistrars
NSObject< FlutterBinaryMessenger > * binaryMessenger
void engineCallbackOnPlatformMessage:(const FlutterPlatformMessage *message)
NSPointerArray * pluginAppDelegates
NSMutableArray< NSNumber * > * isResponseValid
void setUpPlatformViewChannel()
FlutterRenderer * renderer
void setUpAccessibilityChannel()
void engineCallbackOnPreEngineRestart()
void onVSync:(uintptr_t baton)
instancetype sharedInstance()
NSData * encodeMethodCall:(FlutterMethodCall *call)
id decodeEnvelope:(NSData *envelope)
instancetype sharedInstance()
instancetype methodCallWithMethodName:arguments:(NSString *method,[arguments] id _Nullable arguments)
void setMethodCallHandler:(FlutterMethodCallHandler _Nullable handler)
instancetype methodChannelWithName:binaryMessenger:codec:(NSString *name,[binaryMessenger] NSObject< FlutterBinaryMessenger > *messenger,[codec] NSObject< FlutterMethodCodec > *codec)
void registerWithRegistrar:delegate:(nonnull id< FlutterPluginRegistrar > registrar,[delegate] nullable id< FlutterMouseCursorPluginDelegate > delegate)
instancetype sharedInstance()
instancetype sharedInstance()
Converts between the time representation used by Flutter Engine and CAMediaTime.
uint64_t CAMediaTimeToEngineTime:(CFTimeInterval time)
void waitForVSync:(uintptr_t baton)
void onPreEngineRestart()
void updateSemantics:(const FlutterSemanticsUpdate2 *update)
void notifySemanticsEnabledChanged()
void onAccessibilityStatusChanged:(NSNotification *notification)
FlutterView * flutterView
FlutterViewIdentifier viewIdentifier
void setUpWithEngine:viewIdentifier:threadSynchronizer:(FlutterEngine *engine, [viewIdentifier] FlutterViewIdentifier viewIdentifier, [threadSynchronizer] FlutterThreadSynchronizer *threadSynchronizer)
fml::scoped_nsobject< FlutterMethodChannel > _platformViewsChannel
BOOL _allowHeadlessExecution
fml::scoped_nsobject< FlutterBasicMessageChannel > _settingsChannel
fml::scoped_nsobject< FlutterMethodChannel > _platformChannel
FlutterBinaryMessengerRelay * _binaryMessenger
FlutterViewController * viewController
fml::scoped_nsobject< FlutterEngine > _engine
_FlutterEngineAOTData * _aotData
std::unique_ptr< flutter::FlutterCompositor > _macOSCompositor
static const int kMainThreadPriority
static void OnPlatformMessage(const FlutterPlatformMessage *message, void *user_data)
FlutterPlatformViewController * _platformViewController
FlutterBasicMessageChannel * _accessibilityChannel
static FlutterLocale FlutterLocaleFromNSLocale(NSLocale *locale)
NSMutableDictionary< NSString *, FlutterEngineHandlerInfo * > * _messengerHandlers
FlutterBinaryMessengerConnection _currentMessengerConnection
FlutterThreadSynchronizer * _threadSynchronizer
NSString *const kFlutterLifecycleChannel
static NSString *const kEnhancedUserInterfaceNotification
The private notification for voice over.
NSMapTable< NSNumber *, FlutterVSyncWaiter * > * _vsyncWaiters
NSString *const kFlutterPlatformChannel
FlutterDartProject * _project
NSMapTable * _viewControllers
FlutterCompositor _compositor
__weak FlutterView * _lastViewWithPointerEvent
FlutterTerminationCallback _terminator
constexpr char kTextPlainFormat[]
Clipboard plain text format.
__weak FlutterEngine * _flutterEngine
static NSString *const kEnhancedUserInterfaceKey
NSString *const kFlutterSettingsChannel
NS_ASSUME_NONNULL_BEGIN typedef void(^ FlutterTerminationCallback)(id _Nullable sender)
constexpr int64_t kFlutterImplicitViewId
std::vector< std::string > GetSwitchesFromEnvironment()
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network policy
static SkColor4f transform(SkColor4f c, SkColorSpace *src, SkColorSpace *dst)
FlutterBackingStoreCreateCallback create_backing_store_callback
bool avoid_backing_store_cache
Avoid caching backing stores provided by this compositor.
size_t struct_size
This size of this struct. Must be sizeof(FlutterCompositor).
FlutterPresentViewCallback present_view_callback
FlutterBackingStoreCollectCallback collect_backing_store_callback
size_t struct_size
The size of this struct. Must be sizeof(FlutterCustomTaskRunners).
size_t height
The height of the display, in physical pixels.
double device_pixel_ratio
size_t struct_size
This size of this struct. Must be sizeof(FlutterDisplay).
size_t width
The width of the display, in physical pixels.
FlutterEngineDisplayId display_id
Function-pointer-based versions of the APIs above.
const char * language_code
size_t struct_size
This size of this struct. Must be sizeof(FlutterLocale).
const char * country_code
const char * variant_code
FlutterPlatformMessageCallback platform_message_callback
FlutterLogMessageCallback log_message_callback
VsyncCallback vsync_callback
OnPreEngineRestartCallback on_pre_engine_restart_callback
FlutterEngineAOTData aot_data
const char *const * dart_entrypoint_argv
size_t struct_size
The size of this struct. Must be sizeof(FlutterProjectArgs).
FlutterUpdateSemanticsCallback2 update_semantics_callback2
const char *const * command_line_argv
const char * icu_data_path
bool shutdown_dart_vm_when_done
const char * custom_dart_entrypoint
const FlutterCustomTaskRunners * custom_task_runners
int command_line_argc
The command line argument count used to initialize the project.
VoidCallback root_isolate_create_callback
const FlutterCompositor * compositor
A batch of updates to semantics nodes and custom actions.
size_t struct_size
The size of this struct. Must be sizeof(FlutterTaskRunnerDescription).
size_t struct_size
The size of this struct. Must be sizeof(FlutterWindowMetricsEvent).
std::shared_ptr< const fml::Mapping > data