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