| // 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/shell/platform/windows/task_runner_window.h" | |
| #include <algorithm> | |
| #include "flutter/fml/logging.h" | |
| namespace flutter { | |
| TaskRunnerWindow::TaskRunnerWindow() { | |
| WNDCLASS window_class = RegisterWindowClass(); | |
| window_handle_ = | |
| CreateWindowEx(0, window_class.lpszClassName, L"", 0, 0, 0, 0, 0, | |
| HWND_MESSAGE, nullptr, window_class.hInstance, nullptr); | |
| if (window_handle_) { | |
| SetWindowLongPtr(window_handle_, GWLP_USERDATA, | |
| reinterpret_cast<LONG_PTR>(this)); | |
| } else { | |
| auto error = GetLastError(); | |
| LPWSTR message = nullptr; | |
| size_t size = FormatMessageW( | |
| FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | | |
| FORMAT_MESSAGE_IGNORE_INSERTS, | |
| NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), | |
| reinterpret_cast<LPWSTR>(&message), 0, NULL); | |
| OutputDebugString(message); | |
| LocalFree(message); | |
| } | |
| } | |
| TaskRunnerWindow::~TaskRunnerWindow() { | |
| if (window_handle_) { | |
| DestroyWindow(window_handle_); | |
| window_handle_ = nullptr; | |
| } | |
| UnregisterClass(window_class_name_.c_str(), nullptr); | |
| } | |
| std::shared_ptr<TaskRunnerWindow> TaskRunnerWindow::GetSharedInstance() { | |
| static std::weak_ptr<TaskRunnerWindow> instance; | |
| auto res = instance.lock(); | |
| if (!res) { | |
| // can't use make_shared with private contructor | |
| res.reset(new TaskRunnerWindow()); | |
| instance = res; | |
| } | |
| return res; | |
| } | |
| void TaskRunnerWindow::WakeUp() { | |
| if (!PostMessage(window_handle_, WM_NULL, 0, 0)) { | |
| FML_LOG(ERROR) << "Failed to post message to main thread."; | |
| } | |
| } | |
| void TaskRunnerWindow::AddDelegate(Delegate* delegate) { | |
| delegates_.push_back(delegate); | |
| SetTimer(std::chrono::nanoseconds::zero()); | |
| } | |
| void TaskRunnerWindow::RemoveDelegate(Delegate* delegate) { | |
| auto i = std::find(delegates_.begin(), delegates_.end(), delegate); | |
| if (i != delegates_.end()) { | |
| delegates_.erase(i); | |
| } | |
| } | |
| void TaskRunnerWindow::ProcessTasks() { | |
| auto next = std::chrono::nanoseconds::max(); | |
| auto delegates_copy(delegates_); | |
| for (auto delegate : delegates_copy) { | |
| // if not removed in the meanwhile | |
| if (std::find(delegates_.begin(), delegates_.end(), delegate) != | |
| delegates_.end()) { | |
| next = std::min(next, delegate->ProcessTasks()); | |
| } | |
| } | |
| SetTimer(next); | |
| } | |
| void TaskRunnerWindow::SetTimer(std::chrono::nanoseconds when) { | |
| if (when == std::chrono::nanoseconds::max()) { | |
| KillTimer(window_handle_, 0); | |
| } else { | |
| auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(when); | |
| ::SetTimer(window_handle_, 0, millis.count() + 1, nullptr); | |
| } | |
| } | |
| WNDCLASS TaskRunnerWindow::RegisterWindowClass() { | |
| window_class_name_ = L"FlutterTaskRunnerWindow"; | |
| WNDCLASS window_class{}; | |
| window_class.hCursor = nullptr; | |
| window_class.lpszClassName = window_class_name_.c_str(); | |
| window_class.style = 0; | |
| window_class.cbClsExtra = 0; | |
| window_class.cbWndExtra = 0; | |
| window_class.hInstance = GetModuleHandle(nullptr); | |
| window_class.hIcon = nullptr; | |
| window_class.hbrBackground = 0; | |
| window_class.lpszMenuName = nullptr; | |
| window_class.lpfnWndProc = WndProc; | |
| RegisterClass(&window_class); | |
| return window_class; | |
| } | |
| LRESULT | |
| TaskRunnerWindow::HandleMessage(UINT const message, | |
| WPARAM const wparam, | |
| LPARAM const lparam) noexcept { | |
| switch (message) { | |
| case WM_TIMER: | |
| case WM_NULL: | |
| ProcessTasks(); | |
| return 0; | |
| } | |
| return DefWindowProcW(window_handle_, message, wparam, lparam); | |
| } | |
| LRESULT TaskRunnerWindow::WndProc(HWND const window, | |
| UINT const message, | |
| WPARAM const wparam, | |
| LPARAM const lparam) noexcept { | |
| if (auto* that = reinterpret_cast<TaskRunnerWindow*>( | |
| GetWindowLongPtr(window, GWLP_USERDATA))) { | |
| return that->HandleMessage(message, wparam, lparam); | |
| } else { | |
| return DefWindowProc(window, message, wparam, lparam); | |
| } | |
| } | |
| } // namespace flutter |