• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "flutter/shell/platform/windows/win32_flutter_window.h"
2 
3 #include <chrono>
4 
5 namespace flutter {
6 
7 // the Windows DPI system is based on this
8 // constant for machines running at 100% scaling.
9 constexpr int base_dpi = 96;
10 
Win32FlutterWindow()11 Win32FlutterWindow::Win32FlutterWindow() {
12   surface_manager = std::make_unique<AngleSurfaceManager>();
13 }
14 
Win32FlutterWindow(const char * title,const int x,const int y,const int width,const int height)15 Win32FlutterWindow::Win32FlutterWindow(const char* title,
16                                        const int x,
17                                        const int y,
18                                        const int width,
19                                        const int height) noexcept
20     : Win32FlutterWindow() {
21   Win32Window::Initialize(title, x, y, width, height);
22 }
23 
~Win32FlutterWindow()24 Win32FlutterWindow::~Win32FlutterWindow() {
25   DestroyRenderSurface();
26 }
27 
CreateWin32FlutterWindow(const char * title,const int x,const int y,const int width,const int height)28 FlutterDesktopWindowControllerRef Win32FlutterWindow::CreateWin32FlutterWindow(
29     const char* title,
30     const int x,
31     const int y,
32     const int width,
33     const int height) {
34   auto state = std::make_unique<FlutterDesktopWindowControllerState>();
35   state->window = std::make_unique<flutter::Win32FlutterWindow>(title, 10, 10,
36                                                                 width, height);
37 
38   // a window wrapper for the state block, distinct from the
39   // window_wrapper handed to plugin_registrar.
40   state->window_wrapper = std::make_unique<FlutterDesktopWindow>();
41   state->window_wrapper->window = state->window.get();
42   return state.release();
43 }
44 
SetState(FLUTTER_API_SYMBOL (FlutterEngine)eng)45 void Win32FlutterWindow::SetState(FLUTTER_API_SYMBOL(FlutterEngine) eng) {
46   engine_ = eng;
47 
48   auto messenger = std::make_unique<FlutterDesktopMessenger>();
49   message_dispatcher_ =
50       std::make_unique<flutter::IncomingMessageDispatcher>(messenger.get());
51   messenger->engine = engine_;
52   messenger->dispatcher = message_dispatcher_.get();
53 
54   window_wrapper_ = std::make_unique<FlutterDesktopWindow>();
55   window_wrapper_->window = this;
56 
57   plugin_registrar_ = std::make_unique<FlutterDesktopPluginRegistrar>();
58   plugin_registrar_->messenger = std::move(messenger);
59   plugin_registrar_->window = window_wrapper_.get();
60 
61   internal_plugin_registrar_ =
62       std::make_unique<flutter::PluginRegistrar>(plugin_registrar_.get());
63 
64   // Set up the keyboard handlers.
65   auto internal_plugin_messenger = internal_plugin_registrar_->messenger();
66   keyboard_hook_handlers_.push_back(
67       std::make_unique<flutter::KeyEventHandler>(internal_plugin_messenger));
68   keyboard_hook_handlers_.push_back(
69       std::make_unique<flutter::TextInputPlugin>(internal_plugin_messenger));
70   platform_handler_ = std::make_unique<flutter::PlatformHandler>(
71       internal_plugin_messenger, this);
72 
73   auto state = std::make_unique<FlutterDesktopWindowControllerState>();
74   state->engine = engine_;
75 
76   process_events_ = true;
77 }
78 
GetRegistrar()79 FlutterDesktopPluginRegistrarRef Win32FlutterWindow::GetRegistrar() {
80   return plugin_registrar_.get();
81 }
82 
83 // Converts a FlutterPlatformMessage to an equivalent FlutterDesktopMessage.
ConvertToDesktopMessage(const FlutterPlatformMessage & engine_message)84 static FlutterDesktopMessage ConvertToDesktopMessage(
85     const FlutterPlatformMessage& engine_message) {
86   FlutterDesktopMessage message = {};
87   message.struct_size = sizeof(message);
88   message.channel = engine_message.channel;
89   message.message = engine_message.message;
90   message.message_size = engine_message.message_size;
91   message.response_handle = engine_message.response_handle;
92   return message;
93 }
94 
95 // The Flutter Engine calls out to this function when new platform messages
96 // are available.
HandlePlatformMessage(const FlutterPlatformMessage * engine_message)97 void Win32FlutterWindow::HandlePlatformMessage(
98     const FlutterPlatformMessage* engine_message) {
99   if (engine_message->struct_size != sizeof(FlutterPlatformMessage)) {
100     std::cerr << "Invalid message size received. Expected: "
101               << sizeof(FlutterPlatformMessage) << " but received "
102               << engine_message->struct_size << std::endl;
103     return;
104   }
105 
106   auto message = ConvertToDesktopMessage(*engine_message);
107 
108   message_dispatcher_->HandleMessage(
109       message, [this] { this->process_events_ = false; },
110       [this] { this->process_events_ = true; });
111 }
112 
OnDpiScale(unsigned int dpi)113 void Win32FlutterWindow::OnDpiScale(unsigned int dpi){};
114 
115 // When DesktopWindow notifies that a WM_Size message has come in
116 // lets FlutterEngine know about the new size.
OnResize(unsigned int width,unsigned int height)117 void Win32FlutterWindow::OnResize(unsigned int width, unsigned int height) {
118   SendWindowMetrics();
119 }
120 
OnPointerMove(double x,double y)121 void Win32FlutterWindow::OnPointerMove(double x, double y) {
122   if (process_events_) {
123     SendPointerMove(x, y);
124   }
125 }
126 
OnPointerDown(double x,double y)127 void Win32FlutterWindow::OnPointerDown(double x, double y) {
128   if (process_events_) {
129     SendPointerDown(x, y);
130   }
131 }
132 
OnPointerUp(double x,double y)133 void Win32FlutterWindow::OnPointerUp(double x, double y) {
134   if (process_events_) {
135     SendPointerUp(x, y);
136   }
137 }
138 
OnChar(unsigned int code_point)139 void Win32FlutterWindow::OnChar(unsigned int code_point) {
140   if (process_events_) {
141     SendChar(code_point);
142   }
143 }
144 
OnKey(int key,int scancode,int action,int mods)145 void Win32FlutterWindow::OnKey(int key, int scancode, int action, int mods) {
146   if (process_events_) {
147     SendKey(key, scancode, action, 0);
148   }
149 }
150 
OnScroll(double delta_x,double delta_y)151 void Win32FlutterWindow::OnScroll(double delta_x, double delta_y) {
152   if (process_events_) {
153     SendScroll(delta_x, delta_y);
154   }
155 }
156 
OnClose()157 void Win32FlutterWindow::OnClose() {
158   messageloop_running_ = false;
159 }
160 
FlutterMessageLoop()161 void Win32FlutterWindow::FlutterMessageLoop() {
162   MSG message;
163 
164   messageloop_running_ = true;
165 
166   // TODO: need either non-blocking meesage loop or custom dispatch
167   // implementation per  https://github.com/flutter/flutter/issues/36420
168   while (GetMessage(&message, nullptr, 0, 0) && messageloop_running_) {
169     TranslateMessage(&message);
170     DispatchMessage(&message);
171     __FlutterEngineFlushPendingTasksNow();
172   }
173 }
174 
175 // Sends new size information to FlutterEngine.
SendWindowMetrics()176 void Win32FlutterWindow::SendWindowMetrics() {
177   if (engine_ == nullptr) {
178     return;
179   }
180 
181   FlutterWindowMetricsEvent event = {};
182   event.struct_size = sizeof(event);
183   event.width = GetCurrentWidth();
184   event.height = GetCurrentHeight();
185   event.pixel_ratio = static_cast<double>(GetCurrentDPI()) / base_dpi;
186   auto result = FlutterEngineSendWindowMetricsEvent(engine_, &event);
187 }
188 
189 // Updates |event_data| with the current location of the mouse cursor.
SetEventLocationFromCursorPosition(FlutterPointerEvent * event_data)190 void Win32FlutterWindow::SetEventLocationFromCursorPosition(
191     FlutterPointerEvent* event_data) {
192   POINT point;
193   GetCursorPos(&point);
194 
195   ScreenToClient(GetWindowHandle(), &point);
196 
197   event_data->x = point.x;
198   event_data->y = point.y;
199 }
200 
201 // Set's |event_data|'s phase to either kMove or kHover depending on the current
202 // primary mouse button state.
SetEventPhaseFromCursorButtonState(FlutterPointerEvent * event_data)203 void Win32FlutterWindow::SetEventPhaseFromCursorButtonState(
204     FlutterPointerEvent* event_data) {
205   event_data->phase = pointer_is_down_ ? FlutterPointerPhase::kMove
206                                        : FlutterPointerPhase::kHover;
207 }
208 
SendPointerMove(double x,double y)209 void Win32FlutterWindow::SendPointerMove(double x, double y) {
210   FlutterPointerEvent event = {};
211   event.x = x;
212   event.y = y;
213   SetEventPhaseFromCursorButtonState(&event);
214   SendPointerEventWithData(event);
215 }
216 
SendPointerDown(double x,double y)217 void Win32FlutterWindow::SendPointerDown(double x, double y) {
218   pointer_is_down_ = true;
219   FlutterPointerEvent event = {};
220   event.phase = FlutterPointerPhase::kDown;
221   event.x = x;
222   event.y = y;
223   SendPointerEventWithData(event);
224 }
225 
SendPointerUp(double x,double y)226 void Win32FlutterWindow::SendPointerUp(double x, double y) {
227   pointer_is_down_ = false;
228   FlutterPointerEvent event = {};
229   event.phase = FlutterPointerPhase::kUp;
230   event.x = x;
231   event.y = y;
232   SendPointerEventWithData(event);
233 }
234 
SendChar(unsigned int code_point)235 void Win32FlutterWindow::SendChar(unsigned int code_point) {
236   for (const auto& handler : keyboard_hook_handlers_) {
237     handler->CharHook(this, code_point);
238   }
239 }
240 
SendKey(int key,int scancode,int action,int mods)241 void Win32FlutterWindow::SendKey(int key, int scancode, int action, int mods) {
242   for (const auto& handler : keyboard_hook_handlers_) {
243     handler->KeyboardHook(this, key, scancode, action, mods);
244   }
245 }
246 
SendScroll(double delta_x,double delta_y)247 void Win32FlutterWindow::SendScroll(double delta_x, double delta_y) {
248   FlutterPointerEvent event = {};
249   SetEventLocationFromCursorPosition(&event);
250   SetEventPhaseFromCursorButtonState(&event);
251   event.signal_kind = FlutterPointerSignalKind::kFlutterPointerSignalKindScroll;
252   // TODO: See if this can be queried from the OS; this value is chosen
253   // arbitrarily to get something that feels reasonable.
254   const int kScrollOffsetMultiplier = 20;
255   event.scroll_delta_x = delta_x * kScrollOffsetMultiplier;
256   event.scroll_delta_y = delta_y * kScrollOffsetMultiplier;
257   SendPointerEventWithData(event);
258 }
259 
SendPointerEventWithData(const FlutterPointerEvent & event_data)260 void Win32FlutterWindow::SendPointerEventWithData(
261     const FlutterPointerEvent& event_data) {
262   // If sending anything other than an add, and the pointer isn't already added,
263   // synthesize an add to satisfy Flutter's expectations about events.
264   if (!pointer_currently_added_ &&
265       event_data.phase != FlutterPointerPhase::kAdd) {
266     FlutterPointerEvent event = {};
267     event.phase = FlutterPointerPhase::kAdd;
268     event.x = event_data.x;
269     event.y = event_data.y;
270     SendPointerEventWithData(event);
271   }
272   // Don't double-add (e.g., if events are delivered out of order, so an add has
273   // already been synthesized).
274   if (pointer_currently_added_ &&
275       event_data.phase == FlutterPointerPhase::kAdd) {
276     return;
277   }
278 
279   FlutterPointerEvent event = event_data;
280   // Set metadata that's always the same regardless of the event.
281   event.struct_size = sizeof(event);
282   event.timestamp =
283       std::chrono::duration_cast<std::chrono::microseconds>(
284           std::chrono::high_resolution_clock::now().time_since_epoch())
285           .count();
286 
287   // Windows passes all input in either physical pixels (Per-monitor, System
288   // DPI) or pre-scaled to match bitmap scaling of output where process is
289   // running in DPI unaware more.  In either case, no need to manually scale
290   // input here.  For more information see DPIHelper.
291   event.scroll_delta_x;
292   event.scroll_delta_y;
293 
294   FlutterEngineSendPointerEvent(engine_, &event, 1);
295 
296   if (event_data.phase == FlutterPointerPhase::kAdd) {
297     pointer_currently_added_ = true;
298   } else if (event_data.phase == FlutterPointerPhase::kRemove) {
299     pointer_currently_added_ = false;
300   }
301 }
302 
MakeCurrent()303 bool Win32FlutterWindow::MakeCurrent() {
304   return surface_manager->MakeCurrent(render_surface);
305 }
306 
ClearContext()307 bool Win32FlutterWindow::ClearContext() {
308   return surface_manager->MakeCurrent(nullptr);
309 }
310 
SwapBuffers()311 bool Win32FlutterWindow::SwapBuffers() {
312   return surface_manager->SwapBuffers(render_surface);
313 }
314 
CreateRenderSurface()315 void Win32FlutterWindow::CreateRenderSurface() {
316   if (surface_manager && render_surface == EGL_NO_SURFACE) {
317     render_surface = surface_manager->CreateSurface(GetWindowHandle());
318   }
319 }
320 
DestroyRenderSurface()321 void Win32FlutterWindow::DestroyRenderSurface() {
322   if (surface_manager) {
323     surface_manager->DestroySurface(render_surface);
324   }
325   render_surface = EGL_NO_SURFACE;
326 }
327 
328 }  // namespace flutter