blob: d48cf3349920140f128312b917471359b5632493 [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/fml/platform/darwin/message_loop_darwin.h"
#include <CoreFoundation/CFRunLoop.h>
#include <Foundation/Foundation.h>
#include "flutter/fml/logging.h"
namespace fml {
static constexpr CFTimeInterval kDistantFuture = 1.0e10;
CFStringRef MessageLoopDarwin::kMessageLoopCFRunLoopMode = CFSTR("fmlMessageLoop");
MessageLoopDarwin::MessageLoopDarwin()
: running_(false), loop_((CFRunLoopRef)CFRetain(CFRunLoopGetCurrent())) {
FML_DCHECK(loop_ != nullptr);
// Setup the delayed wake source.
CFRunLoopTimerContext timer_context = {
.info = this,
};
delayed_wake_timer_.Reset(
CFRunLoopTimerCreate(kCFAllocatorDefault, kDistantFuture /* fire date */,
HUGE_VAL /* interval */, 0 /* flags */, 0 /* order */,
reinterpret_cast<CFRunLoopTimerCallBack>(&MessageLoopDarwin::OnTimerFire)
/* callout */,
&timer_context /* context */));
FML_DCHECK(delayed_wake_timer_ != nullptr);
CFRunLoopAddTimer(loop_, delayed_wake_timer_, kCFRunLoopCommonModes);
// This mode will be used by FlutterKeyboardManager.
CFRunLoopAddTimer(loop_, delayed_wake_timer_, kMessageLoopCFRunLoopMode);
}
MessageLoopDarwin::~MessageLoopDarwin() {
CFRunLoopTimerInvalidate(delayed_wake_timer_);
CFRunLoopRemoveTimer(loop_, delayed_wake_timer_, kCFRunLoopCommonModes);
CFRunLoopRemoveTimer(loop_, delayed_wake_timer_, kMessageLoopCFRunLoopMode);
}
void MessageLoopDarwin::Run() {
FML_DCHECK(loop_ == CFRunLoopGetCurrent());
running_ = true;
while (running_) {
@autoreleasepool {
int result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, kDistantFuture, YES);
if (result == kCFRunLoopRunStopped || result == kCFRunLoopRunFinished) {
// This handles the case where the loop is terminated using
// CoreFoundation APIs.
@autoreleasepool {
RunExpiredTasksNow();
}
running_ = false;
}
}
}
}
void MessageLoopDarwin::Terminate() {
running_ = false;
// Ensure that the CFRunLoop remains alive through the end of this function
// even if the loop's thread exits and drops its reference to the loop.
CFRef<CFRunLoopRef> local_loop(loop_);
CFRunLoopStop(local_loop);
}
void MessageLoopDarwin::WakeUp(fml::TimePoint time_point) {
// Rearm the timer. The time bases used by CoreFoundation and FXL are
// different and must be accounted for.
CFRunLoopTimerSetNextFireDate(
delayed_wake_timer_,
CFAbsoluteTimeGetCurrent() + (time_point - fml::TimePoint::Now()).ToSecondsF());
}
void MessageLoopDarwin::OnTimerFire(CFRunLoopTimerRef timer, MessageLoopDarwin* loop) {
@autoreleasepool {
// RunExpiredTasksNow rearms the timer as appropriate via a call to WakeUp.
loop->RunExpiredTasksNow();
}
}
} // namespace fml