Flutter Windows Embedder
flutter_windows.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 
6 
7 #include <io.h>
8 
9 #include <algorithm>
10 #include <chrono>
11 #include <cstdlib>
12 #include <filesystem>
13 #include <memory>
14 #include <vector>
15 
19 #include "flutter/shell/platform/embedder/embedder.h"
28 
29 static_assert(FLUTTER_ENGINE_VERSION == 1, "");
30 
31 // Returns the engine corresponding to the given opaque API handle.
34  return reinterpret_cast<flutter::FlutterWindowsEngine*>(ref);
35 }
36 
37 // Returns the opaque API handle for the given engine instance.
40  return reinterpret_cast<FlutterDesktopEngineRef>(engine);
41 }
42 
45  return reinterpret_cast<flutter::FlutterWindowsViewController*>(ref);
46 }
47 
49  flutter::FlutterWindowsViewController* view_controller) {
50  return reinterpret_cast<FlutterDesktopViewControllerRef>(view_controller);
51 }
52 
53 // Returns the view corresponding to the given opaque API handle.
55  return reinterpret_cast<flutter::FlutterWindowsView*>(ref);
56 }
57 
58 // Returns the opaque API handle for the given view instance.
60  return reinterpret_cast<FlutterDesktopViewRef>(view);
61 }
62 
63 // Returns the texture registrar corresponding to the given opaque API handle.
66  return reinterpret_cast<flutter::FlutterWindowsTextureRegistrar*>(ref);
67 }
68 
69 // Returns the opaque API handle for the given texture registrar instance.
72  return reinterpret_cast<FlutterDesktopTextureRegistrarRef>(registrar);
73 }
74 
75 // Creates a view controller that might own the engine.
76 //
77 // If `owns_engine` is true, then the returned `FlutterDesktopViewControllerRef`
78 // owns `engine_ref` and will deallocate `engine_ref` upon its own destruction.
80  FlutterDesktopEngineRef engine_ref,
81  int width,
82  int height,
83  bool owns_engine) {
84  flutter::FlutterWindowsEngine* engine_ptr = EngineFromHandle(engine_ref);
85  std::unique_ptr<flutter::WindowBindingHandler> window_wrapper =
86  std::make_unique<flutter::FlutterWindow>(
87  width, height, engine_ptr->display_manager(),
88  engine_ptr->windows_proc_table());
89 
90  std::unique_ptr<flutter::FlutterWindowsEngine> engine;
91  if (owns_engine) {
92  engine = std::unique_ptr<flutter::FlutterWindowsEngine>(engine_ptr);
93  }
94 
95  std::unique_ptr<flutter::FlutterWindowsView> view = engine_ptr->CreateView(
96  std::move(window_wrapper), false, flutter::BoxConstraints());
97  if (!view) {
98  return nullptr;
99  }
100 
101  auto controller = std::make_unique<flutter::FlutterWindowsViewController>(
102  std::move(engine), std::move(view));
103 
104  // Launch the engine if it is not running already.
105  if (!controller->engine()->running()) {
106  if (!controller->engine()->Run()) {
107  return nullptr;
108  }
109  }
110 
111  // Must happen after engine is running.
112  controller->view()->SendInitialBounds();
113 
114  // The Windows embedder listens to accessibility updates using the
115  // view's HWND. The embedder's accessibility features may be stale if
116  // the app was in headless mode.
117  controller->engine()->UpdateAccessibilityFeatures();
118 
119  return HandleForViewController(controller.release());
120 }
121 
123  int width,
124  int height,
125  FlutterDesktopEngineRef engine) {
126  return CreateViewController(engine, width, height, /*owns_engine=*/true);
127 }
128 
131  const FlutterDesktopViewControllerProperties* properties) {
132  return CreateViewController(engine, properties->width, properties->height,
133  /*owns_engine=*/false);
134 }
135 
137  auto controller = ViewControllerFromHandle(ref);
138  controller->Destroy();
139  delete controller;
140 }
141 
144  auto controller = ViewControllerFromHandle(ref);
145  return static_cast<FlutterDesktopViewId>(controller->view()->view_id());
146 }
147 
150  auto controller = ViewControllerFromHandle(ref);
151  return HandleForEngine(controller->engine());
152 }
153 
156  auto controller = ViewControllerFromHandle(ref);
157  return HandleForView(controller->view());
158 }
159 
162  auto controller = ViewControllerFromHandle(ref);
163  controller->view()->ForceRedraw();
164 }
165 
168  HWND hwnd,
169  UINT message,
170  WPARAM wparam,
171  LPARAM lparam,
172  LRESULT* result) {
173  auto controller = ViewControllerFromHandle(ref);
174  std::optional<LRESULT> delegate_result =
175  controller->engine()
176  ->window_proc_delegate_manager()
177  ->OnTopLevelWindowProc(hwnd, message, wparam, lparam);
178  if (delegate_result) {
179  *result = *delegate_result;
180  }
181  return delegate_result.has_value();
182 }
183 
185  const FlutterDesktopEngineProperties* engine_properties) {
186  flutter::FlutterProjectBundle project(*engine_properties);
187  auto engine = std::make_unique<flutter::FlutterWindowsEngine>(project);
188  return HandleForEngine(engine.release());
189 }
190 
192  flutter::FlutterWindowsEngine* engine = EngineFromHandle(engine_ref);
193  bool result = true;
194  if (engine->running()) {
195  result = engine->Stop();
196  }
197  delete engine;
198  return result;
199 }
200 
202 FlutterDesktopEngineForId(int64_t engine_id) {
203  return HandleForEngine(
205 }
206 
208  const char* entry_point) {
209  std::string_view entry_point_view{""};
210  if (entry_point != nullptr) {
211  entry_point_view = entry_point;
212  }
213 
214  return EngineFromHandle(engine)->Run(entry_point_view);
215 }
216 
218  return std::chrono::nanoseconds::max().count();
219 }
220 
223 }
224 
227  const char* plugin_name) {
228  // Currently, one registrar acts as the registrar for all plugins, so the
229  // name is ignored. It is part of the API to reduce churn in the future when
230  // aligning more closely with the Flutter registrar system.
231 
232  return EngineFromHandle(engine)->GetRegistrar();
233 }
234 
236  FlutterDesktopEngineRef engine) {
237  return EngineFromHandle(engine)->messenger();
238 }
239 
241  FlutterDesktopEngineRef engine) {
243  EngineFromHandle(engine)->texture_registrar());
244 }
245 
248  void* user_data) {
250  [callback, user_data]() { callback(user_data); });
251 }
252 
255 }
256 
259  VoidCallback on_cancel,
260  void* user_data) {
261  FML_DCHECK(callback) << "Callback must not be null";
262  struct Context {
264  VoidCallback on_cancel;
265  void* user_data;
266  bool invoked = false;
267 
268  ~Context() {
269  if (!invoked && on_cancel) {
270  on_cancel(user_data);
271  }
272  }
273  };
274 
275  auto context =
276  std::make_shared<Context>(Context{callback, on_cancel, user_data});
277  EngineFromHandle(engine)->task_runner()->PostTask([context]() {
278  context->invoked = true;
279  context->callback(context->user_data);
280  });
281 }
282 
284  return ViewFromHandle(view)->GetWindowHandle();
285 }
286 
288  auto engine = ViewFromHandle(view)->GetEngine();
289  IDXGIAdapter* adapter;
291  &adapter)) {
292  return nullptr;
293  }
294  return adapter;
295 }
296 
298  IDXGIAdapter** adapter_out) {
299  auto egl_manager = EngineFromHandle(engine)->egl_manager();
300  if (egl_manager) {
301  Microsoft::WRL::ComPtr<ID3D11Device> d3d_device;
302  Microsoft::WRL::ComPtr<IDXGIDevice> dxgi_device;
303  if (egl_manager->GetDevice(d3d_device.GetAddressOf()) &&
304  SUCCEEDED(d3d_device.As(&dxgi_device))) {
305  if (SUCCEEDED(dxgi_device->GetAdapter(adapter_out))) {
306  return true;
307  }
308  }
309  }
310  return false;
311 }
312 
315  HWND hwnd,
316  UINT message,
317  WPARAM wparam,
318  LPARAM lparam,
319  LRESULT* result) {
320  std::optional<LRESULT> lresult =
322  wparam, lparam);
323  if (result && lresult.has_value()) {
324  *result = lresult.value();
325  }
326  return lresult.has_value();
327 }
328 
331  const char* view_type_name,
332  FlutterPlatformViewTypeEntry view_type) {
333  // TODO(schectman): forward to platform view manager.
334  // https://github.com/flutter/flutter/issues/143375
335 }
336 
339  return HandleForView(registrar->engine->view(flutter::kImplicitViewId));
340 }
341 
344  FlutterDesktopViewId view_id) {
345  return HandleForView(registrar->engine->view(view_id));
346 }
347 
351  void* user_data) {
354 }
355 
361 }
362 
365  IDXGIAdapter** adapter_out) {
367  HandleForEngine(registrar->engine), adapter_out);
368 }
369 
371  return flutter::GetDpiForHWND(hwnd);
372 }
373 
374 UINT FlutterDesktopGetDpiForMonitor(HMONITOR monitor) {
375  return flutter::GetDpiForMonitor(monitor);
376 }
377 
379  FILE* unused;
380  if (freopen_s(&unused, "CONOUT$", "w", stdout)) {
381  _dup2(_fileno(stdout), 1);
382  }
383  if (freopen_s(&unused, "CONOUT$", "w", stderr)) {
384  _dup2(_fileno(stdout), 2);
385  }
386  std::ios::sync_with_stdio();
387 }
388 
389 // Implementations of common/ API methods.
390 
393  return registrar->engine->messenger();
394 }
395 
399  registrar->engine->AddPluginRegistrarDestructionCallback(callback, registrar);
400 }
401 
403  const char* channel,
404  const uint8_t* message,
405  const size_t message_size,
406  const FlutterDesktopBinaryReply reply,
407  void* user_data) {
408  FML_DCHECK(FlutterDesktopMessengerIsAvailable(messenger))
409  << "Messenger must reference a running engine to send a message";
410 
412  ->GetEngine()
413  ->SendPlatformMessage(channel, message, message_size, reply, user_data);
414 }
415 
417  const char* channel,
418  const uint8_t* message,
419  const size_t message_size) {
420  return FlutterDesktopMessengerSendWithReply(messenger, channel, message,
421  message_size, nullptr, nullptr);
422 }
423 
425  FlutterDesktopMessengerRef messenger,
427  const uint8_t* data,
428  size_t data_length) {
429  FML_DCHECK(FlutterDesktopMessengerIsAvailable(messenger))
430  << "Messenger must reference a running engine to send a response";
431 
433  ->GetEngine()
434  ->SendPlatformMessageResponse(handle, data, data_length);
435 }
436 
438  const char* channel,
440  void* user_data) {
441  FML_DCHECK(FlutterDesktopMessengerIsAvailable(messenger))
442  << "Messenger must reference a running engine to set a callback";
443 
445  ->GetEngine()
448 }
449 
451  FlutterDesktopMessengerRef messenger) {
453  ->AddRef()
454  ->ToRef();
455 }
456 
459 }
460 
463  nullptr;
464 }
465 
467  FlutterDesktopMessengerRef messenger) {
469  return messenger;
470 }
471 
474 }
475 
478  return HandleForTextureRegistrar(registrar->engine->texture_registrar());
479 }
480 
482  FlutterDesktopTextureRegistrarRef texture_registrar,
483  const FlutterDesktopTextureInfo* texture_info) {
484  return TextureRegistrarFromHandle(texture_registrar)
485  ->RegisterTexture(texture_info);
486 }
487 
489  FlutterDesktopTextureRegistrarRef texture_registrar,
490  int64_t texture_id,
491  void (*callback)(void* user_data),
492  void* user_data) {
493  auto registrar = TextureRegistrarFromHandle(texture_registrar);
494  if (callback) {
495  registrar->UnregisterTexture(
497  return;
498  }
499  registrar->UnregisterTexture(texture_id);
500 }
501 
503  FlutterDesktopTextureRegistrarRef texture_registrar,
504  int64_t texture_id) {
505  return TextureRegistrarFromHandle(texture_registrar)
507 }
flutter::FlutterWindowsEngine * GetEngine() const
Getter for the engine field.
FlutterDesktopMessengerRef ToRef()
Convert to FlutterDesktopMessengerRef.
static FlutterDesktopMessenger * FromRef(FlutterDesktopMessengerRef ref)
Convert from FlutterDesktopMessengerRef.
FlutterWindowsTextureRegistrar * texture_registrar()
std::shared_ptr< WindowsProcTable > windows_proc_table()
FlutterDesktopMessengerRef messenger()
WindowProcDelegateManager * window_proc_delegate_manager()
FlutterWindowsView * view(FlutterViewId view_id) const
std::shared_ptr< DisplayManagerWin32 > display_manager()
bool SendPlatformMessage(const char *channel, const uint8_t *message, const size_t message_size, const FlutterDesktopBinaryReply reply, void *user_data)
std::optional< LRESULT > ProcessExternalWindowMessage(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
void AddPluginRegistrarDestructionCallback(FlutterDesktopOnPluginRegistrarDestroyed callback, FlutterDesktopPluginRegistrarRef registrar)
void SendPlatformMessageResponse(const FlutterDesktopMessageResponseHandle *handle, const uint8_t *data, size_t data_length)
static FlutterWindowsEngine * GetEngineForId(int64_t engine_id)
std::unique_ptr< FlutterWindowsView > CreateView(std::unique_ptr< WindowBindingHandler > window, bool is_sized_to_content, const BoxConstraints &box_constraints, FlutterWindowsViewSizingDelegate *sizing_delegate=nullptr)
IncomingMessageDispatcher * message_dispatcher()
void SetNextFrameCallback(fml::closure callback)
FlutterDesktopPluginRegistrarRef GetRegistrar()
int64_t RegisterTexture(const FlutterDesktopTextureInfo *texture_info)
Controls a view that displays Flutter content.
FlutterWindowsEngine * GetEngine() const
virtual HWND GetWindowHandle() const
void SetMessageCallback(const std::string &channel, FlutterDesktopMessageCallback callback, void *user_data)
virtual bool RunsTasksOnCurrentThread() const
Definition: task_runner.cc:117
void PostTask(TaskClosure task)
Definition: task_runner.cc:89
void UnregisterTopLevelWindowProcDelegate(FlutterDesktopWindowProcCallback callback)
void RegisterTopLevelWindowProcDelegate(FlutterDesktopWindowProcCallback callback, void *user_data)
uint32_t texture_id
#define FLUTTER_EXPORT
void(* FlutterDesktopBinaryReply)(const uint8_t *data, size_t data_size, void *user_data)
struct FlutterDesktopMessenger * FlutterDesktopMessengerRef
void(* FlutterDesktopMessageCallback)(FlutterDesktopMessengerRef, const FlutterDesktopMessage *, void *)
struct _FlutterPlatformMessageResponseHandle FlutterDesktopMessageResponseHandle
void(* FlutterDesktopOnPluginRegistrarDestroyed)(FlutterDesktopPluginRegistrarRef)
struct FlutterDesktopTextureRegistrar * FlutterDesktopTextureRegistrarRef
static flutter::FlutterWindowsTextureRegistrar * TextureRegistrarFromHandle(FlutterDesktopTextureRegistrarRef ref)
void FlutterDesktopMessengerSetCallback(FlutterDesktopMessengerRef messenger, const char *channel, FlutterDesktopMessageCallback callback, void *user_data)
UINT FlutterDesktopGetDpiForHWND(HWND hwnd)
void FlutterDesktopViewControllerForceRedraw(FlutterDesktopViewControllerRef ref)
static FlutterDesktopTextureRegistrarRef HandleForTextureRegistrar(flutter::FlutterWindowsTextureRegistrar *registrar)
bool FlutterDesktopEngineGetGraphicsAdapter(FlutterDesktopEngineRef engine, IDXGIAdapter **adapter_out)
FlutterDesktopEngineRef FlutterDesktopEngineCreate(const FlutterDesktopEngineProperties *engine_properties)
void FlutterDesktopEngineReloadSystemFonts(FlutterDesktopEngineRef engine)
bool FlutterDesktopEngineProcessExternalWindowMessage(FlutterDesktopEngineRef engine, HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam, LRESULT *result)
bool FlutterDesktopPluginRegistrarGetGraphicsAdapter(FlutterDesktopPluginRegistrarRef registrar, IDXGIAdapter **adapter_out)
static flutter::FlutterWindowsView * ViewFromHandle(FlutterDesktopViewRef ref)
void FlutterDesktopResyncOutputStreams()
void FlutterDesktopEngineRegisterPlatformViewType(FlutterDesktopEngineRef engine, const char *view_type_name, FlutterPlatformViewTypeEntry view_type)
static FlutterDesktopViewRef HandleForView(flutter::FlutterWindowsView *view)
static FlutterDesktopViewControllerRef CreateViewController(FlutterDesktopEngineRef engine_ref, int width, int height, bool owns_engine)
FLUTTER_EXPORT FlutterDesktopEngineRef FlutterDesktopEngineForId(int64_t engine_id)
void FlutterDesktopMessengerSendResponse(FlutterDesktopMessengerRef messenger, const FlutterDesktopMessageResponseHandle *handle, const uint8_t *data, size_t data_length)
FlutterDesktopViewRef FlutterDesktopPluginRegistrarGetViewById(FlutterDesktopPluginRegistrarRef registrar, FlutterDesktopViewId view_id)
static FlutterDesktopEngineRef HandleForEngine(flutter::FlutterWindowsEngine *engine)
bool FlutterDesktopMessengerSendWithReply(FlutterDesktopMessengerRef messenger, const char *channel, const uint8_t *message, const size_t message_size, const FlutterDesktopBinaryReply reply, void *user_data)
void FlutterDesktopPluginRegistrarSetDestructionHandler(FlutterDesktopPluginRegistrarRef registrar, FlutterDesktopOnPluginRegistrarDestroyed callback)
FlutterDesktopPluginRegistrarRef FlutterDesktopEngineGetPluginRegistrar(FlutterDesktopEngineRef engine, const char *plugin_name)
static flutter::FlutterWindowsEngine * EngineFromHandle(FlutterDesktopEngineRef ref)
int64_t FlutterDesktopTextureRegistrarRegisterExternalTexture(FlutterDesktopTextureRegistrarRef texture_registrar, const FlutterDesktopTextureInfo *texture_info)
static FlutterDesktopViewControllerRef HandleForViewController(flutter::FlutterWindowsViewController *view_controller)
bool FlutterDesktopTextureRegistrarMarkExternalTextureFrameAvailable(FlutterDesktopTextureRegistrarRef texture_registrar, int64_t texture_id)
bool FlutterDesktopEngineIsPlatformThread(FlutterDesktopEngineRef engine)
FlutterDesktopViewControllerRef FlutterDesktopViewControllerCreate(int width, int height, FlutterDesktopEngineRef engine)
FlutterDesktopMessengerRef FlutterDesktopMessengerLock(FlutterDesktopMessengerRef messenger)
void FlutterDesktopTextureRegistrarUnregisterExternalTexture(FlutterDesktopTextureRegistrarRef texture_registrar, int64_t texture_id, void(*callback)(void *user_data), void *user_data)
bool FlutterDesktopEngineDestroy(FlutterDesktopEngineRef engine_ref)
UINT FlutterDesktopGetDpiForMonitor(HMONITOR monitor)
void FlutterDesktopEnginePostPlatformThreadTask(FlutterDesktopEngineRef engine, VoidCallback callback, VoidCallback on_cancel, void *user_data)
bool FlutterDesktopMessengerIsAvailable(FlutterDesktopMessengerRef messenger)
bool FlutterDesktopMessengerSend(FlutterDesktopMessengerRef messenger, const char *channel, const uint8_t *message, const size_t message_size)
FlutterDesktopTextureRegistrarRef FlutterDesktopEngineGetTextureRegistrar(FlutterDesktopEngineRef engine)
void FlutterDesktopPluginRegistrarUnregisterTopLevelWindowProcDelegate(FlutterDesktopPluginRegistrarRef registrar, FlutterDesktopWindowProcCallback delegate)
IDXGIAdapter * FlutterDesktopViewGetGraphicsAdapter(FlutterDesktopViewRef view)
bool FlutterDesktopViewControllerHandleTopLevelWindowProc(FlutterDesktopViewControllerRef ref, HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam, LRESULT *result)
uint64_t FlutterDesktopEngineProcessMessages(FlutterDesktopEngineRef engine)
void FlutterDesktopMessengerUnlock(FlutterDesktopMessengerRef messenger)
void FlutterDesktopPluginRegistrarRegisterTopLevelWindowProcDelegate(FlutterDesktopPluginRegistrarRef registrar, FlutterDesktopWindowProcCallback delegate, void *user_data)
FlutterDesktopMessengerRef FlutterDesktopEngineGetMessenger(FlutterDesktopEngineRef engine)
FlutterDesktopViewId FlutterDesktopViewControllerGetViewId(FlutterDesktopViewControllerRef ref)
FlutterDesktopEngineRef FlutterDesktopViewControllerGetEngine(FlutterDesktopViewControllerRef ref)
FlutterDesktopTextureRegistrarRef FlutterDesktopRegistrarGetTextureRegistrar(FlutterDesktopPluginRegistrarRef registrar)
FlutterDesktopMessengerRef FlutterDesktopPluginRegistrarGetMessenger(FlutterDesktopPluginRegistrarRef registrar)
void FlutterDesktopEngineSetNextFrameCallback(FlutterDesktopEngineRef engine, VoidCallback callback, void *user_data)
HWND FlutterDesktopViewGetHWND(FlutterDesktopViewRef view)
void FlutterDesktopMessengerRelease(FlutterDesktopMessengerRef messenger)
FlutterDesktopViewRef FlutterDesktopViewControllerGetView(FlutterDesktopViewControllerRef ref)
FlutterDesktopViewRef FlutterDesktopPluginRegistrarGetView(FlutterDesktopPluginRegistrarRef registrar)
FlutterDesktopMessengerRef FlutterDesktopMessengerAddRef(FlutterDesktopMessengerRef messenger)
FlutterDesktopViewControllerRef FlutterDesktopEngineCreateViewController(FlutterDesktopEngineRef engine, const FlutterDesktopViewControllerProperties *properties)
void FlutterDesktopViewControllerDestroy(FlutterDesktopViewControllerRef ref)
static flutter::FlutterWindowsViewController * ViewControllerFromHandle(FlutterDesktopViewControllerRef ref)
bool FlutterDesktopEngineRun(FlutterDesktopEngineRef engine, const char *entry_point)
struct FlutterDesktopViewController * FlutterDesktopViewControllerRef
bool(* FlutterDesktopWindowProcCallback)(HWND, UINT, WPARAM, LPARAM, void *, LRESULT *result)
struct FlutterDesktopEngine * FlutterDesktopEngineRef
int64_t FlutterDesktopViewId
struct FlutterDesktopView * FlutterDesktopViewRef
void(* VoidCallback)(void *)
FlutterDesktopBinaryReply callback
Win32Message message
UINT GetDpiForHWND(HWND hwnd)
Definition: dpi_utils.cc:128
UINT GetDpiForMonitor(HMONITOR monitor)
Definition: dpi_utils.cc:132
constexpr FlutterViewId kImplicitViewId
flutter::FlutterWindowsEngine * engine
Definition: window_state.h:25