14 #include "flutter/fml/logging.h"
21 std::chrono::time_point<std::chrono::high_resolution_clock>::max()) {}
26 std::make_optional<std::thread>(&TimerThread::TimerThreadMain,
this);
34 std::lock_guard<std::mutex> lock(mutex_);
43 FML_DCHECK(callback_ ==
nullptr || !thread_);
50 std::chrono::time_point<std::chrono::high_resolution_clock> time_point) {
51 std::lock_guard<std::mutex> lock(mutex_);
52 if (time_point < next_fire_time_) {
53 next_fire_time_ = time_point;
59 void TimerThread::TimerThreadMain() {
60 std::unique_lock<std::mutex> lock(mutex_);
61 while (callback_ !=
nullptr) {
62 cv_.wait_until(lock, next_fire_time_, [
this]() {
63 return std::chrono::high_resolution_clock::now() >= next_fire_time_ ||
66 auto scheduled_count = schedule_counter_;
73 if (scheduled_count == schedule_counter_ &&
74 next_fire_time_ <= std::chrono::high_resolution_clock::now()) {
76 std::chrono::time_point<std::chrono::high_resolution_clock>::max();
84 TaskRunnerWindow::TaskRunnerWindow() : timer_thread_([this]() { OnTimer(); }) {
85 WNDCLASS window_class = RegisterWindowClass();
87 CreateWindowEx(0, window_class.lpszClassName, L
"", 0, 0, 0, 0, 0,
88 HWND_MESSAGE,
nullptr, window_class.hInstance,
nullptr);
91 SetWindowLongPtr(window_handle_, GWLP_USERDATA,
92 reinterpret_cast<LONG_PTR
>(
this));
93 timer_thread_.Start();
95 auto error = GetLastError();
97 size_t size = FormatMessageW(
98 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
99 FORMAT_MESSAGE_IGNORE_INSERTS,
100 NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
101 reinterpret_cast<LPWSTR
>(&
message), 0, NULL);
106 thread_id_ = GetCurrentThreadId();
109 TaskRunnerWindow::~TaskRunnerWindow() {
110 timer_thread_.Stop();
112 if (window_handle_) {
113 DestroyWindow(window_handle_);
114 window_handle_ =
nullptr;
116 UnregisterClass(window_class_name_.c_str(),
nullptr);
119 void TaskRunnerWindow::OnTimer() {
123 void TaskRunnerWindow::TimerProc(PTP_CALLBACK_INSTANCE instance,
126 reinterpret_cast<TaskRunnerWindow*
>(context)->OnTimer();
129 std::shared_ptr<TaskRunnerWindow> TaskRunnerWindow::GetSharedInstance() {
130 static std::weak_ptr<TaskRunnerWindow> instance;
131 auto res = instance.lock();
140 void TaskRunnerWindow::WakeUp() {
141 bool expected =
false;
145 if (wake_up_posted_.compare_exchange_strong(expected,
true)) {
146 if (!PostMessage(window_handle_, WM_NULL, 0, 0)) {
147 FML_LOG(ERROR) <<
"Failed to post message to main thread.";
152 void TaskRunnerWindow::AddDelegate(
Delegate* delegate) {
153 delegates_.push_back(delegate);
154 SetTimer(std::chrono::nanoseconds::zero());
157 void TaskRunnerWindow::RemoveDelegate(
Delegate* delegate) {
158 auto i = std::find(delegates_.begin(), delegates_.end(), delegate);
159 if (i != delegates_.end()) {
164 void TaskRunnerWindow::PollOnce(std::chrono::milliseconds timeout) {
167 if (GetMessage(&msg, window_handle_, 0, 0)) {
168 TranslateMessage(&msg);
169 DispatchMessage(&msg);
174 void TaskRunnerWindow::ProcessTasks() {
175 auto next = std::chrono::nanoseconds::max();
176 auto delegates_copy(delegates_);
177 for (
auto delegate : delegates_copy) {
179 if (std::find(delegates_.begin(), delegates_.end(), delegate) !=
181 next = std::min(next, delegate->ProcessTasks());
187 void TaskRunnerWindow::SetTimer(std::chrono::nanoseconds when) {
188 if (when == std::chrono::nanoseconds::max()) {
189 timer_thread_.ScheduleAt(
190 std::chrono::time_point<std::chrono::high_resolution_clock>::max());
192 timer_thread_.ScheduleAt(std::chrono::high_resolution_clock::now() + when);
196 WNDCLASS TaskRunnerWindow::RegisterWindowClass() {
197 window_class_name_ = L
"FlutterTaskRunnerWindow";
199 WNDCLASS window_class{};
200 window_class.hCursor =
nullptr;
201 window_class.lpszClassName = window_class_name_.c_str();
202 window_class.style = 0;
203 window_class.cbClsExtra = 0;
204 window_class.cbWndExtra = 0;
205 window_class.hInstance = GetModuleHandle(
nullptr);
206 window_class.hIcon =
nullptr;
207 window_class.hbrBackground = 0;
208 window_class.lpszMenuName =
nullptr;
209 window_class.lpfnWndProc = WndProc;
210 RegisterClass(&window_class);
215 TaskRunnerWindow::HandleMessage(UINT
const message,
217 LPARAM
const lparam) noexcept {
222 wake_up_posted_ =
false;
226 return DefWindowProcW(window_handle_,
message, wparam, lparam);
229 LRESULT TaskRunnerWindow::WndProc(HWND
const window,
232 LPARAM
const lparam) noexcept {
233 if (
auto* that =
reinterpret_cast<TaskRunnerWindow*
>(
234 GetWindowLongPtr(window, GWLP_USERDATA))) {
235 return that->HandleMessage(
message, wparam, lparam);
237 return DefWindowProc(window,
message, wparam, lparam);
void ScheduleAt(std::chrono::time_point< std::chrono::high_resolution_clock > time_point)
TimerThread(std::function< void()> callback)
FlutterDesktopBinaryReply callback
static const uintptr_t kPollTimeoutTimerId