Flutter Linux Embedder
fl_engine_test.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 // Included first as it collides with the X11 headers.
6 #include "gtest/gtest.h"
7 
8 #include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h"
13 #include "flutter/shell/platform/linux/testing/mock_renderable.h"
14 
15 // MOCK_ENGINE_PROC is leaky by design
16 // NOLINTBEGIN(clang-analyzer-core.StackAddressEscape)
17 
18 // Checks notifying display updates works.
19 TEST(FlEngineTest, NotifyDisplayUpdate) {
20  g_autoptr(FlDartProject) project = fl_dart_project_new();
21  g_autoptr(FlEngine) engine = fl_engine_new(project);
22 
23  g_autoptr(GError) error = nullptr;
24  EXPECT_TRUE(fl_engine_start(engine, &error));
25  EXPECT_EQ(error, nullptr);
26 
27  bool called = false;
28  fl_engine_get_embedder_api(engine)->NotifyDisplayUpdate = MOCK_ENGINE_PROC(
29  NotifyDisplayUpdate,
30  ([&called](auto engine, FlutterEngineDisplaysUpdateType update_type,
31  const FlutterEngineDisplay* displays, size_t displays_length) {
32  called = true;
33  EXPECT_EQ(update_type, kFlutterEngineDisplaysUpdateTypeStartup);
34  EXPECT_EQ(displays_length, 2u);
35 
36  EXPECT_EQ(displays[0].display_id, 1u);
37  EXPECT_EQ(displays[0].refresh_rate, 60);
38  EXPECT_EQ(displays[0].width, 1024u);
39  EXPECT_EQ(displays[0].height, 768u);
40  EXPECT_EQ(displays[0].device_pixel_ratio, 1.0);
41 
42  EXPECT_EQ(displays[1].display_id, 2u);
43  EXPECT_EQ(displays[1].refresh_rate, 120);
44  EXPECT_EQ(displays[1].width, 3840u);
45  EXPECT_EQ(displays[1].height, 2160u);
46  EXPECT_EQ(displays[1].device_pixel_ratio, 2.0);
47 
48  return kSuccess;
49  }));
50 
51  FlutterEngineDisplay displays[2] = {
52  {
53  .struct_size = sizeof(FlutterEngineDisplay),
54  .display_id = 1,
55  .single_display = false,
56  .refresh_rate = 60.0,
57  .width = 1024,
58  .height = 768,
59  .device_pixel_ratio = 1.0,
60  },
61  {
62  .struct_size = sizeof(FlutterEngineDisplay),
63  .display_id = 2,
64  .single_display = false,
65  .refresh_rate = 120.0,
66  .width = 3840,
67  .height = 2160,
68  .device_pixel_ratio = 2.0,
69  }};
70  fl_engine_notify_display_update(engine, displays, 2);
71 
72  EXPECT_TRUE(called);
73 }
74 
75 // Checks sending window metrics events works.
76 TEST(FlEngineTest, WindowMetrics) {
77  g_autoptr(FlDartProject) project = fl_dart_project_new();
78  g_autoptr(FlEngine) engine = fl_engine_new(project);
79 
80  g_autoptr(GError) error = nullptr;
81  EXPECT_TRUE(fl_engine_start(engine, &error));
82  EXPECT_EQ(error, nullptr);
83 
84  bool called = false;
85  fl_engine_get_embedder_api(engine)->SendWindowMetricsEvent = MOCK_ENGINE_PROC(
86  SendWindowMetricsEvent,
87  ([&called](auto engine, const FlutterWindowMetricsEvent* event) {
88  called = true;
89  EXPECT_EQ(event->display_id, 99u);
90  EXPECT_EQ(event->view_id, 1);
91  EXPECT_EQ(event->width, 800u);
92  EXPECT_EQ(event->height, 600u);
93  EXPECT_TRUE(event->has_constraints);
94  EXPECT_EQ(event->min_width_constraint, 800u);
95  EXPECT_EQ(event->min_height_constraint, 600u);
96  EXPECT_EQ(event->max_width_constraint, 3840u);
97  EXPECT_EQ(event->max_height_constraint, 2160u);
98  EXPECT_EQ(event->pixel_ratio, 2.0);
99 
100  return kSuccess;
101  }));
102 
103  fl_engine_send_window_metrics_event(engine, 99, 1, 800, 600, 3840, 2160, 2.0);
104 
105  EXPECT_TRUE(called);
106 }
107 
108 // Checks sending mouse pointer events works.
109 TEST(FlEngineTest, MousePointer) {
110  g_autoptr(FlDartProject) project = fl_dart_project_new();
111  g_autoptr(FlEngine) engine = fl_engine_new(project);
112 
113  bool called = false;
114  fl_engine_get_embedder_api(engine)->SendPointerEvent = MOCK_ENGINE_PROC(
115  SendPointerEvent,
116  ([&called](auto engine, const FlutterPointerEvent* events,
117  size_t events_count) {
118  called = true;
119  EXPECT_EQ(events_count, static_cast<size_t>(1));
120  EXPECT_EQ(events[0].view_id, 1);
121  EXPECT_EQ(events[0].phase, kDown);
122  EXPECT_EQ(events[0].timestamp, static_cast<size_t>(1234567890));
123  EXPECT_EQ(events[0].x, 800);
124  EXPECT_EQ(events[0].y, 600);
125  EXPECT_EQ(events[0].device, static_cast<int32_t>(0));
126  EXPECT_EQ(events[0].signal_kind, kFlutterPointerSignalKindScroll);
127  EXPECT_EQ(events[0].scroll_delta_x, 1.2);
128  EXPECT_EQ(events[0].scroll_delta_y, -3.4);
129  EXPECT_EQ(events[0].device_kind, kFlutterPointerDeviceKindMouse);
130  EXPECT_EQ(events[0].buttons, kFlutterPointerButtonMouseSecondary);
131 
132  return kSuccess;
133  }));
134 
135  g_autoptr(GError) error = nullptr;
136  EXPECT_TRUE(fl_engine_start(engine, &error));
137  EXPECT_EQ(error, nullptr);
138  fl_engine_send_mouse_pointer_event(engine, 1, kDown, 1234567890, 800, 600,
139  kFlutterPointerDeviceKindMouse, 1.2, -3.4,
140  kFlutterPointerButtonMouseSecondary);
141 
142  EXPECT_TRUE(called);
143 }
144 
145 // Checks sending pan/zoom events works.
146 TEST(FlEngineTest, PointerPanZoom) {
147  g_autoptr(FlDartProject) project = fl_dart_project_new();
148  g_autoptr(FlEngine) engine = fl_engine_new(project);
149 
150  bool called = false;
151  fl_engine_get_embedder_api(engine)->SendPointerEvent = MOCK_ENGINE_PROC(
152  SendPointerEvent,
153  ([&called](auto engine, const FlutterPointerEvent* events,
154  size_t events_count) {
155  called = true;
156  EXPECT_EQ(events_count, static_cast<size_t>(1));
157  EXPECT_EQ(events[0].view_id, 1);
158  EXPECT_EQ(events[0].phase, kPanZoomUpdate);
159  EXPECT_EQ(events[0].timestamp, static_cast<size_t>(1234567890));
160  EXPECT_EQ(events[0].x, 800);
161  EXPECT_EQ(events[0].y, 600);
162  EXPECT_EQ(events[0].device, static_cast<int32_t>(1));
163  EXPECT_EQ(events[0].signal_kind, kFlutterPointerSignalKindNone);
164  EXPECT_EQ(events[0].pan_x, 1.5);
165  EXPECT_EQ(events[0].pan_y, 2.5);
166  EXPECT_EQ(events[0].scale, 3.5);
167  EXPECT_EQ(events[0].rotation, 4.5);
168  EXPECT_EQ(events[0].device_kind, kFlutterPointerDeviceKindTrackpad);
169  EXPECT_EQ(events[0].buttons, 0);
170 
171  return kSuccess;
172  }));
173 
174  g_autoptr(GError) error = nullptr;
175  EXPECT_TRUE(fl_engine_start(engine, &error));
176  EXPECT_EQ(error, nullptr);
177  fl_engine_send_pointer_pan_zoom_event(engine, 1, 1234567890, 800, 600,
178  kPanZoomUpdate, 1.5, 2.5, 3.5, 4.5);
179 
180  EXPECT_TRUE(called);
181 }
182 
183 // Checks dispatching a semantics action works.
184 TEST(FlEngineTest, DispatchSemanticsAction) {
185  g_autoptr(FlDartProject) project = fl_dart_project_new();
186  g_autoptr(FlEngine) engine = fl_engine_new(project);
187 
188  bool called = false;
189  fl_engine_get_embedder_api(engine)->SendSemanticsAction = MOCK_ENGINE_PROC(
190  SendSemanticsAction,
191  ([&called](auto engine, const FlutterSendSemanticsActionInfo* info) {
192  EXPECT_EQ(info->view_id, static_cast<int64_t>(456));
193  EXPECT_EQ(info->node_id, static_cast<uint64_t>(42));
194  EXPECT_EQ(info->action, kFlutterSemanticsActionTap);
195  EXPECT_EQ(info->data_length, static_cast<size_t>(4));
196  EXPECT_EQ(info->data[0], 't');
197  EXPECT_EQ(info->data[1], 'e');
198  EXPECT_EQ(info->data[2], 's');
199  EXPECT_EQ(info->data[3], 't');
200  called = true;
201 
202  return kSuccess;
203  }));
204 
205  g_autoptr(GError) error = nullptr;
206  EXPECT_TRUE(fl_engine_start(engine, &error));
207  EXPECT_EQ(error, nullptr);
208  g_autoptr(GBytes) data = g_bytes_new_static("test", 4);
209  fl_engine_dispatch_semantics_action(engine, 456, 42,
210  kFlutterSemanticsActionTap, data);
211 
212  EXPECT_TRUE(called);
213 }
214 
215 // Checks sending platform messages works.
216 TEST(FlEngineTest, PlatformMessage) {
217  g_autoptr(FlDartProject) project = fl_dart_project_new();
218  g_autoptr(FlEngine) engine = fl_engine_new(project);
219 
220  bool called = false;
221  FlutterEngineSendPlatformMessageFnPtr old_handler =
222  fl_engine_get_embedder_api(engine)->SendPlatformMessage;
223  fl_engine_get_embedder_api(engine)->SendPlatformMessage = MOCK_ENGINE_PROC(
224  SendPlatformMessage,
225  ([&called, old_handler](auto engine,
226  const FlutterPlatformMessage* message) {
227  if (strcmp(message->channel, "test") != 0) {
228  return old_handler(engine, message);
229  }
230 
231  called = true;
232 
233  EXPECT_EQ(message->message_size, static_cast<size_t>(4));
234  EXPECT_EQ(message->message[0], 't');
235  EXPECT_EQ(message->message[1], 'e');
236  EXPECT_EQ(message->message[2], 's');
237  EXPECT_EQ(message->message[3], 't');
238 
239  return kSuccess;
240  }));
241 
242  g_autoptr(GError) error = nullptr;
243  EXPECT_TRUE(fl_engine_start(engine, &error));
244  EXPECT_EQ(error, nullptr);
245  g_autoptr(GBytes) message = g_bytes_new_static("test", 4);
246  fl_engine_send_platform_message(engine, "test", message, nullptr, nullptr,
247  nullptr);
248 
249  EXPECT_TRUE(called);
250 }
251 
252 // Checks sending platform message responses works.
253 TEST(FlEngineTest, PlatformMessageResponse) {
254  g_autoptr(FlDartProject) project = fl_dart_project_new();
255  g_autoptr(FlEngine) engine = fl_engine_new(project);
256 
257  bool called = false;
258  fl_engine_get_embedder_api(engine)->SendPlatformMessageResponse =
259  MOCK_ENGINE_PROC(
260  SendPlatformMessageResponse,
261  ([&called](auto engine,
262  const FlutterPlatformMessageResponseHandle* handle,
263  const uint8_t* data, size_t data_length) {
264  called = true;
265 
266  EXPECT_EQ(
267  handle,
268  reinterpret_cast<const FlutterPlatformMessageResponseHandle*>(
269  42));
270  EXPECT_EQ(data_length, static_cast<size_t>(4));
271  EXPECT_EQ(data[0], 't');
272  EXPECT_EQ(data[1], 'e');
273  EXPECT_EQ(data[2], 's');
274  EXPECT_EQ(data[3], 't');
275 
276  return kSuccess;
277  }));
278 
279  g_autoptr(GError) error = nullptr;
280  EXPECT_TRUE(fl_engine_start(engine, &error));
281  EXPECT_EQ(error, nullptr);
282  g_autoptr(GBytes) response = g_bytes_new_static("test", 4);
284  engine, reinterpret_cast<const FlutterPlatformMessageResponseHandle*>(42),
285  response, &error));
286  EXPECT_EQ(error, nullptr);
287 
288  EXPECT_TRUE(called);
289 }
290 
291 // Checks settings handler sends settings on startup.
292 TEST(FlEngineTest, SettingsHandler) {
293  g_autoptr(FlDartProject) project = fl_dart_project_new();
294  g_autoptr(FlEngine) engine = fl_engine_new(project);
295 
296  bool called = false;
297  fl_engine_get_embedder_api(engine)->SendPlatformMessage = MOCK_ENGINE_PROC(
298  SendPlatformMessage,
299  ([&called](auto engine, const FlutterPlatformMessage* message) {
300  called = true;
301 
302  EXPECT_STREQ(message->channel, "flutter/settings");
303 
304  g_autoptr(FlJsonMessageCodec) codec = fl_json_message_codec_new();
305  g_autoptr(GBytes) data =
306  g_bytes_new(message->message, message->message_size);
307  g_autoptr(GError) error = nullptr;
309  FL_MESSAGE_CODEC(codec), data, &error);
310  EXPECT_NE(settings, nullptr);
311  EXPECT_EQ(error, nullptr);
312 
313  FlValue* text_scale_factor =
314  fl_value_lookup_string(settings, "textScaleFactor");
315  EXPECT_NE(text_scale_factor, nullptr);
316  EXPECT_EQ(fl_value_get_type(text_scale_factor), FL_VALUE_TYPE_FLOAT);
317 
318  FlValue* always_use_24hr_format =
319  fl_value_lookup_string(settings, "alwaysUse24HourFormat");
320  EXPECT_NE(always_use_24hr_format, nullptr);
321  EXPECT_EQ(fl_value_get_type(always_use_24hr_format),
323 
324  FlValue* platform_brightness =
325  fl_value_lookup_string(settings, "platformBrightness");
326  EXPECT_NE(platform_brightness, nullptr);
327  EXPECT_EQ(fl_value_get_type(platform_brightness), FL_VALUE_TYPE_STRING);
328 
329  return kSuccess;
330  }));
331 
332  g_autoptr(GError) error = nullptr;
333  EXPECT_TRUE(fl_engine_start(engine, &error));
334  EXPECT_EQ(error, nullptr);
335 
336  EXPECT_TRUE(called);
337 }
338 
339 void on_pre_engine_restart_cb(FlEngine* engine, gpointer user_data) {
340  int* count = reinterpret_cast<int*>(user_data);
341  *count += 1;
342 }
343 
344 // Checks restarting the engine invokes the correct callback.
345 TEST(FlEngineTest, OnPreEngineRestart) {
346  g_autoptr(FlDartProject) project = fl_dart_project_new();
347  g_autoptr(FlEngine) engine = fl_engine_new(project);
348 
349  OnPreEngineRestartCallback callback;
350  void* callback_user_data;
351 
352  bool called = false;
353  fl_engine_get_embedder_api(engine)->Initialize = MOCK_ENGINE_PROC(
354  Initialize, ([&callback, &callback_user_data, &called](
355  size_t version, const FlutterRendererConfig* config,
356  const FlutterProjectArgs* args, void* user_data,
357  FLUTTER_API_SYMBOL(FlutterEngine) * engine_out) {
358  called = true;
359  callback = args->on_pre_engine_restart_callback;
360  callback_user_data = user_data;
361 
362  return kSuccess;
363  }));
364  fl_engine_get_embedder_api(engine)->RunInitialized =
365  MOCK_ENGINE_PROC(RunInitialized, ([](auto engine) { return kSuccess; }));
366 
367  g_autoptr(GError) error = nullptr;
368  EXPECT_TRUE(fl_engine_start(engine, &error));
369  EXPECT_EQ(error, nullptr);
370 
371  EXPECT_TRUE(called);
372  EXPECT_NE(callback, nullptr);
373 
374  // The following call has no effect but should not crash.
375  callback(callback_user_data);
376 
377  int count = 0;
378 
379  // Set handler so that:
380  //
381  // * When the engine restarts, count += 1;
382  // * When the engine is freed, count += 10.
383  g_signal_connect(engine, "on-pre-engine-restart",
384  G_CALLBACK(on_pre_engine_restart_cb), &count);
385 
386  callback(callback_user_data);
387  EXPECT_EQ(count, 1);
388 }
389 
390 TEST(FlEngineTest, DartEntrypointArgs) {
391  GPtrArray* args_array = g_ptr_array_new();
392  g_ptr_array_add(args_array, const_cast<char*>("arg_one"));
393  g_ptr_array_add(args_array, const_cast<char*>("arg_two"));
394  g_ptr_array_add(args_array, const_cast<char*>("arg_three"));
395  g_ptr_array_add(args_array, nullptr);
396  gchar** args = reinterpret_cast<gchar**>(g_ptr_array_free(args_array, false));
397 
398  g_autoptr(FlDartProject) project = fl_dart_project_new();
400  g_autoptr(FlEngine) engine = fl_engine_new(project);
401 
402  bool called = false;
403  fl_engine_get_embedder_api(engine)->Initialize = MOCK_ENGINE_PROC(
404  Initialize, ([&called, &set_args = args](
405  size_t version, const FlutterRendererConfig* config,
406  const FlutterProjectArgs* args, void* user_data,
407  FLUTTER_API_SYMBOL(FlutterEngine) * engine_out) {
408  called = true;
409  EXPECT_NE(set_args, args->dart_entrypoint_argv);
410  EXPECT_EQ(args->dart_entrypoint_argc, 3);
411 
412  return kSuccess;
413  }));
414  fl_engine_get_embedder_api(engine)->RunInitialized =
415  MOCK_ENGINE_PROC(RunInitialized, ([](auto engine) { return kSuccess; }));
416 
417  g_autoptr(GError) error = nullptr;
418  EXPECT_TRUE(fl_engine_start(engine, &error));
419  EXPECT_EQ(error, nullptr);
420 
421  EXPECT_TRUE(called);
422 }
423 
424 TEST(FlEngineTest, EngineId) {
425  g_autoptr(FlDartProject) project = fl_dart_project_new();
426  g_autoptr(FlEngine) engine = fl_engine_new(project);
427  int64_t engine_id;
428  fl_engine_get_embedder_api(engine)->Initialize = MOCK_ENGINE_PROC(
429  Initialize,
430  ([&engine_id](size_t version, const FlutterRendererConfig* config,
431  const FlutterProjectArgs* args, void* user_data,
432  FLUTTER_API_SYMBOL(FlutterEngine) * engine_out) {
433  engine_id = args->engine_id;
434  return kSuccess;
435  }));
436  fl_engine_get_embedder_api(engine)->RunInitialized =
437  MOCK_ENGINE_PROC(RunInitialized, ([](auto engine) { return kSuccess; }));
438 
439  g_autoptr(GError) error = nullptr;
440  EXPECT_TRUE(fl_engine_start(engine, &error));
441  EXPECT_EQ(error, nullptr);
442  EXPECT_TRUE(engine_id != 0);
443 
444  EXPECT_EQ(fl_engine_for_id(engine_id), engine);
445 }
446 
447 TEST(FlEngineTest, UIIsolateDefaultThreadPolicy) {
448  g_autoptr(FlDartProject) project = fl_dart_project_new();
449  g_autoptr(FlEngine) engine = fl_engine_new(project);
451 
452  bool same_task_runner = false;
453 
454  fl_engine_get_embedder_api(engine)->Initialize = MOCK_ENGINE_PROC(
455  Initialize,
456  ([&same_task_runner](size_t version, const FlutterRendererConfig* config,
457  const FlutterProjectArgs* args, void* user_data,
458  FLUTTER_API_SYMBOL(FlutterEngine) * engine_out) {
459  same_task_runner = args->custom_task_runners->platform_task_runner ==
460  args->custom_task_runners->ui_task_runner;
461  return kSuccess;
462  }));
463  fl_engine_get_embedder_api(engine)->RunInitialized =
464  MOCK_ENGINE_PROC(RunInitialized, ([](auto engine) { return kSuccess; }));
465 
466  g_autoptr(GError) error = nullptr;
467  EXPECT_TRUE(fl_engine_start(engine, &error));
468  EXPECT_EQ(error, nullptr);
469  EXPECT_TRUE(same_task_runner);
470 }
471 
472 TEST(FlEngineTest, UIIsolateOnPlatformTaskRunner) {
473  g_autoptr(FlDartProject) project = fl_dart_project_new();
474  g_autoptr(FlEngine) engine = fl_engine_new(project);
477 
478  bool same_task_runner = false;
479 
480  fl_engine_get_embedder_api(engine)->Initialize = MOCK_ENGINE_PROC(
481  Initialize,
482  ([&same_task_runner](size_t version, const FlutterRendererConfig* config,
483  const FlutterProjectArgs* args, void* user_data,
484  FLUTTER_API_SYMBOL(FlutterEngine) * engine_out) {
485  same_task_runner = args->custom_task_runners->platform_task_runner ==
486  args->custom_task_runners->ui_task_runner;
487  return kSuccess;
488  }));
489  fl_engine_get_embedder_api(engine)->RunInitialized =
490  MOCK_ENGINE_PROC(RunInitialized, ([](auto engine) { return kSuccess; }));
491 
492  g_autoptr(GError) error = nullptr;
493  EXPECT_TRUE(fl_engine_start(engine, &error));
494  EXPECT_EQ(error, nullptr);
495  EXPECT_TRUE(same_task_runner);
496 }
497 
498 TEST(FlEngineTest, UIIsolateOnSeparateThread) {
499  g_autoptr(FlDartProject) project = fl_dart_project_new();
500  g_autoptr(FlEngine) engine = fl_engine_new(project);
503 
504  bool separate_thread = false;
505 
506  fl_engine_get_embedder_api(engine)->Initialize = MOCK_ENGINE_PROC(
507  Initialize,
508  ([&separate_thread](size_t version, const FlutterRendererConfig* config,
509  const FlutterProjectArgs* args, void* user_data,
510  FLUTTER_API_SYMBOL(FlutterEngine) * engine_out) {
511  separate_thread = args->custom_task_runners->ui_task_runner == nullptr;
512  return kSuccess;
513  }));
514  fl_engine_get_embedder_api(engine)->RunInitialized =
515  MOCK_ENGINE_PROC(RunInitialized, ([](auto engine) { return kSuccess; }));
516 
517  g_autoptr(GError) error = nullptr;
518  EXPECT_TRUE(fl_engine_start(engine, &error));
519  EXPECT_EQ(error, nullptr);
520  EXPECT_TRUE(separate_thread);
521 }
522 
523 TEST(FlEngineTest, Locales) {
524  g_autofree gchar* initial_language = g_strdup(g_getenv("LANGUAGE"));
525  g_setenv("LANGUAGE", "de:en_US", TRUE);
526  g_autoptr(FlDartProject) project = fl_dart_project_new();
527 
528  g_autoptr(FlEngine) engine = fl_engine_new(project);
529 
530  bool called = false;
531  fl_engine_get_embedder_api(engine)->UpdateLocales = MOCK_ENGINE_PROC(
532  UpdateLocales, ([&called](auto engine, const FlutterLocale** locales,
533  size_t locales_count) {
534  called = true;
535 
536  EXPECT_EQ(locales_count, static_cast<size_t>(4));
537 
538  EXPECT_STREQ(locales[0]->language_code, "de");
539  EXPECT_STREQ(locales[0]->country_code, nullptr);
540  EXPECT_STREQ(locales[0]->script_code, nullptr);
541  EXPECT_STREQ(locales[0]->variant_code, nullptr);
542 
543  EXPECT_STREQ(locales[1]->language_code, "en");
544  EXPECT_STREQ(locales[1]->country_code, "US");
545  EXPECT_STREQ(locales[1]->script_code, nullptr);
546  EXPECT_STREQ(locales[1]->variant_code, nullptr);
547 
548  EXPECT_STREQ(locales[2]->language_code, "en");
549  EXPECT_STREQ(locales[2]->country_code, nullptr);
550  EXPECT_STREQ(locales[2]->script_code, nullptr);
551  EXPECT_STREQ(locales[2]->variant_code, nullptr);
552 
553  EXPECT_STREQ(locales[3]->language_code, "C");
554  EXPECT_STREQ(locales[3]->country_code, nullptr);
555  EXPECT_STREQ(locales[3]->script_code, nullptr);
556  EXPECT_STREQ(locales[3]->variant_code, nullptr);
557 
558  return kSuccess;
559  }));
560 
561  g_autoptr(GError) error = nullptr;
562  EXPECT_TRUE(fl_engine_start(engine, &error));
563  EXPECT_EQ(error, nullptr);
564 
565  EXPECT_TRUE(called);
566 
567  if (initial_language) {
568  g_setenv("LANGUAGE", initial_language, TRUE);
569  } else {
570  g_unsetenv("LANGUAGE");
571  }
572 }
573 
574 TEST(FlEngineTest, CLocale) {
575  g_autofree gchar* initial_language = g_strdup(g_getenv("LANGUAGE"));
576  g_setenv("LANGUAGE", "C", TRUE);
577  g_autoptr(FlDartProject) project = fl_dart_project_new();
578 
579  g_autoptr(FlEngine) engine = fl_engine_new(project);
580 
581  bool called = false;
582  fl_engine_get_embedder_api(engine)->UpdateLocales = MOCK_ENGINE_PROC(
583  UpdateLocales, ([&called](auto engine, const FlutterLocale** locales,
584  size_t locales_count) {
585  called = true;
586 
587  EXPECT_EQ(locales_count, static_cast<size_t>(1));
588 
589  EXPECT_STREQ(locales[0]->language_code, "C");
590  EXPECT_STREQ(locales[0]->country_code, nullptr);
591  EXPECT_STREQ(locales[0]->script_code, nullptr);
592  EXPECT_STREQ(locales[0]->variant_code, nullptr);
593 
594  return kSuccess;
595  }));
596 
597  g_autoptr(GError) error = nullptr;
598  EXPECT_TRUE(fl_engine_start(engine, &error));
599  EXPECT_EQ(error, nullptr);
600 
601  EXPECT_TRUE(called);
602 
603  if (initial_language) {
604  g_setenv("LANGUAGE", initial_language, TRUE);
605  } else {
606  g_unsetenv("LANGUAGE");
607  }
608 }
609 
610 TEST(FlEngineTest, DuplicateLocale) {
611  g_autofree gchar* initial_language = g_strdup(g_getenv("LANGUAGE"));
612  g_setenv("LANGUAGE", "en:en", TRUE);
613  g_autoptr(FlDartProject) project = fl_dart_project_new();
614 
615  g_autoptr(FlEngine) engine = fl_engine_new(project);
616 
617  bool called = false;
618  fl_engine_get_embedder_api(engine)->UpdateLocales = MOCK_ENGINE_PROC(
619  UpdateLocales, ([&called](auto engine, const FlutterLocale** locales,
620  size_t locales_count) {
621  called = true;
622 
623  EXPECT_EQ(locales_count, static_cast<size_t>(2));
624 
625  EXPECT_STREQ(locales[0]->language_code, "en");
626  EXPECT_STREQ(locales[0]->country_code, nullptr);
627  EXPECT_STREQ(locales[0]->script_code, nullptr);
628  EXPECT_STREQ(locales[0]->variant_code, nullptr);
629 
630  EXPECT_STREQ(locales[1]->language_code, "C");
631  EXPECT_STREQ(locales[1]->country_code, nullptr);
632  EXPECT_STREQ(locales[1]->script_code, nullptr);
633  EXPECT_STREQ(locales[1]->variant_code, nullptr);
634 
635  return kSuccess;
636  }));
637 
638  g_autoptr(GError) error = nullptr;
639  EXPECT_TRUE(fl_engine_start(engine, &error));
640  EXPECT_EQ(error, nullptr);
641 
642  EXPECT_TRUE(called);
643 
644  if (initial_language) {
645  g_setenv("LANGUAGE", initial_language, TRUE);
646  } else {
647  g_unsetenv("LANGUAGE");
648  }
649 }
650 
651 TEST(FlEngineTest, EmptyLocales) {
652  g_autofree gchar* initial_language = g_strdup(g_getenv("LANGUAGE"));
653  g_setenv("LANGUAGE", "de:: :en_US", TRUE);
654  g_autoptr(FlDartProject) project = fl_dart_project_new();
655 
656  g_autoptr(FlEngine) engine = fl_engine_new(project);
657 
658  bool called = false;
659  fl_engine_get_embedder_api(engine)->UpdateLocales = MOCK_ENGINE_PROC(
660  UpdateLocales, ([&called](auto engine, const FlutterLocale** locales,
661  size_t locales_count) {
662  called = true;
663 
664  EXPECT_EQ(locales_count, static_cast<size_t>(4));
665 
666  EXPECT_STREQ(locales[0]->language_code, "de");
667  EXPECT_STREQ(locales[0]->country_code, nullptr);
668  EXPECT_STREQ(locales[0]->script_code, nullptr);
669  EXPECT_STREQ(locales[0]->variant_code, nullptr);
670 
671  EXPECT_STREQ(locales[1]->language_code, "en");
672  EXPECT_STREQ(locales[1]->country_code, "US");
673  EXPECT_STREQ(locales[1]->script_code, nullptr);
674  EXPECT_STREQ(locales[1]->variant_code, nullptr);
675 
676  EXPECT_STREQ(locales[2]->language_code, "en");
677  EXPECT_STREQ(locales[2]->country_code, nullptr);
678  EXPECT_STREQ(locales[2]->script_code, nullptr);
679  EXPECT_STREQ(locales[2]->variant_code, nullptr);
680 
681  EXPECT_STREQ(locales[3]->language_code, "C");
682  EXPECT_STREQ(locales[3]->country_code, nullptr);
683  EXPECT_STREQ(locales[3]->script_code, nullptr);
684  EXPECT_STREQ(locales[3]->variant_code, nullptr);
685 
686  return kSuccess;
687  }));
688 
689  g_autoptr(GError) error = nullptr;
690  EXPECT_TRUE(fl_engine_start(engine, &error));
691  EXPECT_EQ(error, nullptr);
692 
693  EXPECT_TRUE(called);
694 
695  if (initial_language) {
696  g_setenv("LANGUAGE", initial_language, TRUE);
697  } else {
698  g_unsetenv("LANGUAGE");
699  }
700 }
701 
702 static void add_view_cb(GObject* object,
703  GAsyncResult* result,
704  gpointer user_data) {
705  g_autoptr(GError) error = nullptr;
706  gboolean r = fl_engine_add_view_finish(FL_ENGINE(object), result, &error);
707  EXPECT_TRUE(r);
708  EXPECT_EQ(error, nullptr);
709 
710  g_main_loop_quit(static_cast<GMainLoop*>(user_data));
711 }
712 
713 TEST(FlEngineTest, AddView) {
714  g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
715 
716  g_autoptr(FlDartProject) project = fl_dart_project_new();
717  g_autoptr(FlEngine) engine = fl_engine_new(project);
718 
719  bool called = false;
720  fl_engine_get_embedder_api(engine)->AddView = MOCK_ENGINE_PROC(
721  AddView, ([&called](auto engine, const FlutterAddViewInfo* info) {
722  called = true;
723  EXPECT_EQ(info->view_metrics->width, 123u);
724  EXPECT_EQ(info->view_metrics->height, 456u);
725  EXPECT_TRUE(info->view_metrics->has_constraints);
726  EXPECT_EQ(info->view_metrics->min_width_constraint, 123u);
727  EXPECT_EQ(info->view_metrics->min_height_constraint, 456u);
728  EXPECT_EQ(info->view_metrics->max_width_constraint, 888u);
729  EXPECT_EQ(info->view_metrics->max_height_constraint, 999u);
730  EXPECT_EQ(info->view_metrics->pixel_ratio, 2.0);
731 
732  FlutterAddViewResult result;
733  result.struct_size = sizeof(FlutterAddViewResult);
734  result.added = true;
735  result.user_data = info->user_data;
736  info->add_view_callback(&result);
737 
738  return kSuccess;
739  }));
740 
741  g_autoptr(FlMockRenderable) renderable = fl_mock_renderable_new();
742  FlutterViewId view_id =
743  fl_engine_add_view(engine, FL_RENDERABLE(renderable), 123, 456, 888, 999,
744  2.0, nullptr, add_view_cb, loop);
745  EXPECT_GT(view_id, 0);
746  EXPECT_TRUE(called);
747 
748  // Blocks here until add_view_cb is called.
749  g_main_loop_run(loop);
750 }
751 
752 static void add_view_error_cb(GObject* object,
753  GAsyncResult* result,
754  gpointer user_data) {
755  g_autoptr(GError) error = nullptr;
756  gboolean r = fl_engine_add_view_finish(FL_ENGINE(object), result, &error);
757  EXPECT_FALSE(r);
758  EXPECT_NE(error, nullptr);
759 
760  g_main_loop_quit(static_cast<GMainLoop*>(user_data));
761 }
762 
763 TEST(FlEngineTest, AddViewError) {
764  g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
765 
766  g_autoptr(FlDartProject) project = fl_dart_project_new();
767  g_autoptr(FlEngine) engine = fl_engine_new(project);
768 
769  fl_engine_get_embedder_api(engine)->AddView = MOCK_ENGINE_PROC(
770  AddView, ([](auto engine, const FlutterAddViewInfo* info) {
771  FlutterAddViewResult result;
772  result.struct_size = sizeof(FlutterAddViewResult);
773  result.added = false;
774  result.user_data = info->user_data;
775  info->add_view_callback(&result);
776 
777  return kSuccess;
778  }));
779 
780  g_autoptr(FlMockRenderable) renderable = fl_mock_renderable_new();
781  FlutterViewId view_id =
782  fl_engine_add_view(engine, FL_RENDERABLE(renderable), 123, 456, 123, 456,
783  2.0, nullptr, add_view_error_cb, loop);
784  EXPECT_GT(view_id, 0);
785 
786  // Blocks here until add_view_error_cb is called.
787  g_main_loop_run(loop);
788 }
789 
790 static void add_view_engine_error_cb(GObject* object,
791  GAsyncResult* result,
792  gpointer user_data) {
793  g_autoptr(GError) error = nullptr;
794  gboolean r = fl_engine_add_view_finish(FL_ENGINE(object), result, &error);
795  EXPECT_FALSE(r);
796  EXPECT_NE(error, nullptr);
797 
798  g_main_loop_quit(static_cast<GMainLoop*>(user_data));
799 }
800 
801 TEST(FlEngineTest, AddViewEngineError) {
802  g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
803 
804  g_autoptr(FlDartProject) project = fl_dart_project_new();
805  g_autoptr(FlEngine) engine = fl_engine_new(project);
806 
807  fl_engine_get_embedder_api(engine)->AddView = MOCK_ENGINE_PROC(
808  AddView, ([](auto engine, const FlutterAddViewInfo* info) {
809  return kInvalidArguments;
810  }));
811 
812  g_autoptr(FlMockRenderable) renderable = fl_mock_renderable_new();
813  FlutterViewId view_id =
814  fl_engine_add_view(engine, FL_RENDERABLE(renderable), 123, 456, 123, 456,
815  2.0, nullptr, add_view_engine_error_cb, loop);
816  EXPECT_GT(view_id, 0);
817 
818  // Blocks here until remove_view_engine_error_cb is called.
819  g_main_loop_run(loop);
820 }
821 
822 static void remove_view_cb(GObject* object,
823  GAsyncResult* result,
824  gpointer user_data) {
825  g_autoptr(GError) error = nullptr;
826  gboolean r = fl_engine_remove_view_finish(FL_ENGINE(object), result, &error);
827  EXPECT_TRUE(r);
828  EXPECT_EQ(error, nullptr);
829 
830  g_main_loop_quit(static_cast<GMainLoop*>(user_data));
831 }
832 
833 TEST(FlEngineTest, RemoveView) {
834  g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
835 
836  g_autoptr(FlDartProject) project = fl_dart_project_new();
837  g_autoptr(FlEngine) engine = fl_engine_new(project);
838 
839  bool called = false;
840  fl_engine_get_embedder_api(engine)->RemoveView = MOCK_ENGINE_PROC(
841  RemoveView, ([&called](auto engine, const FlutterRemoveViewInfo* info) {
842  called = true;
843  EXPECT_EQ(info->view_id, 123);
844 
845  FlutterRemoveViewResult result;
846  result.struct_size = sizeof(FlutterRemoveViewResult);
847  result.removed = true;
848  result.user_data = info->user_data;
849  info->remove_view_callback(&result);
850 
851  return kSuccess;
852  }));
853 
854  fl_engine_remove_view(engine, 123, nullptr, remove_view_cb, loop);
855  EXPECT_TRUE(called);
856 
857  // Blocks here until remove_view_cb is called.
858  g_main_loop_run(loop);
859 }
860 
861 static void remove_view_error_cb(GObject* object,
862  GAsyncResult* result,
863  gpointer user_data) {
864  g_autoptr(GError) error = nullptr;
865  gboolean r = fl_engine_remove_view_finish(FL_ENGINE(object), result, &error);
866  EXPECT_FALSE(r);
867  EXPECT_NE(error, nullptr);
868 
869  g_main_loop_quit(static_cast<GMainLoop*>(user_data));
870 }
871 
872 TEST(FlEngineTest, RemoveViewError) {
873  g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
874 
875  g_autoptr(FlDartProject) project = fl_dart_project_new();
876  g_autoptr(FlEngine) engine = fl_engine_new(project);
877 
878  fl_engine_get_embedder_api(engine)->RemoveView = MOCK_ENGINE_PROC(
879  RemoveView, ([](auto engine, const FlutterRemoveViewInfo* info) {
880  FlutterRemoveViewResult result;
881  result.struct_size = sizeof(FlutterRemoveViewResult);
882  result.removed = false;
883  result.user_data = info->user_data;
884  info->remove_view_callback(&result);
885 
886  return kSuccess;
887  }));
888 
889  fl_engine_remove_view(engine, 123, nullptr, remove_view_error_cb, loop);
890 
891  // Blocks here until remove_view_error_cb is called.
892  g_main_loop_run(loop);
893 }
894 
895 static void remove_view_engine_error_cb(GObject* object,
896  GAsyncResult* result,
897  gpointer user_data) {
898  g_autoptr(GError) error = nullptr;
899  gboolean r = fl_engine_remove_view_finish(FL_ENGINE(object), result, &error);
900  EXPECT_FALSE(r);
901  EXPECT_NE(error, nullptr);
902 
903  g_main_loop_quit(static_cast<GMainLoop*>(user_data));
904 }
905 
906 TEST(FlEngineTest, RemoveViewEngineError) {
907  g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
908 
909  g_autoptr(FlDartProject) project = fl_dart_project_new();
910  g_autoptr(FlEngine) engine = fl_engine_new(project);
911 
912  fl_engine_get_embedder_api(engine)->RemoveView = MOCK_ENGINE_PROC(
913  RemoveView, ([](auto engine, const FlutterRemoveViewInfo* info) {
914  return kInvalidArguments;
915  }));
916 
918  loop);
919 
920  // Blocks here until remove_view_engine_error_cb is called.
921  g_main_loop_run(loop);
922 }
923 
924 TEST(FlEngineTest, SendKeyEvent) {
925  g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
926 
927  g_autoptr(FlDartProject) project = fl_dart_project_new();
928  g_autoptr(FlEngine) engine = fl_engine_new(project);
929 
930  g_autoptr(GError) error = nullptr;
931  EXPECT_TRUE(fl_engine_start(engine, &error));
932  EXPECT_EQ(error, nullptr);
933 
934  bool called;
935  fl_engine_get_embedder_api(engine)->SendKeyEvent = MOCK_ENGINE_PROC(
936  SendKeyEvent,
937  ([&called](auto engine, const FlutterKeyEvent* event,
938  FlutterKeyEventCallback callback, void* user_data) {
939  called = true;
940  EXPECT_EQ(event->timestamp, 1234);
941  EXPECT_EQ(event->type, kFlutterKeyEventTypeUp);
942  EXPECT_EQ(event->physical, static_cast<uint64_t>(42));
943  EXPECT_EQ(event->logical, static_cast<uint64_t>(123));
944  EXPECT_TRUE(event->synthesized);
945  EXPECT_EQ(event->device_type, kFlutterKeyEventDeviceTypeKeyboard);
946  callback(TRUE, user_data);
947  return kSuccess;
948  }));
949 
950  FlutterKeyEvent event = {.struct_size = sizeof(FlutterKeyEvent),
951  .timestamp = 1234,
952  .type = kFlutterKeyEventTypeUp,
953  .physical = 42,
954  .logical = 123,
955  .character = nullptr,
956  .synthesized = true,
957  .device_type = kFlutterKeyEventDeviceTypeKeyboard};
959  engine, &event, nullptr,
960  [](GObject* object, GAsyncResult* result, gpointer user_data) {
961  gboolean handled;
962  g_autoptr(GError) error = nullptr;
963  EXPECT_TRUE(fl_engine_send_key_event_finish(FL_ENGINE(object), result,
964  &handled, &error));
965  EXPECT_EQ(error, nullptr);
966  EXPECT_TRUE(handled);
967  g_main_loop_quit(static_cast<GMainLoop*>(user_data));
968  },
969  loop);
970 
971  g_main_loop_run(loop);
972  EXPECT_TRUE(called);
973 }
974 
975 TEST(FlEngineTest, SendKeyEventNotHandled) {
976  g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
977 
978  g_autoptr(FlDartProject) project = fl_dart_project_new();
979  g_autoptr(FlEngine) engine = fl_engine_new(project);
980 
981  g_autoptr(GError) error = nullptr;
982  EXPECT_TRUE(fl_engine_start(engine, &error));
983  EXPECT_EQ(error, nullptr);
984 
985  bool called;
986  fl_engine_get_embedder_api(engine)->SendKeyEvent = MOCK_ENGINE_PROC(
987  SendKeyEvent,
988  ([&called](auto engine, const FlutterKeyEvent* event,
989  FlutterKeyEventCallback callback, void* user_data) {
990  called = true;
991  callback(FALSE, user_data);
992  return kSuccess;
993  }));
994 
995  FlutterKeyEvent event = {.struct_size = sizeof(FlutterKeyEvent),
996  .timestamp = 1234,
997  .type = kFlutterKeyEventTypeUp,
998  .physical = 42,
999  .logical = 123,
1000  .character = nullptr,
1001  .synthesized = true,
1002  .device_type = kFlutterKeyEventDeviceTypeKeyboard};
1004  engine, &event, nullptr,
1005  [](GObject* object, GAsyncResult* result, gpointer user_data) {
1006  gboolean handled;
1007  g_autoptr(GError) error = nullptr;
1008  EXPECT_TRUE(fl_engine_send_key_event_finish(FL_ENGINE(object), result,
1009  &handled, &error));
1010  EXPECT_EQ(error, nullptr);
1011  EXPECT_FALSE(handled);
1012  g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1013  },
1014  loop);
1015 
1016  g_main_loop_run(loop);
1017  EXPECT_TRUE(called);
1018 }
1019 
1020 TEST(FlEngineTest, SendKeyEventError) {
1021  g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
1022 
1023  g_autoptr(FlDartProject) project = fl_dart_project_new();
1024  g_autoptr(FlEngine) engine = fl_engine_new(project);
1025 
1026  g_autoptr(GError) error = nullptr;
1027  // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.Assign)
1028  EXPECT_TRUE(fl_engine_start(engine, &error));
1029  EXPECT_EQ(error, nullptr);
1030 
1031  bool called;
1032  fl_engine_get_embedder_api(engine)->SendKeyEvent = MOCK_ENGINE_PROC(
1033  SendKeyEvent,
1034  ([&called](auto engine, const FlutterKeyEvent* event,
1035  FlutterKeyEventCallback callback, void* user_data) {
1036  called = true;
1037  return kInvalidArguments;
1038  }));
1039 
1040  FlutterKeyEvent event = {.struct_size = sizeof(FlutterKeyEvent),
1041  .timestamp = 1234,
1042  .type = kFlutterKeyEventTypeUp,
1043  .physical = 42,
1044  .logical = 123,
1045  .character = nullptr,
1046  .synthesized = true,
1047  .device_type = kFlutterKeyEventDeviceTypeKeyboard};
1049  engine, &event, nullptr,
1050  [](GObject* object, GAsyncResult* result, gpointer user_data) {
1051  gboolean handled;
1052  g_autoptr(GError) error = nullptr;
1053  EXPECT_FALSE(fl_engine_send_key_event_finish(FL_ENGINE(object), result,
1054  &handled, &error));
1055  EXPECT_NE(error, nullptr);
1056  EXPECT_STREQ(error->message, "Failed to send key event");
1057  g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1058  },
1059  loop);
1060 
1061  g_main_loop_run(loop);
1062  EXPECT_TRUE(called);
1063 }
1064 
1065 TEST(FlEngineTest, ChildObjects) {
1066  g_autoptr(FlDartProject) project = fl_dart_project_new();
1067  g_autoptr(FlEngine) engine = fl_engine_new(project);
1068 
1069  // Check objects exist before engine started.
1070  EXPECT_NE(fl_engine_get_binary_messenger(engine), nullptr);
1071  EXPECT_NE(fl_engine_get_display_monitor(engine), nullptr);
1072  EXPECT_NE(fl_engine_get_task_runner(engine), nullptr);
1073  EXPECT_NE(fl_engine_get_keyboard_manager(engine), nullptr);
1074  EXPECT_NE(fl_engine_get_mouse_cursor_handler(engine), nullptr);
1075 }
1076 
1077 // NOLINTEND(clang-analyzer-core.StackAddressEscape)
const char * message
g_autoptr(FlEngine) engine
FlRenderable * renderable
const char FlTextDirection FlAssertiveness gpointer user_data
self height
self width
return TRUE
G_MODULE_EXPORT FlDartProject * fl_dart_project_new()
G_MODULE_EXPORT void fl_dart_project_set_ui_thread_policy(FlDartProject *project, FlUIThreadPolicy policy)
G_MODULE_EXPORT void fl_dart_project_set_dart_entrypoint_arguments(FlDartProject *self, char **argv)
@ FL_UI_THREAD_POLICY_RUN_ON_PLATFORM_THREAD
@ FL_UI_THREAD_POLICY_RUN_ON_SEPARATE_THREAD
@ FL_UI_THREAD_POLICY_DEFAULT
FlMouseCursorHandler * fl_engine_get_mouse_cursor_handler(FlEngine *self)
Definition: fl_engine.cc:1544
void fl_engine_send_mouse_pointer_event(FlEngine *self, FlutterViewId view_id, FlutterPointerPhase phase, size_t timestamp, double x, double y, FlutterPointerDeviceKind device_kind, double scroll_delta_x, double scroll_delta_y, int64_t buttons)
Definition: fl_engine.cc:1176
gboolean fl_engine_send_key_event_finish(FlEngine *self, GAsyncResult *result, gboolean *handled, GError **error)
Definition: fl_engine.cc:1423
FlutterEngineProcTable * fl_engine_get_embedder_api(FlEngine *self)
Definition: fl_engine.cc:902
void fl_engine_dispatch_semantics_action(FlEngine *self, FlutterViewId view_id, uint64_t node_id, FlutterSemanticsAction action, GBytes *data)
Definition: fl_engine.cc:1440
void fl_engine_send_window_metrics_event(FlEngine *self, FlutterEngineDisplayId display_id, FlutterViewId view_id, size_t min_width, size_t min_height, size_t max_width, size_t max_height, double pixel_ratio)
Definition: fl_engine.cc:1144
void fl_engine_notify_display_update(FlEngine *self, const FlutterEngineDisplay *displays, size_t displays_length)
Definition: fl_engine.cc:906
gboolean fl_engine_remove_view_finish(FlEngine *self, GAsyncResult *result, GError **error)
Definition: fl_engine.cc:1016
FlTaskRunner * fl_engine_get_task_runner(FlEngine *self)
Definition: fl_engine.cc:1497
FlKeyboardManager * fl_engine_get_keyboard_manager(FlEngine *self)
Definition: fl_engine.cc:1534
FlDisplayMonitor * fl_engine_get_display_monitor(FlEngine *self)
Definition: fl_engine.cc:755
gboolean fl_engine_send_platform_message_response(FlEngine *self, const FlutterPlatformMessageResponseHandle *handle, GBytes *response, GError **error)
Definition: fl_engine.cc:1042
FlutterViewId fl_engine_add_view(FlEngine *self, FlRenderable *renderable, size_t min_width, size_t min_height, size_t max_width, size_t max_height, double pixel_ratio, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
Definition: fl_engine.cc:923
void fl_engine_send_platform_message(FlEngine *self, const gchar *channel, GBytes *message, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
Definition: fl_engine.cc:1074
FlEngine * fl_engine_for_id(int64_t id)
Definition: fl_engine.cc:725
void fl_engine_remove_view(FlEngine *self, FlutterViewId view_id, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
Definition: fl_engine.cc:989
G_MODULE_EXPORT FlBinaryMessenger * fl_engine_get_binary_messenger(FlEngine *self)
Definition: fl_engine.cc:1491
gboolean fl_engine_add_view_finish(FlEngine *self, GAsyncResult *result, GError **error)
Definition: fl_engine.cc:976
void fl_engine_send_key_event(FlEngine *self, const FlutterKeyEvent *event, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
Definition: fl_engine.cc:1400
void fl_engine_send_pointer_pan_zoom_event(FlEngine *self, FlutterViewId view_id, size_t timestamp, double x, double y, FlutterPointerPhase phase, double pan_x, double pan_y, double scale, double rotation)
Definition: fl_engine.cc:1358
gboolean fl_engine_start(FlEngine *self, GError **error)
Definition: fl_engine.cc:760
G_MODULE_EXPORT FlEngine * fl_engine_new(FlDartProject *project)
Definition: fl_engine.cc:731
void on_pre_engine_restart_cb(FlEngine *engine, gpointer user_data)
static void remove_view_engine_error_cb(GObject *object, GAsyncResult *result, gpointer user_data)
TEST(FlEngineTest, NotifyDisplayUpdate)
static void remove_view_cb(GObject *object, GAsyncResult *result, gpointer user_data)
static void add_view_error_cb(GObject *object, GAsyncResult *result, gpointer user_data)
static void add_view_engine_error_cb(GObject *object, GAsyncResult *result, gpointer user_data)
static void remove_view_error_cb(GObject *object, GAsyncResult *result, gpointer user_data)
static void add_view_cb(GObject *object, GAsyncResult *result, gpointer user_data)
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
G_MODULE_EXPORT FlJsonMessageCodec * fl_json_message_codec_new()
G_MODULE_EXPORT FlValue * fl_message_codec_decode_message(FlMessageCodec *self, GBytes *message, GError **error)
const uint8_t uint32_t uint32_t GError ** error
G_MODULE_EXPORT FlValue * fl_value_lookup_string(FlValue *self, const gchar *key)
Definition: fl_value.cc:811
G_MODULE_EXPORT FlValueType fl_value_get_type(FlValue *self)
Definition: fl_value.cc:466
typedefG_BEGIN_DECLS struct _FlValue FlValue
Definition: fl_value.h:42
@ FL_VALUE_TYPE_STRING
Definition: fl_value.h:68
@ FL_VALUE_TYPE_BOOL
Definition: fl_value.h:65
@ FL_VALUE_TYPE_FLOAT
Definition: fl_value.h:67
G_BEGIN_DECLS FlutterViewId view_id