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() {
120 if (!PostMessage(window_handle_, WM_NULL, 0, 0)) {
121 FML_LOG(ERROR) <<
"Failed to post message to main thread.";
125 void TaskRunnerWindow::TimerProc(PTP_CALLBACK_INSTANCE instance,
128 reinterpret_cast<TaskRunnerWindow*
>(context)->OnTimer();
131 std::shared_ptr<TaskRunnerWindow> TaskRunnerWindow::GetSharedInstance() {
132 static std::weak_ptr<TaskRunnerWindow> instance;
133 auto res = instance.lock();
142 void TaskRunnerWindow::WakeUp() {
150 if (thread_id_ == GetCurrentThreadId() && GetQueueStatus(QS_ALLEVENTS) != 0) {
151 SetTimer(std::chrono::milliseconds(1));
155 if (!PostMessage(window_handle_, WM_NULL, 0, 0)) {
156 FML_LOG(ERROR) <<
"Failed to post message to main thread.";
160 void TaskRunnerWindow::AddDelegate(
Delegate* delegate) {
161 delegates_.push_back(delegate);
162 SetTimer(std::chrono::nanoseconds::zero());
165 void TaskRunnerWindow::RemoveDelegate(
Delegate* delegate) {
166 auto i = std::find(delegates_.begin(), delegates_.end(), delegate);
167 if (i != delegates_.end()) {
172 void TaskRunnerWindow::PollOnce(std::chrono::milliseconds timeout) {
175 if (GetMessage(&msg, window_handle_, 0, 0)) {
176 TranslateMessage(&msg);
177 DispatchMessage(&msg);
182 void TaskRunnerWindow::ProcessTasks() {
183 auto next = std::chrono::nanoseconds::max();
184 auto delegates_copy(delegates_);
185 for (
auto delegate : delegates_copy) {
187 if (std::find(delegates_.begin(), delegates_.end(), delegate) !=
189 next = std::min(next, delegate->ProcessTasks());
195 void TaskRunnerWindow::SetTimer(std::chrono::nanoseconds when) {
196 if (when == std::chrono::nanoseconds::max()) {
197 timer_thread_.ScheduleAt(
198 std::chrono::time_point<std::chrono::high_resolution_clock>::max());
200 timer_thread_.ScheduleAt(std::chrono::high_resolution_clock::now() + when);
204 WNDCLASS TaskRunnerWindow::RegisterWindowClass() {
205 window_class_name_ = L
"FlutterTaskRunnerWindow";
207 WNDCLASS window_class{};
208 window_class.hCursor =
nullptr;
209 window_class.lpszClassName = window_class_name_.c_str();
210 window_class.style = 0;
211 window_class.cbClsExtra = 0;
212 window_class.cbWndExtra = 0;
213 window_class.hInstance = GetModuleHandle(
nullptr);
214 window_class.hIcon =
nullptr;
215 window_class.hbrBackground = 0;
216 window_class.lpszMenuName =
nullptr;
217 window_class.lpfnWndProc = WndProc;
218 RegisterClass(&window_class);
223 TaskRunnerWindow::HandleMessage(UINT
const message,
225 LPARAM
const lparam) noexcept {
231 return DefWindowProcW(window_handle_,
message, wparam, lparam);
234 LRESULT TaskRunnerWindow::WndProc(HWND
const window,
237 LPARAM
const lparam) noexcept {
238 if (
auto* that =
reinterpret_cast<TaskRunnerWindow*
>(
239 GetWindowLongPtr(window, GWLP_USERDATA))) {
240 return that->HandleMessage(
message, wparam, lparam);
242 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