| Flutter macOS Embedder |

FlutterRunLoop.mm
Go to the documentation of this file.
1 #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterRunLoop.h"
2 #include <vector>
3 #include "fml/logging.h"
4
5 namespace {
6 struct Task {
7 void (^block)(void);
8 CFAbsoluteTime target_time;
9
10 Task(void (^block)(void), CFAbsoluteTime target_time) : block(block), target_time(target_time) {}
11 };
12
13 const CFStringRef kFlutterRunLoopMode = CFSTR("FlutterRunLoopMode");
14
15 FlutterRunLoop* mainLoop;
16
17 } // namespace
18
19 @implementation FlutterRunLoop {
20 CFRunLoopRef _runLoop;
21 CFRunLoopSourceRef _source;
22 CFRunLoopTimerRef _timer;
23 std::vector<Task> _tasks;
24 }
25
26 static void Perform(void* info) {
27 FlutterRunLoop* runner = (__bridge FlutterRunLoop*)info;
28 [runner performExpiredTasks];
29 }
30
31 static void PerformTimer(CFRunLoopTimerRef timer, void* info) {
32 FlutterRunLoop* runner = (__bridge FlutterRunLoop*)info;
33 [runner performExpiredTasks];
34 }
35
36 - (instancetype)init {
37 if (self = [super init]) {
38 _runLoop = CFRunLoopGetCurrent();
39 CFRunLoopSourceContext sourceContext = {
40 .info = (__bridge void*)self,
41 .perform = Perform,
42 };
43 _source = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &sourceContext);
44 CFRunLoopAddSource(_runLoop, _source, kCFRunLoopCommonModes);
45 CFRunLoopAddSource(_runLoop, _source, kFlutterRunLoopMode);
46
47 CFRunLoopTimerContext timerContext = {
48 .info = (__bridge void*)self,
49 };
50 _timer = CFRunLoopTimerCreate(kCFAllocatorDefault, HUGE_VALF, HUGE_VALF, 0, 0, PerformTimer,
51 &timerContext);
52 CFRunLoopAddTimer(_runLoop, _timer, kCFRunLoopCommonModes);
53 CFRunLoopAddTimer(_runLoop, _timer, kFlutterRunLoopMode);
54 }
55 return self;
56 }
57
58 - (void)dealloc {
59 CFRunLoopTimerInvalidate(_timer);
60 CFRunLoopRemoveTimer(_runLoop, _timer, kCFRunLoopCommonModes);
61 CFRunLoopRemoveTimer(_runLoop, _timer, kFlutterRunLoopMode);
62 CFRunLoopSourceInvalidate(_source);
63 CFRunLoopRemoveSource(_runLoop, _source, kCFRunLoopCommonModes);
64 CFRunLoopRemoveSource(_runLoop, _source, kFlutterRunLoopMode);
65 }
66
67 - (void)rearmTimer {
68 CFAbsoluteTime nextFireTime = HUGE_VALF;
69 for (const auto& task : _tasks) {
70 nextFireTime = std::min(nextFireTime, task.target_time);
71 }
72 CFRunLoopTimerSetNextFireDate(_timer, nextFireTime);
73 }
74
75 - (void)performExpiredTasks {
76 std::vector<Task> expiredTasks;
77 @synchronized(self) {
78 CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
79 std::vector<Task>::iterator it = _tasks.begin();
80 while (it != _tasks.end()) {
81 if (it->target_time <= now) {
82 expiredTasks.push_back(std::move(*it));
83 it = _tasks.erase(it);
84 } else {
85 ++it;
86 }
87 }
88 [self rearmTimer];
89 }
90 for (const auto& task : expiredTasks) {
91 task.block();
92 }
93 }
94
95 - (void)performBlock:(void (^)(void))block afterDelay:(NSTimeInterval)delay {
96 @synchronized(self) {
97 _tasks.emplace_back(block, CFAbsoluteTimeGetCurrent() + delay);
98 if (delay > 0) {
99 [self rearmTimer];
100 } else {
101 CFRunLoopSourceSignal(_source);
102 CFRunLoopWakeUp(_runLoop);
103 }
104 }
105 }
106
107 - (void)performBlock:(void (^)(void))block {
108 [self performBlock:block afterDelay:0];
109 }
110
111 + (void)ensureMainLoopInitialized {
112 FML_DCHECK(NSRunLoop.currentRunLoop == NSRunLoop.mainRunLoop);
113 if (mainLoop == nil) {
114 mainLoop = [[FlutterRunLoop alloc] init];
115 }
116 }
117
118 + (FlutterRunLoop*)mainRunLoop {
119 FML_DCHECK(mainLoop != nil);
120 return mainLoop;
121 }
122
123 - (void)pollFlutterMessagesOnce {
124 CFRunLoopRunInMode(kFlutterRunLoopMode, 0.1, YES);
125 }
126
127 @end
FlutterRunLoop.h
_tasks
std::vector< Task > _tasks
Definition: FlutterRunLoop.mm:23
_source
CFRunLoopSourceRef _source
Definition: FlutterRunLoop.mm:19
_timer
CFRunLoopTimerRef _timer
Definition: FlutterRunLoop.mm:22
FlutterRunLoop
Definition: FlutterRunLoop.h:16