Flutter Engine
flutter_glfw.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/glfw/public/flutter_glfw.h"
6 
7 #include <GLFW/glfw3.h>
8 
9 #include <algorithm>
10 #include <cassert>
11 #include <chrono>
12 #include <cstdlib>
13 #include <filesystem>
14 #include <iostream>
15 
16 #include "flutter/shell/platform/common/cpp/client_wrapper/include/flutter/plugin_registrar.h"
17 #include "flutter/shell/platform/common/cpp/incoming_message_dispatcher.h"
18 #include "flutter/shell/platform/common/cpp/path_utils.h"
19 #include "flutter/shell/platform/embedder/embedder.h"
20 #include "flutter/shell/platform/glfw/glfw_event_loop.h"
21 #include "flutter/shell/platform/glfw/headless_event_loop.h"
22 #include "flutter/shell/platform/glfw/key_event_handler.h"
23 #include "flutter/shell/platform/glfw/keyboard_hook_handler.h"
24 #include "flutter/shell/platform/glfw/platform_handler.h"
25 #include "flutter/shell/platform/glfw/text_input_plugin.h"
26 
27 // GLFW_TRUE & GLFW_FALSE are introduced since libglfw-3.3,
28 // add definitions here to compile under the old versions.
29 #ifndef GLFW_TRUE
30 #define GLFW_TRUE 1
31 #endif
32 #ifndef GLFW_FALSE
33 #define GLFW_FALSE 0
34 #endif
35 
36 using UniqueGLFWwindowPtr = std::unique_ptr<GLFWwindow, void (*)(GLFWwindow*)>;
37 
38 static_assert(FLUTTER_ENGINE_VERSION == 1, "");
39 
40 const int kFlutterDesktopDontCare = GLFW_DONT_CARE;
41 
42 static constexpr double kDpPerInch = 160.0;
43 
44 // Struct for storing state within an instance of the GLFW Window.
46  // The GLFW window that is bound to this state object.
47  UniqueGLFWwindowPtr window = UniqueGLFWwindowPtr(nullptr, glfwDestroyWindow);
48 
49  // The invisible GLFW window used to upload resources in the background.
51  UniqueGLFWwindowPtr(nullptr, glfwDestroyWindow);
52 
53  // The state associated with the engine.
54  std::unique_ptr<FlutterDesktopEngineState> engine;
55 
56  // The window handle given to API clients.
57  std::unique_ptr<FlutterDesktopWindow> window_wrapper;
58 
59  // Handlers for keyboard events from GLFW.
60  std::vector<std::unique_ptr<flutter::KeyboardHookHandler>>
62 
63  // Whether or not the pointer has been added (or if tracking is enabled,
64  // has been added since it was last removed).
66 
67  // The screen coordinates per inch on the primary monitor. Defaults to a sane
68  // value based on pixel_ratio 1.0.
70 };
71 
72 // Opaque reference for the GLFW window itself. This is separate from the
73 // controller so that it can be provided to plugins without giving them access
74 // to all of the controller-based functionality.
76  // The GLFW window that (indirectly) owns this state object.
77  GLFWwindow* window;
78 
79  // Whether or not to track mouse movements to send kHover events.
80  bool hover_tracking_enabled = true;
81 
82  // The ratio of pixels per screen coordinate for the window.
83  double pixels_per_screen_coordinate = 1.0;
84 
85  // If non-zero, a forced pixel ratio to use instead of one computed based on
86  // screen information.
87  double pixel_ratio_override = 0.0;
88 
89  // Resizing triggers a window refresh, but the resize already updates Flutter.
90  // To avoid double messages, the refresh after each resize is skipped.
91  bool skip_next_window_refresh = false;
92 };
93 
94 // Custom deleter for FlutterEngineAOTData.
98  }
99 };
100 
101 using UniqueAotDataPtr = std::unique_ptr<_FlutterEngineAOTData, AOTDataDeleter>;
102 
103 // Struct for storing state of a Flutter engine instance.
105  // The handle to the Flutter engine instance.
106  FLUTTER_API_SYMBOL(FlutterEngine) flutter_engine;
107 
108  // The event loop for the main thread that allows for delayed task execution.
109  std::unique_ptr<flutter::EventLoop> event_loop;
110 
111  // The plugin messenger handle given to API clients.
112  std::unique_ptr<FlutterDesktopMessenger> messenger;
113 
114  // Message dispatch manager for messages from the Flutter engine.
115  std::unique_ptr<flutter::IncomingMessageDispatcher> message_dispatcher;
116 
117  // The plugin registrar handle given to API clients.
118  std::unique_ptr<FlutterDesktopPluginRegistrar> plugin_registrar;
119 
120  // The plugin registrar managing internal plugins.
121  std::unique_ptr<flutter::PluginRegistrar> internal_plugin_registrar;
122 
123  // Handler for the flutter/platform channel.
124  std::unique_ptr<flutter::PlatformHandler> platform_handler;
125 
126  // The controller associated with this engine instance, if any.
127  // This will always be null for a headless engine.
128  FlutterDesktopWindowControllerState* window_controller = nullptr;
129 
130  // AOT data for this engine instance, if applicable.
131  UniqueAotDataPtr aot_data = nullptr;
132 };
133 
134 // State associated with the plugin registrar.
136  // The engine that backs this registrar.
138 
139  // Callback to be called on registrar destruction.
141 };
142 
143 // State associated with the messenger used to communicate with the engine.
145  // The engine that backs this messenger.
147 };
148 
149 // Retrieves state bag for the window in question from the GLFWWindow.
151  GLFWwindow* window) {
152  return reinterpret_cast<FlutterDesktopWindowControllerState*>(
153  glfwGetWindowUserPointer(window));
154 }
155 
156 // Creates and returns an invisible GLFW window that shares |window|'s resource
157 // context.
159  glfwWindowHint(GLFW_DECORATED, GLFW_FALSE);
160  glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
161 #if defined(__linux__)
162  glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API);
163 #endif
164  GLFWwindow* share_window = glfwCreateWindow(1, 1, "", NULL, window);
165  glfwDefaultWindowHints();
166  return UniqueGLFWwindowPtr(share_window, glfwDestroyWindow);
167 }
168 
169 // Converts a FlutterPlatformMessage to an equivalent FlutterDesktopMessage.
171  const FlutterPlatformMessage& engine_message) {
172  FlutterDesktopMessage message = {};
173  message.struct_size = sizeof(message);
174  message.channel = engine_message.channel;
175  message.message = engine_message.message;
176  message.message_size = engine_message.message_size;
177  message.response_handle = engine_message.response_handle;
178  return message;
179 }
180 
181 // Returns the number of screen coordinates per inch for the main monitor.
182 // If the information is unavailable, returns a default value that assumes
183 // that a screen coordinate is one dp.
185  auto* primary_monitor = glfwGetPrimaryMonitor();
186  if (primary_monitor == nullptr) {
187  return kDpPerInch;
188  }
189  auto* primary_monitor_mode = glfwGetVideoMode(primary_monitor);
190  int primary_monitor_width_mm;
191  glfwGetMonitorPhysicalSize(primary_monitor, &primary_monitor_width_mm,
192  nullptr);
193  if (primary_monitor_width_mm == 0) {
194  return kDpPerInch;
195  }
196  return primary_monitor_mode->width / (primary_monitor_width_mm / 25.4);
197 }
198 
199 // Sends a window metrics update to the Flutter engine using the given
200 // framebuffer size and the current window information in |state|.
202  int width,
203  int height) {
204  double dpi = controller->window_wrapper->pixels_per_screen_coordinate *
206 
207  FlutterWindowMetricsEvent event = {};
208  event.struct_size = sizeof(event);
209  event.width = width;
210  event.height = height;
211  if (controller->window_wrapper->pixel_ratio_override == 0.0) {
212  // The Flutter pixel_ratio is defined as DPI/dp. Limit the ratio to a
213  // minimum of 1 to avoid rendering a smaller UI on standard resolution
214  // monitors.
215  event.pixel_ratio = std::max(dpi / kDpPerInch, 1.0);
216  } else {
217  event.pixel_ratio = controller->window_wrapper->pixel_ratio_override;
218  }
219  FlutterEngineSendWindowMetricsEvent(controller->engine->flutter_engine,
220  &event);
221 }
222 
223 // Populates |task_runner| with a description that uses |engine_state|'s event
224 // loop to run tasks.
226  FlutterTaskRunnerDescription* task_runner,
227  FlutterDesktopEngineState* engine_state) {
228  task_runner->struct_size = sizeof(FlutterTaskRunnerDescription);
229  task_runner->user_data = engine_state;
230  task_runner->runs_task_on_current_thread_callback = [](void* state) -> bool {
231  return reinterpret_cast<FlutterDesktopEngineState*>(state)
232  ->event_loop->RunsTasksOnCurrentThread();
233  };
234  task_runner->post_task_callback =
235  [](FlutterTask task, uint64_t target_time_nanos, void* state) -> void {
236  reinterpret_cast<FlutterDesktopEngineState*>(state)->event_loop->PostTask(
237  task, target_time_nanos);
238  };
239 }
240 
241 // When GLFW calls back to the window with a framebuffer size change, notify
242 // FlutterEngine about the new window metrics.
243 static void GLFWFramebufferSizeCallback(GLFWwindow* window,
244  int width_px,
245  int height_px) {
246  int width;
247  glfwGetWindowSize(window, &width, nullptr);
248  auto* controller = GetWindowController(window);
249  controller->window_wrapper->pixels_per_screen_coordinate =
250  width > 0 ? width_px / width : 1;
251 
252  SendWindowMetrics(controller, width_px, height_px);
253  controller->window_wrapper->skip_next_window_refresh = true;
254 }
255 
256 // Indicates that the window needs to be redrawn.
258  auto* controller = GetWindowController(window);
259  if (controller->window_wrapper->skip_next_window_refresh) {
260  controller->window_wrapper->skip_next_window_refresh = false;
261  return;
262  }
263  // There's no engine API to request a redraw explicitly, so instead send a
264  // window metrics event with the current size to trigger it.
265  int width_px, height_px;
266  glfwGetFramebufferSize(window, &width_px, &height_px);
267  if (width_px > 0 && height_px > 0) {
268  SendWindowMetrics(controller, width_px, height_px);
269  }
270 }
271 
272 // Sends a pointer event to the Flutter engine based on the given data.
273 //
274 // Any coordinate/distance values in |event_data| should be in screen
275 // coordinates; they will be adjusted to pixel values before being sent.
276 static void SendPointerEventWithData(GLFWwindow* window,
277  const FlutterPointerEvent& event_data) {
278  auto* controller = GetWindowController(window);
279  // If sending anything other than an add, and the pointer isn't already added,
280  // synthesize an add to satisfy Flutter's expectations about events.
281  if (!controller->pointer_currently_added &&
282  event_data.phase != FlutterPointerPhase::kAdd) {
283  FlutterPointerEvent event = {};
285  event.x = event_data.x;
286  event.y = event_data.y;
288  }
289  // Don't double-add (e.g., if events are delivered out of order, so an add has
290  // already been synthesized).
291  if (controller->pointer_currently_added &&
292  event_data.phase == FlutterPointerPhase::kAdd) {
293  return;
294  }
295 
296  FlutterPointerEvent event = event_data;
297  // Set metadata that's always the same regardless of the event.
298  event.struct_size = sizeof(event);
299  event.timestamp =
300  std::chrono::duration_cast<std::chrono::microseconds>(
301  std::chrono::high_resolution_clock::now().time_since_epoch())
302  .count();
303  // Convert all screen coordinates to pixel coordinates.
304  double pixels_per_coordinate =
305  controller->window_wrapper->pixels_per_screen_coordinate;
306  event.x *= pixels_per_coordinate;
307  event.y *= pixels_per_coordinate;
308  event.scroll_delta_x *= pixels_per_coordinate;
309  event.scroll_delta_y *= pixels_per_coordinate;
310 
311  FlutterEngineSendPointerEvent(controller->engine->flutter_engine, &event, 1);
312 
313  if (event_data.phase == FlutterPointerPhase::kAdd) {
314  controller->pointer_currently_added = true;
315  } else if (event_data.phase == FlutterPointerPhase::kRemove) {
316  controller->pointer_currently_added = false;
317  }
318 }
319 
320 // Updates |event_data| with the current location of the mouse cursor.
322  GLFWwindow* window,
323  FlutterPointerEvent* event_data) {
324  glfwGetCursorPos(window, &event_data->x, &event_data->y);
325 }
326 
327 // Set's |event_data|'s phase to either kMove or kHover depending on the current
328 // primary mouse button state.
330  GLFWwindow* window,
331  FlutterPointerEvent* event_data) {
332  event_data->phase =
333  glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS
336 }
337 
338 // Reports the mouse entering or leaving the Flutter view.
339 static void GLFWCursorEnterCallback(GLFWwindow* window, int entered) {
340  FlutterPointerEvent event = {};
341  event.phase =
345 }
346 
347 // Reports mouse movement to the Flutter engine.
348 static void GLFWCursorPositionCallback(GLFWwindow* window, double x, double y) {
349  FlutterPointerEvent event = {};
350  event.x = x;
351  event.y = y;
354 }
355 
356 // Reports mouse button press to the Flutter engine.
357 static void GLFWMouseButtonCallback(GLFWwindow* window,
358  int key,
359  int action,
360  int mods) {
361  // Flutter currently doesn't understand other buttons, so ignore anything
362  // other than left.
363  if (key != GLFW_MOUSE_BUTTON_LEFT) {
364  return;
365  }
366 
367  FlutterPointerEvent event = {};
368  event.phase = (action == GLFW_PRESS) ? FlutterPointerPhase::kDown
372 
373  // If mouse tracking isn't already enabled, turn it on for the duration of
374  // the drag to generate kMove events.
375  bool hover_enabled =
376  GetWindowController(window)->window_wrapper->hover_tracking_enabled;
377  if (!hover_enabled) {
378  glfwSetCursorPosCallback(
379  window, (action == GLFW_PRESS) ? GLFWCursorPositionCallback : nullptr);
380  }
381  // Disable enter/exit events while the mouse button is down; GLFW will send
382  // an exit event when the mouse button is released, and the pointer should
383  // stay valid until then.
384  if (hover_enabled) {
385  glfwSetCursorEnterCallback(
386  window, (action == GLFW_PRESS) ? nullptr : GLFWCursorEnterCallback);
387  }
388 }
389 
390 // Reports scroll wheel events to the Flutter engine.
391 static void GLFWScrollCallback(GLFWwindow* window,
392  double delta_x,
393  double delta_y) {
394  FlutterPointerEvent event = {};
398  // TODO: See if this can be queried from the OS; this value is chosen
399  // arbitrarily to get something that feels reasonable.
400  const int kScrollOffsetMultiplier = 20;
401  event.scroll_delta_x = delta_x * kScrollOffsetMultiplier;
402  event.scroll_delta_y = -delta_y * kScrollOffsetMultiplier;
404 }
405 
406 // Passes character input events to registered handlers.
407 static void GLFWCharCallback(GLFWwindow* window, unsigned int code_point) {
408  for (const auto& handler :
410  handler->CharHook(window, code_point);
411  }
412 }
413 
414 // Passes raw key events to registered handlers.
415 static void GLFWKeyCallback(GLFWwindow* window,
416  int key,
417  int scancode,
418  int action,
419  int mods) {
420  for (const auto& handler :
422  handler->KeyboardHook(window, key, scancode, action, mods);
423  }
424 }
425 
426 // Enables/disables the callbacks related to mouse tracking.
427 static void SetHoverCallbacksEnabled(GLFWwindow* window, bool enabled) {
428  glfwSetCursorEnterCallback(window,
429  enabled ? GLFWCursorEnterCallback : nullptr);
430  glfwSetCursorPosCallback(window,
431  enabled ? GLFWCursorPositionCallback : nullptr);
432 }
433 
434 // Flushes event queue and then assigns default window callbacks.
435 static void GLFWAssignEventCallbacks(GLFWwindow* window) {
436  glfwPollEvents();
437  glfwSetKeyCallback(window, GLFWKeyCallback);
438  glfwSetCharCallback(window, GLFWCharCallback);
439  glfwSetMouseButtonCallback(window, GLFWMouseButtonCallback);
440  glfwSetScrollCallback(window, GLFWScrollCallback);
441  if (GetWindowController(window)->window_wrapper->hover_tracking_enabled) {
442  SetHoverCallbacksEnabled(window, true);
443  }
444 }
445 
446 // Clears default window events.
447 static void GLFWClearEventCallbacks(GLFWwindow* window) {
448  glfwSetKeyCallback(window, nullptr);
449  glfwSetCharCallback(window, nullptr);
450  glfwSetMouseButtonCallback(window, nullptr);
451  glfwSetScrollCallback(window, nullptr);
452  SetHoverCallbacksEnabled(window, false);
453 }
454 
455 // The Flutter Engine calls out to this function when new platform messages are
456 // available
458  const FlutterPlatformMessage* engine_message,
459  void* user_data) {
460  if (engine_message->struct_size != sizeof(FlutterPlatformMessage)) {
461  std::cerr << "Invalid message size received. Expected: "
462  << sizeof(FlutterPlatformMessage) << " but received "
463  << engine_message->struct_size << std::endl;
464  return;
465  }
466 
467  FlutterDesktopEngineState* engine_state =
468  static_cast<FlutterDesktopEngineState*>(user_data);
469  GLFWwindow* window = engine_state->window_controller == nullptr
470  ? nullptr
471  : engine_state->window_controller->window.get();
472 
473  auto message = ConvertToDesktopMessage(*engine_message);
474  engine_state->message_dispatcher->HandleMessage(
475  message,
476  [window] {
477  if (window) {
478  GLFWClearEventCallbacks(window);
479  }
480  },
481  [window] {
482  if (window) {
483  GLFWAssignEventCallbacks(window);
484  }
485  });
486 }
487 
489  FlutterDesktopEngineState* engine_state =
490  static_cast<FlutterDesktopEngineState*>(user_data);
491  FlutterDesktopWindowControllerState* window_controller =
492  engine_state->window_controller;
493  if (!window_controller) {
494  return false;
495  }
496  glfwMakeContextCurrent(window_controller->window.get());
497  return true;
498 }
499 
501  FlutterDesktopEngineState* engine_state =
502  static_cast<FlutterDesktopEngineState*>(user_data);
503  FlutterDesktopWindowControllerState* window_controller =
504  engine_state->window_controller;
505  if (!window_controller) {
506  return false;
507  }
508  glfwMakeContextCurrent(window_controller->resource_window.get());
509  return true;
510 }
511 
512 static bool EngineClearContext(void* user_data) {
513  FlutterDesktopEngineState* engine_state =
514  static_cast<FlutterDesktopEngineState*>(user_data);
515  FlutterDesktopWindowControllerState* window_controller =
516  engine_state->window_controller;
517  if (!window_controller) {
518  return false;
519  }
520  glfwMakeContextCurrent(nullptr);
521  return true;
522 }
523 
524 static bool EnginePresent(void* user_data) {
525  FlutterDesktopEngineState* engine_state =
526  static_cast<FlutterDesktopEngineState*>(user_data);
527  FlutterDesktopWindowControllerState* window_controller =
528  engine_state->window_controller;
529  if (!window_controller) {
530  return false;
531  }
532  glfwSwapBuffers(window_controller->window.get());
533  return true;
534 }
535 
536 static uint32_t EngineGetActiveFbo(void* user_data) {
537  return 0;
538 }
539 
540 // Resolves the address of the specified OpenGL or OpenGL ES
541 // core or extension function, if it is supported by the current context.
542 static void* EngineProcResolver(void* user_data, const char* name) {
543  return reinterpret_cast<void*>(glfwGetProcAddress(name));
544 }
545 
546 // Clears the GLFW window to Material Blue-Grey.
547 //
548 // This function is primarily to fix an issue when the Flutter Engine is
549 // spinning up, wherein artifacts of existing windows are rendered onto the
550 // canvas for a few moments.
551 //
552 // This function isn't necessary, but makes starting the window much easier on
553 // the eyes.
554 static void GLFWClearCanvas(GLFWwindow* window) {
555  glfwMakeContextCurrent(window);
556  // This color is Material Blue Grey.
557  glClearColor(236.0f / 255.0f, 239.0f / 255.0f, 241.0f / 255.0f, 0.0f);
558  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
559  glFlush();
560  glfwSwapBuffers(window);
561  glfwMakeContextCurrent(nullptr);
562 }
563 
564 static void GLFWErrorCallback(int error_code, const char* description) {
565  std::cerr << "GLFW error " << error_code << ": " << description << std::endl;
566 }
567 
568 // Attempts to load AOT data from the given path, which must be absolute and
569 // non-empty. Logs and returns nullptr on failure.
571  if (aot_data_path.empty()) {
572  std::cerr
573  << "Attempted to load AOT data, but no aot_data_path was provided."
574  << std::endl;
575  return nullptr;
576  }
577  if (!std::filesystem::exists(aot_data_path)) {
578  std::cerr << "Can't load AOT data from " << aot_data_path.u8string()
579  << "; no such file." << std::endl;
580  return nullptr;
581  }
582  std::string path_string = aot_data_path.u8string();
583  FlutterEngineAOTDataSource source = {};
585  source.elf_path = path_string.c_str();
586  FlutterEngineAOTData data = nullptr;
587  auto result = FlutterEngineCreateAOTData(&source, &data);
588  if (result != kSuccess) {
589  std::cerr << "Failed to load AOT data from: " << path_string << std::endl;
590  return nullptr;
591  }
592  return UniqueAotDataPtr(data);
593 }
594 
595 // Starts an instance of the Flutter Engine.
596 //
597 // Configures the engine according to |engine_propreties| and using |event_loop|
598 // to schedule engine tasks.
599 //
600 // Returns true on success, in which case |engine_state|'s 'engine' field will
601 // be updated to point to the started engine.
602 static bool RunFlutterEngine(
603  FlutterDesktopEngineState* engine_state,
604  const FlutterDesktopEngineProperties& engine_properties,
605  std::unique_ptr<flutter::EventLoop> event_loop) {
606  // FlutterProjectArgs is expecting a full argv, so when processing it for
607  // flags the first item is treated as the executable and ignored. Add a dummy
608  // value so that all provided arguments are used.
609  std::vector<const char*> argv = {"placeholder"};
610  if (engine_properties.switches_count > 0) {
611  argv.insert(argv.end(), &engine_properties.switches[0],
612  &engine_properties.switches[engine_properties.switches_count]);
613  }
614 
615  std::filesystem::path assets_path =
616  std::filesystem::u8path(engine_properties.assets_path);
617  std::filesystem::path icu_path =
618  std::filesystem::u8path(engine_properties.icu_data_path);
619  std::filesystem::path aot_library_path =
620  std::filesystem::u8path(engine_properties.aot_library_path);
621  if (assets_path.is_relative() || icu_path.is_relative() ||
622  (!aot_library_path.empty() && aot_library_path.is_relative())) {
623  // Treat relative paths as relative to the directory of this executable.
624  std::filesystem::path executable_location =
626  if (executable_location.empty()) {
627  std::cerr << "Unable to find executable location to resolve paths."
628  << std::endl;
629  return false;
630  }
631  assets_path = std::filesystem::path(executable_location) / assets_path;
632  icu_path = std::filesystem::path(executable_location) / icu_path;
633  if (!aot_library_path.empty()) {
634  aot_library_path =
635  std::filesystem::path(executable_location) / aot_library_path;
636  }
637  }
638  std::string assets_path_string = assets_path.u8string();
639  std::string icu_path_string = icu_path.u8string();
640  std::string lib_path_string = aot_library_path.u8string();
641 
642  // Configure a task runner using the event loop.
643  engine_state->event_loop = std::move(event_loop);
644  FlutterTaskRunnerDescription platform_task_runner = {};
645  ConfigurePlatformTaskRunner(&platform_task_runner, engine_state);
646  FlutterCustomTaskRunners task_runners = {};
647  task_runners.struct_size = sizeof(FlutterCustomTaskRunners);
648  task_runners.platform_task_runner = &platform_task_runner;
649 
650  FlutterRendererConfig config = {};
651  config.type = kOpenGL;
652  config.open_gl.struct_size = sizeof(config.open_gl);
655  config.open_gl.present = EnginePresent;
658  // Don't provide a resolver in headless mode, since headless mode should
659  // work even if GLFW initialization failed.
660  if (engine_state->window_controller != nullptr) {
662  }
664  args.struct_size = sizeof(FlutterProjectArgs);
665  args.assets_path = assets_path_string.c_str();
666  args.icu_data_path = icu_path_string.c_str();
667  args.command_line_argc = static_cast<int>(argv.size());
668  args.command_line_argv = &argv[0];
670  args.custom_task_runners = &task_runners;
671 
673  engine_state->aot_data = LoadAotData(lib_path_string);
674  if (!engine_state->aot_data) {
675  std::cerr << "Unable to start engine without AOT data." << std::endl;
676  return false;
677  }
678  args.aot_data = engine_state->aot_data.get();
679  }
680 
682  auto result = FlutterEngineRun(FLUTTER_ENGINE_VERSION, &config, &args,
683  engine_state, &engine);
684  if (result != kSuccess || engine == nullptr) {
685  std::cerr << "Failed to start Flutter engine: error " << result
686  << std::endl;
687  return false;
688  }
689  engine_state->flutter_engine = engine;
690  return true;
691 }
692 
693 // Populates |state|'s helper object fields that are common to normal and
694 // headless mode.
695 //
696 // Window is optional; if present it will be provided to the created
697 // PlatformHandler.
699  GLFWwindow* window) {
700  // Messaging.
701  state->messenger = std::make_unique<FlutterDesktopMessenger>();
702  state->messenger->engine = state;
703  state->message_dispatcher =
704  std::make_unique<flutter::IncomingMessageDispatcher>(
705  state->messenger.get());
706 
707  // Plugins.
708  state->plugin_registrar = std::make_unique<FlutterDesktopPluginRegistrar>();
709  state->plugin_registrar->engine = state;
711  std::make_unique<flutter::PluginRegistrar>(state->plugin_registrar.get());
712 
713  // System channel handler.
714  state->platform_handler = std::make_unique<flutter::PlatformHandler>(
715  state->internal_plugin_registrar->messenger(), window);
716 }
717 
719  // Before making any GLFW calls, set up a logging error handler.
720  glfwSetErrorCallback(GLFWErrorCallback);
721  return glfwInit();
722 }
723 
725  glfwTerminate();
726 }
727 
729  const FlutterDesktopWindowProperties& window_properties,
730  const FlutterDesktopEngineProperties& engine_properties) {
731  auto state = std::make_unique<FlutterDesktopWindowControllerState>();
732 
733  // Create the window, and set the state as its user data.
734  if (window_properties.prevent_resize) {
735  glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
736  }
737 #if defined(__linux__)
738  glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API);
739 #endif
740  state->window = UniqueGLFWwindowPtr(
741  glfwCreateWindow(window_properties.width, window_properties.height,
742  window_properties.title, NULL, NULL),
743  glfwDestroyWindow);
744  glfwDefaultWindowHints();
745  GLFWwindow* window = state->window.get();
746  if (window == nullptr) {
747  return nullptr;
748  }
749  GLFWClearCanvas(window);
750  glfwSetWindowUserPointer(window, state.get());
751 
752  // Create the share window before starting the engine, since it may call
753  // EngineMakeResourceContextCurrent immediately.
754  state->resource_window = CreateShareWindowForWindow(window);
755 
756  state->engine = std::make_unique<FlutterDesktopEngineState>();
757  state->engine->window_controller = state.get();
758 
759  // Create an event loop for the window. It is not running yet.
760  auto event_loop = std::make_unique<flutter::GLFWEventLoop>(
761  std::this_thread::get_id(), // main GLFW thread
762  [engine_state = state->engine.get()](const auto* task) {
763  if (FlutterEngineRunTask(engine_state->flutter_engine, task) !=
764  kSuccess) {
765  std::cerr << "Could not post an engine task." << std::endl;
766  }
767  });
768 
769  // Start the engine.
770  if (!RunFlutterEngine(state->engine.get(), engine_properties,
771  std::move(event_loop))) {
772  return nullptr;
773  }
774  SetUpCommonEngineState(state->engine.get(), window);
775 
776  state->window_wrapper = std::make_unique<FlutterDesktopWindow>();
777  state->window_wrapper->window = window;
778 
779  // Set up the keyboard handlers
780  auto internal_plugin_messenger =
781  state->engine->internal_plugin_registrar->messenger();
782  state->keyboard_hook_handlers.push_back(
783  std::make_unique<flutter::KeyEventHandler>(internal_plugin_messenger));
784  state->keyboard_hook_handlers.push_back(
785  std::make_unique<flutter::TextInputPlugin>(internal_plugin_messenger));
786 
787  // Trigger an initial size callback to send size information to Flutter.
788  state->monitor_screen_coordinates_per_inch = GetScreenCoordinatesPerInch();
789  int width_px, height_px;
790  glfwGetFramebufferSize(window, &width_px, &height_px);
791  GLFWFramebufferSizeCallback(window, width_px, height_px);
792 
793  // Set up GLFW callbacks for the window.
794  glfwSetFramebufferSizeCallback(window, GLFWFramebufferSizeCallback);
795  glfwSetWindowRefreshCallback(window, GLFWWindowRefreshCallback);
796  GLFWAssignEventCallbacks(window);
797 
798  return state.release();
799 }
800 
803  controller->engine->plugin_registrar.get();
804  if (registrar->destruction_handler) {
805  registrar->destruction_handler(registrar);
806  }
807  FlutterEngineShutdown(controller->engine->flutter_engine);
808  delete controller;
809 }
810 
812  bool enabled) {
813  flutter_window->hover_tracking_enabled = enabled;
814  SetHoverCallbacksEnabled(flutter_window->window, enabled);
815 }
816 
818  const char* title) {
819  GLFWwindow* window = flutter_window->window;
820  glfwSetWindowTitle(window, title);
821 }
822 
824  uint8_t* pixel_data,
825  int width,
826  int height) {
827  GLFWimage image = {width, height, static_cast<unsigned char*>(pixel_data)};
828  glfwSetWindowIcon(flutter_window->window, pixel_data ? 1 : 0, &image);
829 }
830 
832  int* x,
833  int* y,
834  int* width,
835  int* height) {
836  glfwGetWindowPos(flutter_window->window, x, y);
837  glfwGetWindowSize(flutter_window->window, width, height);
838  // The above gives content area size and position; adjust for the window
839  // decoration to give actual window frame.
840  int frame_left, frame_top, frame_right, frame_bottom;
841  glfwGetWindowFrameSize(flutter_window->window, &frame_left, &frame_top,
842  &frame_right, &frame_bottom);
843  if (x) {
844  *x -= frame_left;
845  }
846  if (y) {
847  *y -= frame_top;
848  }
849  if (width) {
850  *width += frame_left + frame_right;
851  }
852  if (height) {
853  *height += frame_top + frame_bottom;
854  }
855 }
856 
858  int x,
859  int y,
860  int width,
861  int height) {
862  // Get the window decoration sizes to adjust, since the GLFW setters take
863  // content position and size.
864  int frame_left, frame_top, frame_right, frame_bottom;
865  glfwGetWindowFrameSize(flutter_window->window, &frame_left, &frame_top,
866  &frame_right, &frame_bottom);
867  glfwSetWindowPos(flutter_window->window, x + frame_left, y + frame_top);
868  glfwSetWindowSize(flutter_window->window, width - frame_left - frame_right,
869  height - frame_top - frame_bottom);
870 }
871 
873  FlutterDesktopWindowRef flutter_window) {
874  return flutter_window->pixels_per_screen_coordinate;
875 }
876 
878  FlutterDesktopWindowRef flutter_window,
879  double pixel_ratio) {
880  flutter_window->pixel_ratio_override = pixel_ratio;
881  // Send a metrics update using the new pixel ratio.
882  int width_px, height_px;
883  glfwGetFramebufferSize(flutter_window->window, &width_px, &height_px);
884  if (width_px > 0 && height_px > 0) {
885  auto* controller = GetWindowController(flutter_window->window);
886  SendWindowMetrics(controller, width_px, height_px);
887  }
888 }
889 
891  FlutterDesktopSize minimum_size,
892  FlutterDesktopSize maximum_size) {
893  glfwSetWindowSizeLimits(flutter_window->window, minimum_size.width,
894  minimum_size.height, maximum_size.width,
895  maximum_size.height);
896 }
897 
900  uint32_t timeout_milliseconds) {
902  timeout_milliseconds);
903  return !glfwWindowShouldClose(controller->window.get());
904 }
905 
908  // Currently, one registrar acts as the registrar for all plugins, so the
909  // name is ignored. It is part of the API to reduce churn in the future when
910  // aligning more closely with the Flutter registrar system.
911  return controller->window_wrapper.get();
912 }
913 
916  return controller->engine.get();
917 }
918 
921  const char* plugin_name) {
922  // Currently, one registrar acts as the registrar for all plugins, so the
923  // name is ignored. It is part of the API to reduce churn in the future when
924  // aligning more closely with the Flutter registrar system.
925  return engine->plugin_registrar.get();
926 }
927 
929  const FlutterDesktopEngineProperties& properties) {
930  auto engine_state = std::make_unique<FlutterDesktopEngineState>();
931 
932  auto event_loop = std::make_unique<flutter::HeadlessEventLoop>(
933  std::this_thread::get_id(),
934  [state = engine_state.get()](const auto* task) {
935  if (FlutterEngineRunTask(state->flutter_engine, task) != kSuccess) {
936  std::cerr << "Could not post an engine task." << std::endl;
937  }
938  });
939 
940  if (!RunFlutterEngine(engine_state.get(), properties,
941  std::move(event_loop))) {
942  return nullptr;
943  }
944  SetUpCommonEngineState(engine_state.get(), nullptr);
945 
946  return engine_state.release();
947 }
948 
951  uint32_t timeout_milliseconds) {
952  std::chrono::nanoseconds wait_duration =
953  timeout_milliseconds == 0
954  ? std::chrono::nanoseconds::max()
955  : std::chrono::milliseconds(timeout_milliseconds);
956  engine->event_loop->WaitForEvents(wait_duration);
957 }
958 
960  auto result = FlutterEngineShutdown(engine->flutter_engine);
961  delete engine;
962  return (result == kSuccess);
963 }
964 
967  const char* channel) {
968  registrar->engine->message_dispatcher->EnableInputBlockingForChannel(channel);
969 }
970 
973  return registrar->engine->messenger.get();
974 }
975 
979  registrar->destruction_handler = callback;
980 }
981 
985  registrar->engine->window_controller;
986  if (!controller) {
987  return nullptr;
988  }
989  return controller->window_wrapper.get();
990 }
991 
993  const char* channel,
994  const uint8_t* message,
995  const size_t message_size,
996  const FlutterDesktopBinaryReply reply,
997  void* user_data) {
998  FlutterPlatformMessageResponseHandle* response_handle = nullptr;
999  if (reply != nullptr && user_data != nullptr) {
1001  messenger->engine->flutter_engine, reply, user_data, &response_handle);
1002  if (result != kSuccess) {
1003  std::cout << "Failed to create response handle\n";
1004  return false;
1005  }
1006  }
1007 
1008  FlutterPlatformMessage platform_message = {
1009  sizeof(FlutterPlatformMessage),
1010  channel,
1011  message,
1012  message_size,
1013  response_handle,
1014  };
1015 
1017  messenger->engine->flutter_engine, &platform_message);
1018 
1019  if (response_handle != nullptr) {
1021  messenger->engine->flutter_engine, response_handle);
1022  }
1023 
1024  return message_result == kSuccess;
1025 }
1026 
1028  const char* channel,
1029  const uint8_t* message,
1030  const size_t message_size) {
1031  return FlutterDesktopMessengerSendWithReply(messenger, channel, message,
1032  message_size, nullptr, nullptr);
1033 }
1034 
1036  FlutterDesktopMessengerRef messenger,
1038  const uint8_t* data,
1039  size_t data_length) {
1040  FlutterEngineSendPlatformMessageResponse(messenger->engine->flutter_engine,
1041  handle, data, data_length);
1042 }
1043 
1045  const char* channel,
1047  void* user_data) {
1048  messenger->engine->message_dispatcher->SetMessageCallback(channel, callback,
1049  user_data);
1050 }
static void * EngineProcResolver(void *user_data, const char *name)
G_BEGIN_DECLS FlValue * args
#define GLFW_FALSE
Definition: flutter_glfw.cc:33
DEF_SWITCHES_START snapshot asset path
Definition: switches.h:32
Definition: embedder.h:479
const char * channel
Definition: embedder.h:567
struct _FlutterEngine * FLUTTER_API_SYMBOL(FlutterEngine)
Definition: embedder.h:220
bool FlutterDesktopInit()
FlutterDesktopWindowControllerRef FlutterDesktopCreateWindow(const FlutterDesktopWindowProperties &window_properties, const FlutterDesktopEngineProperties &engine_properties)
static bool EnginePresent(void *user_data)
bool FlutterDesktopMessengerSend(FlutterDesktopMessengerRef messenger, const char *channel, const uint8_t *message, const size_t message_size)
static void GLFWClearEventCallbacks(GLFWwindow *window)
static void SetEventLocationFromCursorPosition(GLFWwindow *window, FlutterPointerEvent *event_data)
FlutterEngineResult FlutterPlatformMessageReleaseResponseHandle(FLUTTER_API_SYMBOL(FlutterEngine) engine, FlutterPlatformMessageResponseHandle *response)
Collects the handle created using FlutterPlatformMessageCreateResponseHandle.
Definition: embedder.cc:1483
static uint32_t EngineGetActiveFbo(void *user_data)
static bool EngineMakeResourceContextCurrent(void *user_data)
FlutterEngineResult FlutterEngineRunTask(FLUTTER_API_SYMBOL(FlutterEngine) engine, const FlutterTask *task)
Inform the engine to run the specified task. This task has been given to the engine via the FlutterTa...
Definition: embedder.cc:1717
void FlutterDesktopTerminate()
std::unique_ptr< flutter::IncomingMessageDispatcher > message_dispatcher
const char * icu_data_path
Definition: embedder.h:1199
double y
The y coordinate of the pointer event in physical pixels.
Definition: embedder.h:541
std::filesystem::path GetExecutableDirectory()
Definition: path_utils.cc:16
const FlutterPlatformMessageResponseHandle * response_handle
Definition: embedder.h:576
void FlutterDesktopWindowSetIcon(FlutterDesktopWindowRef flutter_window, uint8_t *pixel_data, int width, int height)
std::vector< std::unique_ptr< flutter::KeyboardHookHandler > > keyboard_hook_handlers
Definition: flutter_glfw.cc:61
size_t struct_size
The size of this struct. Must be sizeof(FlutterTaskRunnerDescription).
Definition: embedder.h:722
FlutterEngineResult FlutterEngineSendPlatformMessageResponse(FLUTTER_API_SYMBOL(FlutterEngine) engine, const FlutterPlatformMessageResponseHandle *handle, const uint8_t *data, size_t data_length)
Send a response from the native side to a platform message from the Dart Flutter application.
Definition: embedder.cc:1497
const FlutterCustomTaskRunners * custom_task_runners
Definition: embedder.h:1313
void FlutterDesktopWindowSetFrame(FlutterDesktopWindowRef flutter_window, int x, int y, int width, int height)
static void SetEventPhaseFromCursorButtonState(GLFWwindow *window, FlutterPointerEvent *event_data)
static UniqueGLFWwindowPtr CreateShareWindowForWindow(GLFWwindow *window)
static void SendPointerEventWithData(GLFWwindow *window, const FlutterPointerEvent &event_data)
void FlutterDesktopWindowGetFrame(FlutterDesktopWindowRef flutter_window, int *x, int *y, int *width, int *height)
FlutterDesktopEngineRef FlutterDesktopRunEngine(const FlutterDesktopEngineProperties &properties)
void FlutterDesktopPluginRegistrarEnableInputBlocking(FlutterDesktopPluginRegistrarRef registrar, const char *channel)
FlutterEngineResult FlutterEngineShutdown(FLUTTER_API_SYMBOL(FlutterEngine) engine)
Shuts down a Flutter engine instance. The engine handle is no longer valid for any calls in the embed...
Definition: embedder.cc:1218
std::unique_ptr< FlutterDesktopEngineState > engine
Definition: flutter_glfw.cc:54
void FlutterDesktopMessengerSetCallback(FlutterDesktopMessengerRef messenger, const char *channel, FlutterDesktopMessageCallback callback, void *user_data)
const FlutterDesktopMessageResponseHandle * response_handle
static void GLFWErrorCallback(int error_code, const char *description)
static void GLFWScrollCallback(GLFWwindow *window, double delta_x, double delta_y)
static void GLFWKeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods)
std::unique_ptr< FlutterDesktopMessenger > messenger
FlutterPlatformMessageCallback platform_message_callback
Definition: embedder.h:1222
std::unique_ptr< FlutterDesktopWindow > window_wrapper
Definition: flutter_glfw.cc:57
void FlutterDesktopWindowSetHoverEnabled(FlutterDesktopWindowRef flutter_window, bool enabled)
static double GetScreenCoordinatesPerInch()
static bool EngineMakeContextCurrent(void *user_data)
std::unique_ptr< flutter::PlatformHandler > platform_handler
const char *const * command_line_argv
Definition: embedder.h:1217
static void SetHoverCallbacksEnabled(GLFWwindow *window, bool enabled)
std::unique_ptr< flutter::PluginRegistrar > internal_plugin_registrar
static void SendWindowMetrics(FlutterDesktopWindowControllerState *controller, int width, int height)
static void GLFWAssignEventCallbacks(GLFWwindow *window)
std::unique_ptr< GLFWwindow, void(*)(GLFWwindow *)> UniqueGLFWwindowPtr
Definition: flutter_glfw.cc:36
const int kFlutterDesktopDontCare
Definition: flutter_glfw.cc:40
UniqueGLFWwindowPtr resource_window
Definition: flutter_glfw.cc:50
static void GLFWClearCanvas(GLFWwindow *window)
FlutterDesktopWindowRef FlutterDesktopPluginRegistrarGetWindow(FlutterDesktopPluginRegistrarRef registrar)
G_BEGIN_DECLS FlValue gpointer user_data
static void ConfigurePlatformTaskRunner(FlutterTaskRunnerDescription *task_runner, FlutterDesktopEngineState *engine_state)
#define FLUTTER_ENGINE_VERSION
Definition: embedder.h:63
FlutterRendererType type
Definition: embedder.h:448
FlutterDesktopWindowRef FlutterDesktopGetWindow(FlutterDesktopWindowControllerRef controller)
FlutterEngineResult FlutterEngineRun(size_t version, const FlutterRendererConfig *config, const FlutterProjectArgs *args, void *user_data, FLUTTER_API_SYMBOL(FlutterEngine) *engine_out)
Initialize and run a Flutter engine instance and return a handle to it. This is a convenience method ...
Definition: embedder.cc:718
FlutterEngineResult FlutterEngineCollectAOTData(FlutterEngineAOTData data)
Collects the AOT data.
Definition: embedder.cc:651
const uint8_t * message
Definition: embedder.h:568
size_t struct_size
The size of this struct. Must be sizeof(FlutterPointerEvent).
Definition: embedder.h:532
size_t struct_size
The size of this struct. Must be sizeof(FlutterOpenGLRendererConfig).
Definition: embedder.h:379
std::unique_ptr< FlutterDesktopPluginRegistrar > plugin_registrar
static bool EngineClearContext(void *user_data)
bool FlutterDesktopRunWindowEventLoopWithTimeout(FlutterDesktopWindowControllerRef controller, uint32_t timeout_milliseconds)
FlutterDesktopEngineState * engine
void FlutterDesktopWindowSetPixelRatioOverride(FlutterDesktopWindowRef flutter_window, double pixel_ratio)
SemanticsAction action
static bool RunFlutterEngine(FlutterDesktopEngineState *engine_state, const FlutterDesktopEngineProperties &engine_properties, std::unique_ptr< flutter::EventLoop > event_loop)
The pointer moved while up.
Definition: embedder.h:503
int32_t height
UniqueAotDataPtr aot_data
static void GLFWCharCallback(GLFWwindow *window, unsigned int code_point)
FlutterDesktopEngineRef FlutterDesktopGetEngine(FlutterDesktopWindowControllerRef controller)
static FlutterDesktopWindowControllerState * GetWindowController(GLFWwindow *window)
BoolCallback make_resource_current
Definition: embedder.h:398
void GLFWWindowRefreshCallback(GLFWwindow *window)
static FlutterDesktopMessage ConvertToDesktopMessage(const FlutterPlatformMessage &engine_message)
BoolCallback clear_current
Definition: embedder.h:381
int32_t width
static void GLFWMouseButtonCallback(GLFWwindow *window, int key, int action, int mods)
double pixels_per_screen_coordinate
Definition: flutter_glfw.cc:83
size_t struct_size
The size of this struct. Must be sizeof(FlutterWindowMetricsEvent).
Definition: embedder.h:457
void FlutterDesktopMessengerSendResponse(FlutterDesktopMessengerRef messenger, const FlutterDesktopMessageResponseHandle *handle, const uint8_t *data, size_t data_length)
Definition: embedder.h:496
double x
The x coordinate of the pointer event in physical pixels.
Definition: embedder.h:539
const uint8_t * message
FlutterDesktopWindowControllerState * window_controller
GdkEventButton * event
Definition: fl_view.cc:62
const char * assets_path
Definition: embedder.h:1175
BoolCallback make_current
Definition: embedder.h:380
static void GLFWCursorPositionCallback(GLFWwindow *window, double x, double y)
FlutterOpenGLRendererConfig open_gl
Definition: embedder.h:450
FlutterEngineResult
Definition: embedder.h:65
size_t struct_size
The size of this struct. Must be sizeof(FlutterProjectArgs).
Definition: embedder.h:1171
void operator()(FlutterEngineAOTData aot_data)
Definition: flutter_glfw.cc:96
static void SetUpCommonEngineState(FlutterDesktopEngineState *state, GLFWwindow *window)
static void GLFWFramebufferSizeCallback(GLFWwindow *window, int width_px, int height_px)
void FlutterDesktopWindowSetTitle(FlutterDesktopWindowRef flutter_window, const char *title)
const char * name
Definition: fuchsia.cc:50
UniqueAotDataPtr LoadAotData(std::filesystem::path aot_data_path)
static void GLFWCursorEnterCallback(GLFWwindow *window, int entered)
std::unique_ptr< flutter::EventLoop > event_loop
UIntCallback fbo_callback
Definition: embedder.h:391
void FlutterDesktopRunEngineEventLoopWithTimeout(FlutterDesktopEngineRef engine, uint32_t timeout_milliseconds)
const FlutterTaskRunnerDescription * platform_task_runner
Definition: embedder.h:752
FlutterTaskRunnerPostTaskCallback post_task_callback
Definition: embedder.h:739
void(* FlutterDesktopBinaryReply)(const uint8_t *data, size_t data_size, void *user_data)
void FlutterDesktopDestroyWindow(FlutterDesktopWindowControllerRef controller)
FlutterEngineAOTDataSourceType type
Definition: embedder.h:1126
void(* FlutterDesktopOnPluginRegistrarDestroyed)(FlutterDesktopPluginRegistrarRef)
FlutterEngineResult FlutterEngineSendPointerEvent(FLUTTER_API_SYMBOL(FlutterEngine) engine, const FlutterPointerEvent *pointers, size_t events_count)
Definition: embedder.cc:1323
FlutterEngineAOTData aot_data
Definition: embedder.h:1363
double FlutterDesktopWindowGetScaleFactor(FlutterDesktopWindowRef flutter_window)
void FlutterDesktopWindowSetSizeLimits(FlutterDesktopWindowRef flutter_window, FlutterDesktopSize minimum_size, FlutterDesktopSize maximum_size)
static void EngineOnFlutterPlatformMessage(const FlutterPlatformMessage *engine_message, void *user_data)
ProcResolver gl_proc_resolver
Definition: embedder.h:415
size_t struct_size
The size of this struct. Must be sizeof(FlutterCustomTaskRunners).
Definition: embedder.h:747
size_t struct_size
The size of this struct. Must be sizeof(FlutterPlatformMessage).
Definition: embedder.h:566
FlutterEngineResult FlutterEngineSendWindowMetricsEvent(FLUTTER_API_SYMBOL(FlutterEngine) engine, const FlutterWindowMetricsEvent *flutter_metrics)
Definition: embedder.cc:1229
FlutterPointerPhase phase
Definition: embedder.h:533
void(* FlutterDesktopMessageCallback)(FlutterDesktopMessengerRef, const FlutterDesktopMessage *, void *)
FlutterDesktopEngineState * engine
void FlutterDesktopPluginRegistrarSetDestructionHandler(FlutterDesktopPluginRegistrarRef registrar, FlutterDesktopOnPluginRegistrarDestroyed callback)
FlutterDesktopMessengerRef FlutterDesktopPluginRegistrarGetMessenger(FlutterDesktopPluginRegistrarRef registrar)
bool FlutterEngineRunsAOTCompiledDartCode(void)
Returns if the Flutter engine instance will run AOT compiled Dart code. This call has no threading re...
Definition: embedder.cc:1821
BoolCallback runs_task_on_current_thread_callback
Definition: embedder.h:728
bool FlutterDesktopShutDownEngine(FlutterDesktopEngineRef engine)
int command_line_argc
The command line argument count used to initialize the project.
Definition: embedder.h:1201
const char * elf_path
Absolute path to an ELF library file.
Definition: embedder.h:1129
std::unique_ptr< _FlutterEngineAOTData, AOTDataDeleter > UniqueAotDataPtr
FlutterDesktopPluginRegistrarRef FlutterDesktopGetPluginRegistrar(FlutterDesktopEngineRef engine, const char *plugin_name)
FlutterEngineResult FlutterEngineSendPlatformMessage(FLUTTER_API_SYMBOL(FlutterEngine) engine, const FlutterPlatformMessage *flutter_message)
Definition: embedder.cc:1396
FlutterEngineResult FlutterPlatformMessageCreateResponseHandle(FLUTTER_API_SYMBOL(FlutterEngine) engine, FlutterDataCallback data_callback, void *user_data, FlutterPlatformMessageResponseHandle **response_out)
Creates a platform message response handle that allows the embedder to set a native callback for a re...
Definition: embedder.cc:1448
GLFWwindow * window
Definition: flutter_glfw.cc:77
bool FlutterDesktopMessengerSendWithReply(FlutterDesktopMessengerRef messenger, const char *channel, const uint8_t *message, const size_t message_size, const FlutterDesktopBinaryReply reply, void *user_data)
FlutterDesktopOnPluginRegistrarDestroyed destruction_handler
static constexpr double kDpPerInch
Definition: flutter_glfw.cc:42
FlutterEngineResult FlutterEngineCreateAOTData(const FlutterEngineAOTDataSource *source, FlutterEngineAOTData *data_out)
Creates the necessary data structures to launch a Flutter Dart application in AOT mode...
Definition: embedder.cc:597