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