| Flutter Windows Embedder |

task_runner_window.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "flutter/shell/platform/windows/task_runner_window.h"
6
7 #include <algorithm>
8
9 #include "flutter/fml/logging.h"
10
11 namespace flutter {
12
13 static const uintptr_t kTimerId = 0;
14
15 // Timer used for PollOnce timeout.
16 static const uintptr_t kPollTimeoutTimerId = 1;
17
18 TaskRunnerWindow::TaskRunnerWindow() {
19 WNDCLASS window_class = RegisterWindowClass();
20 window_handle_ =
21 CreateWindowEx(0, window_class.lpszClassName, L"", 0, 0, 0, 0, 0,
22 HWND_MESSAGE, nullptr, window_class.hInstance, nullptr);
23
24 if (window_handle_) {
25 SetWindowLongPtr(window_handle_, GWLP_USERDATA,
26 reinterpret_cast<LONG_PTR>(this));
27 } else {
28 auto error = GetLastError();
29 LPWSTR message = nullptr;
30 size_t size = FormatMessageW(
31 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
32 FORMAT_MESSAGE_IGNORE_INSERTS,
33 NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
34 reinterpret_cast<LPWSTR>(&message), 0, NULL);
35 OutputDebugString(message);
36 LocalFree(message);
37 }
38 }
39
40 TaskRunnerWindow::~TaskRunnerWindow() {
41 if (window_handle_) {
42 DestroyWindow(window_handle_);
43 window_handle_ = nullptr;
44 }
45 UnregisterClass(window_class_name_.c_str(), nullptr);
46 }
47
48 std::shared_ptr<TaskRunnerWindow> TaskRunnerWindow::GetSharedInstance() {
49 static std::weak_ptr<TaskRunnerWindow> instance;
50 auto res = instance.lock();
51 if (!res) {
52 // can't use make_shared with private contructor
53 res.reset(new TaskRunnerWindow());
54 instance = res;
55 }
56 return res;
57 }
58
59 void TaskRunnerWindow::WakeUp() {
60 if (!PostMessage(window_handle_, WM_NULL, 0, 0)) {
61 FML_LOG(ERROR) << "Failed to post message to main thread.";
62 }
63 }
64
65 void TaskRunnerWindow::AddDelegate(Delegate* delegate) {
66 delegates_.push_back(delegate);
67 SetTimer(std::chrono::nanoseconds::zero());
68 }
69
70 void TaskRunnerWindow::RemoveDelegate(Delegate* delegate) {
71 auto i = std::find(delegates_.begin(), delegates_.end(), delegate);
72 if (i != delegates_.end()) {
73 delegates_.erase(i);
74 }
75 }
76
77 void TaskRunnerWindow::PollOnce(std::chrono::milliseconds timeout) {
78 MSG msg;
79 ::SetTimer(window_handle_, kPollTimeoutTimerId, timeout.count(), nullptr);
80 if (GetMessage(&msg, window_handle_, 0, 0)) {
81 TranslateMessage(&msg);
82 DispatchMessage(&msg);
83 }
84 ::KillTimer(window_handle_, kPollTimeoutTimerId);
85 }
86
87 void TaskRunnerWindow::ProcessTasks() {
88 auto next = std::chrono::nanoseconds::max();
89 auto delegates_copy(delegates_);
90 for (auto delegate : delegates_copy) {
91 // if not removed in the meanwhile
92 if (std::find(delegates_.begin(), delegates_.end(), delegate) !=
93 delegates_.end()) {
94 next = std::min(next, delegate->ProcessTasks());
95 }
96 }
97 SetTimer(next);
98 }
99
100 void TaskRunnerWindow::SetTimer(std::chrono::nanoseconds when) {
101 if (when == std::chrono::nanoseconds::max()) {
102 KillTimer(window_handle_, kTimerId);
103 } else {
104 auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(when);
105 ::SetTimer(window_handle_, kTimerId, millis.count() + 1, nullptr);
106 }
107 }
108
109 WNDCLASS TaskRunnerWindow::RegisterWindowClass() {
110 window_class_name_ = L"FlutterTaskRunnerWindow";
111
112 WNDCLASS window_class{};
113 window_class.hCursor = nullptr;
114 window_class.lpszClassName = window_class_name_.c_str();
115 window_class.style = 0;
116 window_class.cbClsExtra = 0;
117 window_class.cbWndExtra = 0;
118 window_class.hInstance = GetModuleHandle(nullptr);
119 window_class.hIcon = nullptr;
120 window_class.hbrBackground = 0;
121 window_class.lpszMenuName = nullptr;
122 window_class.lpfnWndProc = WndProc;
123 RegisterClass(&window_class);
124 return window_class;
125 }
126
127 LRESULT
128 TaskRunnerWindow::HandleMessage(UINT const message,
129 WPARAM const wparam,
130 LPARAM const lparam) noexcept {
131 switch (message) {
132 case WM_TIMER:
133 if (wparam == kPollTimeoutTimerId) {
134 // Ignore PollOnce timeout timer.
135 return 0;
136 }
137 FML_DCHECK(wparam == kTimerId);
138 ProcessTasks();
139 return 0;
140 case WM_NULL:
141 ProcessTasks();
142 return 0;
143 }
144 return DefWindowProcW(window_handle_, message, wparam, lparam);
145 }
146
147 LRESULT TaskRunnerWindow::WndProc(HWND const window,
148 UINT const message,
149 WPARAM const wparam,
150 LPARAM const lparam) noexcept {
151 if (auto* that = reinterpret_cast<TaskRunnerWindow*>(
152 GetWindowLongPtr(window, GWLP_USERDATA))) {
153 return that->HandleMessage(message, wparam, lparam);
154 } else {
155 return DefWindowProc(window, message, wparam, lparam);
156 }
157 }
158
159 } // namespace flutter
flutter::TaskRunnerWindow::Delegate
Definition: task_runner_window.h:22
flutter::TaskRunnerWindow
Definition: task_runner_window.h:20
flutter::TaskRunnerWindow::WakeUp
void WakeUp()
Definition: task_runner_window.cc:59
flutter::TaskRunnerWindow::PollOnce
void PollOnce(std::chrono::milliseconds timeout)
Definition: task_runner_window.cc:77
flutter::TaskRunnerWindow::GetSharedInstance
static std::shared_ptr< TaskRunnerWindow > GetSharedInstance()
Definition: task_runner_window.cc:48
flutter::TaskRunnerWindow::AddDelegate
void AddDelegate(Delegate *delegate)
Definition: task_runner_window.cc:65
flutter::TaskRunnerWindow::RemoveDelegate
void RemoveDelegate(Delegate *delegate)
Definition: task_runner_window.cc:70
flutter::TaskRunnerWindow::~TaskRunnerWindow
~TaskRunnerWindow()
Definition: task_runner_window.cc:40
message
Win32Message message
Definition: keyboard_unittests.cc:137
flutter
Definition: accessibility_bridge_windows.cc:11
flutter::kTimerId
static const uintptr_t kTimerId
Definition: task_runner_window.cc:13
flutter::kPollTimeoutTimerId
static const uintptr_t kPollTimeoutTimerId
Definition: task_runner_window.cc:16
task_runner_window.h