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");
92@interface FlutterEngine () <FlutterBinaryMessenger, FlutterMouseCursorPluginDelegate>
99@property(nonatomic, strong) NSMutableArray<NSNumber*>* isResponseValid;
104@property(nonatomic, strong) NSPointerArray* pluginAppDelegates;
109@property(nonatomic, readonly)
110 NSMutableDictionary<NSString*, FlutterEngineRegistrar*>* pluginRegistrars;
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
340- (
id<FlutterBinaryMessenger>)messenger {
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];
370- (void)addApplicationDelegate:(NSObject<FlutterAppLifecycleDelegate>*)delegate {
371 id<NSApplicationDelegate> appDelegate = [[NSApplication sharedApplication] delegate];
372 if ([appDelegate conformsToProtocol:@protocol(FlutterAppLifecycleProvider)]) {
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
477- (instancetype)initWithName:(NSString*)labelPrefix project:(
FlutterDartProject*)project {
478 return [
self initWithName:labelPrefix project:project allowHeadlessExecution:YES];
485 pthread_t thread = pthread_self();
488 if (!pthread_getschedparam(thread, &policy, ¶m)) {
490 pthread_setschedparam(thread, policy, ¶m);
492 pthread_set_qos_class_self_np(QOS_CLASS_USER_INTERACTIVE, 0);
496- (instancetype)initWithName:(NSString*)labelPrefix
498 allowHeadlessExecution:(
BOOL)allowHeadlessExecution {
500 NSAssert(
self,
@"Super init cannot be nil");
507 _pluginAppDelegates = [NSPointerArray weakObjectsPointerArray];
508 _pluginRegistrars = [[NSMutableDictionary alloc] init];
511 _semanticsEnabled = NO;
513 _isResponseValid = [[NSMutableArray alloc] initWithCapacity:1];
514 [_isResponseValid addObject:@YES];
522 NSNotificationCenter* notificationCenter = [NSNotificationCenter defaultCenter];
523 [notificationCenter addObserver:self
524 selector:@selector(sendUserLocales)
525 name:NSCurrentLocaleDidChangeNotification
530 [
self setUpPlatformViewChannel];
531 [
self setUpAccessibilityChannel];
532 [
self setUpNotificationCenterListeners];
533 id<NSApplicationDelegate> appDelegate = [[NSApplication sharedApplication] delegate];
534 if ([appDelegate conformsToProtocol:@protocol(FlutterAppLifecycleProvider)]) {
537 id<FlutterAppLifecycleProvider> lifecycleProvider =
538 static_cast<id<FlutterAppLifecycleProvider>
>(appDelegate);
539 [lifecycleProvider addApplicationLifecycleDelegate:self];
541 _terminationHandler = nil;
550 id<NSApplicationDelegate> appDelegate = [[NSApplication sharedApplication] delegate];
551 if ([appDelegate conformsToProtocol:@protocol(FlutterAppLifecycleProvider)]) {
552 id<FlutterAppLifecycleProvider> lifecycleProvider =
553 static_cast<id<FlutterAppLifecycleProvider>
>(appDelegate);
554 [lifecycleProvider removeApplicationLifecycleDelegate:self];
559 for (id<FlutterAppLifecycleDelegate> delegate in _pluginAppDelegates) {
561 [lifecycleProvider removeApplicationLifecycleDelegate:delegate];
567 for (NSString* pluginName in _pluginRegistrars) {
568 [_pluginRegistrars[pluginName] publish:[NSNull null]];
570 @
synchronized(_isResponseValid) {
571 [_isResponseValid removeAllObjects];
572 [_isResponseValid addObject:@NO];
574 [
self shutDownEngine];
576 _embedderAPI.CollectAOTData(
_aotData);
580- (
BOOL)runWithEntrypoint:(NSString*)entrypoint {
586 NSLog(
@"Attempted to run an engine with no view controller without headless mode enabled.");
590 [
self addInternalPlugins];
593 std::vector<const char*>
argv = {[
self.executableName UTF8String]};
594 std::vector<std::string> switches =
self.switches;
598 std::find(switches.begin(), switches.end(),
"--enable-impeller=true") != switches.end()) {
599 switches.push_back(
"--enable-impeller=true");
602 std::transform(switches.begin(), switches.end(), std::back_inserter(argv),
603 [](
const std::string& arg) ->
const char* { return arg.c_str(); });
605 std::vector<const char*> dartEntrypointArgs;
606 for (NSString* argument in [
_project dartEntrypointArguments]) {
607 dartEntrypointArgs.push_back([argument UTF8String]);
633 std::cout << tag <<
": ";
635 std::cout <<
message << std::endl;
638 static size_t sTaskRunnerIdentifiers = 0;
642 .runs_task_on_current_thread_callback = [](
void*
user_data) ->
bool {
643 return [[NSThread currentThread] isMainThread];
645 .post_task_callback = [](
FlutterTask task, uint64_t target_time_nanos,
648 targetTimeInNanoseconds:target_time_nanos];
650 .identifier = ++sTaskRunnerIdentifiers,
654 .platform_task_runner = &cocoa_task_runner_description,
655 .thread_priority_setter = SetThreadPriority};
658 [
self loadAOTData:_project.assetsPath];
663 flutterArguments.
compositor = [
self createFlutterCompositor];
679 NSLog(
@"Failed to initialize Flutter engine: error %d",
result);
685 NSLog(
@"Failed to run an initialized engine: error %d",
result);
689 [
self sendUserLocales];
692 NSEnumerator* viewControllerEnumerator = [_viewControllers objectEnumerator];
694 while ((nextViewController = [viewControllerEnumerator nextObject])) {
695 [
self updateWindowMetricsForViewController:nextViewController];
698 [
self updateDisplayConfig];
701 [
self sendInitialSettings];
705- (void)loadAOTData:(NSString*)assetsDir {
706 if (!_embedderAPI.RunsAOTCompiledDartCode()) {
710 BOOL isDirOut =
false;
711 NSFileManager* fileManager = [NSFileManager defaultManager];
715 NSString* elfPath = [NSString pathWithComponents:@[ assetsDir, @"app_elf_snapshot.so" ]];
717 if (![fileManager fileExistsAtPath:elfPath isDirectory:&isDirOut]) {
723 source.elf_path = [elfPath cStringUsingEncoding:NSUTF8StringEncoding];
727 NSLog(
@"Failed to load AOT data from: %@", elfPath);
733 NSAssert(controller != nil,
@"The controller must not be nil.");
734 NSAssert(controller.
engine == nil,
735 @"The FlutterViewController is unexpectedly attached to "
736 @"engine %@ before initialization.",
739 @"The requested view ID is occupied.");
740 [_viewControllers setObject:controller forKey:@(viewIdentifier)];
744 NSAssert(controller.
viewIdentifier == viewIdentifier,
@"Failed to assign view ID.");
748 NSAssert(controller.
attached,
@"The FlutterViewController should switch to the attached mode "
749 @"after it is added to a FlutterEngine.");
751 @"The FlutterViewController was added to %@, but its engine unexpectedly became %@.",
754 if (controller.viewLoaded) {
755 [
self viewControllerViewDidLoad:controller];
764 block:^(CFTimeInterval timestamp, CFTimeInterval targetTimestamp,
767 uint64_t targetTimeNanos =
769 FlutterEngine* engine = weakSelf;
775 [engine->_threadSynchronizer performOnPlatformThread:^{
776 engine->_embedderAPI.OnVsync(_engine, baton, timeNanos, targetTimeNanos);
782 [_vsyncWaiters setObject:waiter forKey:@(viewController.viewIdentifier)];
790 if (controller != nil) {
793 @"The FlutterViewController unexpectedly stays attached after being removed. "
794 @"In unit tests, this is likely because either the FlutterViewController or "
795 @"the FlutterEngine is mocked. Please subclass these classes instead.");
797 [_viewControllers removeObjectForKey:@(viewIdentifier)];
799 [_vsyncWaiters removeObjectForKey:@(viewIdentifier)];
803- (void)shutDownIfNeeded {
805 [
self shutDownEngine];
811 NSAssert(controller == nil || controller.
viewIdentifier == viewIdentifier,
812 @"The stored controller has unexpected view ID.");
818 [_viewControllers objectForKey:@(kFlutterImplicitViewId)];
819 if (currentController == controller) {
823 if (currentController == nil && controller != nil) {
825 NSAssert(controller.
engine == nil,
826 @"Failed to set view controller to the engine: "
827 @"The given FlutterViewController is already attached to an engine %@. "
828 @"If you wanted to create an FlutterViewController and set it to an existing engine, "
829 @"you should use FlutterViewController#init(engine:, nibName, bundle:) instead.",
831 [
self registerViewController:controller forIdentifier:kFlutterImplicitViewId];
832 }
else if (currentController != nil && controller == nil) {
833 NSAssert(currentController.
viewIdentifier == kFlutterImplicitViewId,
834 @"The default controller has an unexpected ID %llu", currentController.
viewIdentifier);
836 [
self deregisterViewControllerForIdentifier:kFlutterImplicitViewId];
837 [
self shutDownIfNeeded];
841 @"Failed to set view controller to the engine: "
842 @"The engine already has an implicit view controller %@. "
843 @"If you wanted to make the implicit view render in a different window, "
844 @"you should attach the current view controller to the window instead.",
850 return [
self viewControllerForIdentifier:kFlutterImplicitViewId];
867 config, backing_store_out);
876 ->Present(
info->view_id,
info->layers,
info->layers_count);
884- (
id<FlutterBinaryMessenger>)binaryMessenger {
888#pragma mark - Framework-internal methods
893 NSAssert(
self.viewController == nil,
894 @"The engine already has a view controller for the implicit view.");
895 self.viewController = controller;
899 [
self deregisterViewControllerForIdentifier:viewController.viewIdentifier];
900 [
self shutDownIfNeeded];
907- (void)updateDisplayConfig:(NSNotification*)notification {
908 [
self updateDisplayConfig];
911- (NSArray<NSScreen*>*)screens {
912 return [NSScreen screens];
915- (void)updateDisplayConfig {
920 std::vector<FlutterEngineDisplay> displays;
921 for (NSScreen* screen : [
self screens]) {
922 CGDirectDisplayID displayID =
923 static_cast<CGDirectDisplayID
>([screen.deviceDescription[@"NSScreenNumber"] integerValue]);
925 double devicePixelRatio = screen.backingScaleFactor;
930 display.
width =
static_cast<size_t>(screen.frame.size.width) * devicePixelRatio;
931 display.
height =
static_cast<size_t>(screen.frame.size.height) * devicePixelRatio;
934 CVDisplayLinkRef displayLinkRef = nil;
935 CVReturn
error = CVDisplayLinkCreateWithCGDisplay(displayID, &displayLinkRef);
938 CVTime nominal = CVDisplayLinkGetNominalOutputVideoRefreshPeriod(displayLinkRef);
939 if (!(nominal.flags & kCVTimeIsIndefinite)) {
940 double refreshRate =
static_cast<double>(nominal.timeScale) / nominal.timeValue;
943 CVDisplayLinkRelease(displayLinkRef);
948 displays.push_back(display);
951 displays.data(), displays.size());
954- (void)onSettingsChanged:(NSNotification*)notification {
956 NSString* brightness =
957 [[NSUserDefaults standardUserDefaults] stringForKey:@"AppleInterfaceStyle"];
958 [_settingsChannel sendMessage:@{
959 @"platformBrightness" : [brightness isEqualToString:@"Dark"] ? @"dark" : @"light",
961 @"textScaleFactor" : @1.0,
962 @"alwaysUse24HourFormat" : @false
966- (void)sendInitialSettings {
968 [[NSDistributedNotificationCenter defaultCenter]
970 selector:@selector(onSettingsChanged:)
971 name:@"AppleInterfaceThemeChangedNotification"
973 [
self onSettingsChanged:nil];
980- (nonnull NSString*)executableName {
981 return [[[NSProcessInfo processInfo] arguments] firstObject] ?:
@"Flutter";
989 @"The provided view controller is not attached to this engine.");
991 CGRect scaledBounds = [view convertRectToBacking:view.bounds];
992 CGSize scaledSize = scaledBounds.size;
993 double pixelRatio = view.bounds.size.width == 0 ? 1 : scaledSize.width / view.bounds.size.width;
994 auto displayId = [view.window.screen.deviceDescription[@"NSScreenNumber"] integerValue];
997 .
width =
static_cast<size_t>(scaledSize.width),
998 .height =
static_cast<size_t>(scaledSize.height),
999 .pixel_ratio = pixelRatio,
1000 .
left =
static_cast<size_t>(scaledBounds.origin.x),
1001 .top =
static_cast<size_t>(scaledBounds.origin.y),
1002 .display_id =
static_cast<uint64_t
>(displayId),
1005 _embedderAPI.SendWindowMetricsEvent(
_engine, &windowMetricsEvent);
1015 userData:(
void*)userData {
1019- (void)setSemanticsEnabled:(
BOOL)enabled {
1020 if (_semanticsEnabled == enabled) {
1023 _semanticsEnabled = enabled;
1026 NSEnumerator* viewControllerEnumerator = [_viewControllers objectEnumerator];
1028 while ((nextViewController = [viewControllerEnumerator nextObject])) {
1032 _embedderAPI.UpdateSemanticsEnabled(
_engine, _semanticsEnabled);
1036 toTarget:(uint16_t)target
1037 withData:(
fml::MallocMapping)data {
1045#pragma mark - Private methods
1047- (void)sendUserLocales {
1048 if (!
self.running) {
1053 NSMutableArray<NSLocale*>* locales = [NSMutableArray array];
1054 std::vector<FlutterLocale> flutterLocales;
1055 flutterLocales.reserve(locales.count);
1056 for (NSString* localeID in [NSLocale preferredLanguages]) {
1057 NSLocale* locale = [[NSLocale alloc] initWithLocaleIdentifier:localeID];
1058 [locales addObject:locale];
1062 std::vector<const FlutterLocale*> flutterLocaleList;
1063 flutterLocaleList.reserve(flutterLocales.size());
1064 std::transform(flutterLocales.begin(), flutterLocales.end(),
1065 std::back_inserter(flutterLocaleList),
1066 [](
const auto& arg) ->
const auto* { return &arg; });
1067 _embedderAPI.UpdateLocales(
_engine, flutterLocaleList.data(), flutterLocaleList.size());
1071 NSData* messageData = nil;
1072 if (
message->message_size > 0) {
1073 messageData = [NSData dataWithBytesNoCopy:(void*)message->message
1074 length:message->message_size
1077 NSString* channel = @(
message->channel);
1082 _embedderAPI.SendPlatformMessageResponse;
1084 @
synchronized(isResponseValid) {
1085 if (![isResponseValid[0] boolValue]) {
1089 if (responseHandle) {
1090 sendPlatformMessageResponse(weakSelf->_engine, responseHandle,
1091 static_cast<const uint8_t*
>(response.bytes), response.length);
1092 responseHandle = NULL;
1094 NSLog(
@"Error: Message responses can be sent only once. Ignoring duplicate response "
1103 handlerInfo.
handler(messageData, binaryResponseHandler);
1105 binaryResponseHandler(nil);
1109- (void)engineCallbackOnPreEngineRestart {
1110 NSEnumerator* viewControllerEnumerator = [_viewControllers objectEnumerator];
1112 while ((nextViewController = [viewControllerEnumerator nextObject])) {
1117- (void)onVSync:(uintptr_t)baton {
1129- (void)shutDownEngine {
1134 [_threadSynchronizer shutdown];
1139 NSLog(
@"Could not de-initialize the Flutter engine: error %d",
result);
1143 CFRelease((CFTypeRef)
self);
1147 NSLog(
@"Failed to shut down Flutter engine: error %d",
result);
1152- (void)setUpPlatformViewChannel {
1159 [_platformViewsChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
1160 [[weakSelf platformViewController] handleMethodCall:call result:result];
1164- (void)setUpAccessibilityChannel {
1170 [_accessibilityChannel setMessageHandler:^(id message, FlutterReply reply) {
1171 [weakSelf handleAccessibilityEvent:message];
1174- (void)setUpNotificationCenterListeners {
1175 NSNotificationCenter*
center = [NSNotificationCenter defaultCenter];
1177 [center addObserver:self
1178 selector:@selector(onAccessibilityStatusChanged:)
1179 name:kEnhancedUserInterfaceNotification
1181 [center addObserver:self
1182 selector:@selector(applicationWillTerminate:)
1183 name:NSApplicationWillTerminateNotification
1185 [center addObserver:self
1186 selector:@selector(windowDidChangeScreen:)
1187 name:NSWindowDidChangeScreenNotification
1189 [center addObserver:self
1190 selector:@selector(updateDisplayConfig:)
1191 name:NSApplicationDidChangeScreenParametersNotification
1195- (void)addInternalPlugins {
1208 [_platformChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
1209 [weakSelf handleMethodCall:call result:result];
1213- (void)didUpdateMouseCursor:(NSCursor*)cursor {
1217 [_lastViewWithPointerEvent didUpdateMouseCursor:cursor];
1220- (void)applicationWillTerminate:(NSNotification*)notification {
1221 [
self shutDownEngine];
1224- (void)windowDidChangeScreen:(NSNotification*)notification {
1227 NSEnumerator* viewControllerEnumerator = [_viewControllers objectEnumerator];
1229 while ((nextViewController = [viewControllerEnumerator nextObject])) {
1230 [
self updateWindowMetricsForViewController:nextViewController];
1234- (void)onAccessibilityStatusChanged:(NSNotification*)notification {
1235 BOOL enabled = [notification.userInfo[kEnhancedUserInterfaceKey] boolValue];
1236 NSEnumerator* viewControllerEnumerator = [_viewControllers objectEnumerator];
1238 while ((nextViewController = [viewControllerEnumerator nextObject])) {
1242 self.semanticsEnabled = enabled;
1244- (void)handleAccessibilityEvent:(NSDictionary<NSString*,
id>*)annotatedEvent {
1245 NSString*
type = annotatedEvent[@"type"];
1246 if ([
type isEqualToString:
@"announce"]) {
1247 NSString*
message = annotatedEvent[@"data"][@"message"];
1248 NSNumber* assertiveness = annotatedEvent[@"data"][@"assertiveness"];
1253 NSAccessibilityPriorityLevel priority = [assertiveness isEqualToNumber:@1]
1254 ? NSAccessibilityPriorityHigh
1255 : NSAccessibilityPriorityMedium;
1257 [
self announceAccessibilityMessage:message withPriority:priority];
1261- (void)announceAccessibilityMessage:(NSString*)message
1262 withPriority:(NSAccessibilityPriorityLevel)priority {
1263 NSAccessibilityPostNotificationWithUserInfo(
1265 NSAccessibilityAnnouncementRequestedNotification,
1266 @{NSAccessibilityAnnouncementKey :
message, NSAccessibilityPriorityKey : @(priority)});
1269 if ([
call.method isEqualToString:
@"SystemNavigator.pop"]) {
1270 [[NSApplication sharedApplication] terminate:self];
1272 }
else if ([
call.method isEqualToString:
@"SystemSound.play"]) {
1273 [
self playSystemSound:call.arguments];
1275 }
else if ([
call.method isEqualToString:
@"Clipboard.getData"]) {
1277 }
else if ([
call.method isEqualToString:
@"Clipboard.setData"]) {
1278 [
self setClipboardData:call.arguments];
1280 }
else if ([
call.method isEqualToString:
@"Clipboard.hasStrings"]) {
1281 result(@{
@"value" : @([
self clipboardHasStrings])});
1282 }
else if ([
call.method isEqualToString:
@"System.exitApplication"]) {
1283 if ([
self terminationHandler] == nil) {
1288 [NSApp terminate:self];
1291 [[
self terminationHandler] handleRequestAppExitMethodCall:call.arguments result:result];
1293 }
else if ([
call.method isEqualToString:
@"System.initializationComplete"]) {
1294 if ([
self terminationHandler] != nil) {
1295 [
self terminationHandler].acceptingRequests = YES;
1303- (void)playSystemSound:(NSString*)soundType {
1304 if ([soundType isEqualToString:
@"SystemSoundType.alert"]) {
1309- (NSDictionary*)getClipboardData:(NSString*)format {
1311 NSString* stringInPasteboard = [
self.pasteboard stringForType:NSPasteboardTypeString];
1312 return stringInPasteboard == nil ? nil : @{
@"text" : stringInPasteboard};
1317- (void)setClipboardData:(NSDictionary*)data {
1319 [
self.pasteboard clearContents];
1320 if (
text && ![
text isEqual:[NSNull null]]) {
1321 [
self.pasteboard setString:text forType:NSPasteboardTypeString];
1325- (
BOOL)clipboardHasStrings {
1326 return [
self.pasteboard stringForType:NSPasteboardTypeString].length > 0;
1329- (
std::vector<std::string>)switches {
1337#pragma mark - FlutterAppLifecycleDelegate
1340 NSString* nextState =
1341 [[NSString alloc] initWithCString:flutter::AppLifecycleStateToString(state)];
1342 [
self sendOnChannel:kFlutterLifecycleChannel
1343 message:[nextState dataUsingEncoding:NSUTF8StringEncoding]];
1350- (void)handleWillBecomeActive:(NSNotification*)notification {
1353 [
self setApplicationState:flutter::AppLifecycleState::kHidden];
1355 [
self setApplicationState:flutter::AppLifecycleState::kResumed];
1363- (void)handleWillResignActive:(NSNotification*)notification {
1366 [
self setApplicationState:flutter::AppLifecycleState::kHidden];
1368 [
self setApplicationState:flutter::AppLifecycleState::kInactive];
1376- (void)handleDidChangeOcclusionState:(NSNotification*)notification {
1377 NSApplicationOcclusionState occlusionState = [[NSApplication sharedApplication] occlusionState];
1378 if (occlusionState & NSApplicationOcclusionStateVisible) {
1381 [
self setApplicationState:flutter::AppLifecycleState::kResumed];
1383 [
self setApplicationState:flutter::AppLifecycleState::kInactive];
1387 [
self setApplicationState:flutter::AppLifecycleState::kHidden];
1391#pragma mark - FlutterBinaryMessenger
1393- (void)sendOnChannel:(nonnull NSString*)channel message:(nullable NSData*)message {
1394 [
self sendOnChannel:channel message:message binaryReply:nil];
1397- (void)sendOnChannel:(NSString*)channel
1398 message:(NSData* _Nullable)message
1405 auto captures = std::make_unique<Captures>();
1407 auto message_reply = [](
const uint8_t*
data,
size_t data_size,
void*
user_data) {
1408 auto captures =
reinterpret_cast<Captures*
>(
user_data);
1409 NSData* reply_data = nil;
1410 if (data !=
nullptr && data_size > 0) {
1411 reply_data = [NSData dataWithBytes:static_cast<const void*>(data) length:data_size];
1413 captures->reply(reply_data);
1418 _engine, message_reply, captures.get(), &response_handle);
1420 NSLog(
@"Failed to create a FlutterPlatformMessageResponseHandle (%d)", create_result);
1428 .channel = [channel UTF8String],
1430 .message_size =
message.length,
1431 .response_handle = response_handle,
1436 NSLog(
@"Failed to send message to Flutter engine on channel '%@' (%d).", channel,
1440 if (response_handle !=
nullptr) {
1442 _embedderAPI.PlatformMessageReleaseResponseHandle(
_engine, response_handle);
1444 NSLog(
@"Failed to release the response handle (%d).", release_result);
1450 binaryMessageHandler:
1455 handler:[handler copy]];
1462 NSString* foundChannel = nil;
1465 if ([handlerInfo.
connection isEqual:@(connection)]) {
1471 [_messengerHandlers removeObjectForKey:foundChannel];
1475#pragma mark - FlutterPluginRegistry
1477- (
id<FlutterPluginRegistrar>)registrarForPlugin:(NSString*)pluginName {
1478 id<FlutterPluginRegistrar> registrar =
self.pluginRegistrars[pluginName];
1482 self.pluginRegistrars[pluginName] = registrarImpl;
1483 registrar = registrarImpl;
1488- (nullable NSObject*)valuePublishedByPlugin:(NSString*)pluginName {
1492#pragma mark - FlutterTextureRegistrar
1495 return [_renderer registerTexture:texture];
1498- (
BOOL)registerTextureWithID:(int64_t)textureId {
1499 return _embedderAPI.RegisterExternalTexture(
_engine, textureId) ==
kSuccess;
1502- (void)textureFrameAvailable:(int64_t)textureID {
1503 [_renderer textureFrameAvailable:textureID];
1506- (
BOOL)markTextureFrameAvailable:(int64_t)textureID {
1507 return _embedderAPI.MarkExternalTextureFrameAvailable(
_engine, textureID) ==
kSuccess;
1510- (void)unregisterTexture:(int64_t)textureID {
1511 [_renderer unregisterTexture:textureID];
1514- (
BOOL)unregisterTextureWithID:(int64_t)textureID {
1515 return _embedderAPI.UnregisterExternalTexture(
_engine, textureID) ==
kSuccess;
1518#pragma mark - Task runner integration
1524 NSLog(
@"Could not post a task to the Flutter engine.");
1529- (void)postMainThreadTask:(
FlutterTask)task targetTimeInNanoseconds:(uint64_t)targetTime {
1532 [weakSelf runTaskOnEmbedder:task];
1535 const auto engine_time = _embedderAPI.GetCurrentTime();
1536 if (targetTime <= engine_time) {
1537 dispatch_async(dispatch_get_main_queue(), worker);
1540 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, targetTime - engine_time),
1541 dispatch_get_main_queue(), worker);
1546- (
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)
NSInteger clearContents()
std::vector< std::shared_ptr< FakeTexture > > textures
FlutterEngineResult FlutterEngineGetProcAddresses(FlutterEngineProcTable *table)
Gets the table of engine function pointers.
#define FLUTTER_API_SYMBOL(symbol)
@ kFlutterEngineAOTDataSourceTypeElfPath
void(* FlutterPlatformMessageCallback)(const FlutterPlatformMessage *, void *)
@ 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)
NSObject< FlutterBinaryMessenger > * binaryMessenger
void engineCallbackOnPlatformMessage:(const FlutterPlatformMessage *message)
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
FlutterMethodChannel * _platformViewsChannel
_FlutterEngineAOTData * _aotData
std::unique_ptr< flutter::FlutterCompositor > _macOSCompositor
static const int kMainThreadPriority
FlutterPlatformViewController * _platformViewController
static void OnPlatformMessage(const FlutterPlatformMessage *message, FlutterEngine *engine)
FlutterBasicMessageChannel * _accessibilityChannel
FlutterBasicMessageChannel * _settingsChannel
static FlutterLocale FlutterLocaleFromNSLocale(NSLocale *locale)
BOOL _allowHeadlessExecution
NSMutableDictionary< NSString *, FlutterEngineHandlerInfo * > * _messengerHandlers
FlutterBinaryMessengerConnection _currentMessengerConnection
FlutterMethodChannel * _platformChannel
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
FlutterBinaryMessengerRelay * _binaryMessenger
static NSString *const kEnhancedUserInterfaceKey
NSString *const kFlutterSettingsChannel
NS_ASSUME_NONNULL_BEGIN typedef void(^ FlutterTerminationCallback)(id _Nullable sender)
constexpr int64_t kFlutterImplicitViewId
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
std::vector< std::string > GetSwitchesFromEnvironment()
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).