From 033d19150fe149a121d1bc812ed31fa4db8f859a Mon Sep 17 00:00:00 2001 From: Robert Ancell Date: Mon, 22 Jul 2024 12:05:22 +0100 Subject: [PATCH 1/3] Add fl_engine_add/remove_view --- shell/platform/linux/fl_engine.cc | 120 ++++++++++++- shell/platform/linux/fl_engine_private.h | 95 ++++++++-- shell/platform/linux/fl_engine_test.cc | 215 +++++++++++++++++++++++ 3 files changed, 410 insertions(+), 20 deletions(-) diff --git a/shell/platform/linux/fl_engine.cc b/shell/platform/linux/fl_engine.cc index ace289a1b08bb..02651723c0341 100644 --- a/shell/platform/linux/fl_engine.cc +++ b/shell/platform/linux/fl_engine.cc @@ -53,6 +53,9 @@ struct _FlEngine { FLUTTER_API_SYMBOL(FlutterEngine) engine; FlutterEngineProcTable embedder_api; + // Next ID to use for a view. + FlutterViewId next_view_id; + // Function to call when a platform message is received. FlEnginePlatformMessageHandler platform_message_handler; gpointer platform_message_handler_data; @@ -127,6 +130,28 @@ static void parse_locale(const gchar* locale, } } +static void view_added_cb(const FlutterAddViewResult* result) { + g_autoptr(GTask) task = G_TASK(result->user_data); + + if (result->added) { + g_task_return_boolean(task, TRUE); + } else { + g_task_return_new_error(task, fl_engine_error_quark(), + FL_ENGINE_ERROR_FAILED, "Failed to add view"); + } +} + +static void view_removed_cb(const FlutterRemoveViewResult* result) { + g_autoptr(GTask) task = G_TASK(result->user_data); + + if (result->removed) { + g_task_return_boolean(task, TRUE); + } else { + g_task_return_new_error(task, fl_engine_error_quark(), + FL_ENGINE_ERROR_FAILED, "Failed to remove view"); + } +} + static void set_app_lifecycle_state(FlEngine* self, const flutter::AppLifecycleState state) { FlBinaryMessenger* binary_messenger = fl_engine_get_binary_messenger(self); @@ -200,12 +225,11 @@ static bool compositor_collect_backing_store_callback( } // Called when embedder should composite contents of each layer onto the screen. -static bool compositor_present_layers_callback(const FlutterLayer** layers, - size_t layers_count, - void* user_data) { - g_return_val_if_fail(FL_IS_RENDERER(user_data), false); - return fl_renderer_present_layers(FL_RENDERER(user_data), layers, - layers_count); +static bool compositor_present_view_callback( + const FlutterPresentViewInfo* info) { + g_return_val_if_fail(FL_IS_RENDERER(info->user_data), false); + return fl_renderer_present_layers(FL_RENDERER(info->user_data), info->layers, + info->layers_count); } // Flutter engine rendering callbacks. @@ -234,7 +258,7 @@ static uint32_t fl_engine_gl_get_fbo(void* user_data) { static bool fl_engine_gl_present(void* user_data) { // No action required, as this is handled in - // compositor_present_layers_callback. + // compositor_present_view_callback. return true; } @@ -452,6 +476,9 @@ static void fl_engine_init(FlEngine* self) { self->embedder_api.struct_size = sizeof(FlutterEngineProcTable); FlutterEngineGetProcAddresses(&self->embedder_api); + // Implicit view is 0, so start at 1. + self->next_view_id = 1; + self->texture_registrar = fl_texture_registrar_new(self); } @@ -534,7 +561,7 @@ gboolean fl_engine_start(FlEngine* self, GError** error) { compositor_create_backing_store_callback; compositor.collect_backing_store_callback = compositor_collect_backing_store_callback; - compositor.present_layers_callback = compositor_present_layers_callback; + compositor.present_view_callback = compositor_present_view_callback; args.compositor = &compositor; if (self->embedder_api.RunsAOTCompiledDartCode()) { @@ -603,6 +630,83 @@ FlutterEngineProcTable* fl_engine_get_embedder_api(FlEngine* self) { return &(self->embedder_api); } +FlutterViewId fl_engine_add_view(FlEngine* self, + size_t width, + size_t height, + double pixel_ratio, + GCancellable* cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { + g_return_val_if_fail(FL_IS_ENGINE(self), 0); + + g_autoptr(GTask) task = g_task_new(self, cancellable, callback, user_data); + + FlutterViewId view_id = self->next_view_id; + self->next_view_id++; + + FlutterWindowMetricsEvent metrics; + metrics.struct_size = sizeof(FlutterWindowMetricsEvent); + metrics.width = width; + metrics.height = height; + metrics.pixel_ratio = pixel_ratio; + metrics.view_id = view_id; + FlutterAddViewInfo info; + info.struct_size = sizeof(FlutterAddViewInfo); + info.view_id = view_id; + info.view_metrics = &metrics; + info.user_data = g_object_ref(task); + info.add_view_callback = view_added_cb; + FlutterEngineResult result = self->embedder_api.AddView(self->engine, &info); + if (result != kSuccess) { + g_task_return_new_error(task, fl_engine_error_quark(), + FL_ENGINE_ERROR_FAILED, "AddView returned %d", + result); + // This would have been done in the callback, but that won't occur now. + g_object_unref(task); + } + + return view_id; +} + +gboolean fl_engine_add_view_finish(FlEngine* self, + GAsyncResult* result, + GError** error) { + g_return_val_if_fail(FL_IS_ENGINE(self), FALSE); + return g_task_propagate_boolean(G_TASK(result), error); +} + +void fl_engine_remove_view(FlEngine* self, + FlutterViewId view_id, + GCancellable* cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { + g_return_if_fail(FL_IS_ENGINE(self)); + + g_autoptr(GTask) task = g_task_new(self, cancellable, callback, user_data); + + FlutterRemoveViewInfo info; + info.struct_size = sizeof(FlutterRemoveViewInfo); + info.view_id = view_id; + info.user_data = g_object_ref(task); + info.remove_view_callback = view_removed_cb; + FlutterEngineResult result = + self->embedder_api.RemoveView(self->engine, &info); + if (result != kSuccess) { + g_task_return_new_error(task, fl_engine_error_quark(), + FL_ENGINE_ERROR_FAILED, "RemoveView returned %d", + result); + // This would have been done in the callback, but that won't occur now. + g_object_unref(task); + } +} + +gboolean fl_engine_remove_view_finish(FlEngine* self, + GAsyncResult* result, + GError** error) { + g_return_val_if_fail(FL_IS_ENGINE(self), FALSE); + return g_task_propagate_boolean(G_TASK(result), error); +} + void fl_engine_set_platform_message_handler( FlEngine* self, FlEnginePlatformMessageHandler handler, diff --git a/shell/platform/linux/fl_engine_private.h b/shell/platform/linux/fl_engine_private.h index 9225b481cd67c..61371c3e0b44c 100644 --- a/shell/platform/linux/fl_engine_private.h +++ b/shell/platform/linux/fl_engine_private.h @@ -81,6 +81,18 @@ typedef void (*FlEngineOnPreEngineRestartHandler)(FlEngine* engine, */ FlEngine* fl_engine_new(FlDartProject* project, FlRenderer* renderer); +/** + * fl_engine_start: + * @engine: an #FlEngine. + * @error: (allow-none): #GError location to store the error occurring, or %NULL + * to ignore. + * + * Starts the Flutter engine. + * + * Returns: %TRUE on success. + */ +gboolean fl_engine_start(FlEngine* engine, GError** error); + /** * fl_engine_get_embedder_api: * @engine: an #FlEngine. @@ -91,6 +103,77 @@ FlEngine* fl_engine_new(FlDartProject* project, FlRenderer* renderer); */ FlutterEngineProcTable* fl_engine_get_embedder_api(FlEngine* engine); +/** + * fl_engine_add_view: + * @engine: an #FlEngine. + * @width: width of view in pixels. + * @height: height of view in pixels. + * @pixel_ratio: scale factor for view. + * @cancellable: (allow-none): a #GCancellable or %NULL. + * @callback: (scope async): a #GAsyncReadyCallback to call when the view is + * added. + * @user_data: (closure): user data to pass to @callback. + * + * Adds a new view. + * + * Returns: the ID for the new view. + * + */ +FlutterViewId fl_engine_add_view(FlEngine* engine, + size_t width, + size_t height, + double pixel_ratio, + GCancellable* cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +/** + * fl_engine_add_view_finish: + * @engine: an #FlEngine. + * @result: a #GAsyncResult. + * @error: (allow-none): #GError location to store the error occurring, or %NULL + * to ignore. + * + * Completes request started with fl_engine_add_view(). + * + * Returns: TRUE on succcess. + */ +gboolean fl_engine_add_view_finish(FlEngine* engine, + GAsyncResult* result, + GError** error); + +/** + * fl_engine_remove_view: + * @engine: an #FlEngine. + * @view_id: ID to remove. + * @cancellable: (allow-none): a #GCancellable or %NULL. + * @callback: (scope async): a #GAsyncReadyCallback to call when the view is + * added. + * @user_data: (closure): user data to pass to @callback. + * + * Removes a view previously added with fl_engine_add_view(). + */ +void fl_engine_remove_view(FlEngine* engine, + FlutterViewId view_id, + GCancellable* cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +/** + * fl_engine_remove_view_finish: + * @engine: an #FlEngine. + * @result: a #GAsyncResult. + * @error: (allow-none): #GError location to store the error occurring, or %NULL + * to ignore. + * + * Completes request started with fl_engine_remove_view(). + * + * Returns: TRUE on succcess. + */ +gboolean fl_engine_remove_view_finish(FlEngine* engine, + GAsyncResult* result, + GError** error); + /** * fl_engine_set_platform_message_handler: * @engine: an #FlEngine. @@ -143,18 +226,6 @@ void fl_engine_set_on_pre_engine_restart_handler( gpointer user_data, GDestroyNotify destroy_notify); -/** - * fl_engine_start: - * @engine: an #FlEngine. - * @error: (allow-none): #GError location to store the error occurring, or %NULL - * to ignore. - * - * Starts the Flutter engine. - * - * Returns: %TRUE on success. - */ -gboolean fl_engine_start(FlEngine* engine, GError** error); - /** * fl_engine_send_window_metrics_event: * @engine: an #FlEngine. diff --git a/shell/platform/linux/fl_engine_test.cc b/shell/platform/linux/fl_engine_test.cc index ce690c0535a90..9c90782556c37 100644 --- a/shell/platform/linux/fl_engine_test.cc +++ b/shell/platform/linux/fl_engine_test.cc @@ -426,6 +426,221 @@ TEST(FlEngineTest, SwitchesEmpty) { EXPECT_EQ(switches->len, 0U); } +static void add_view_cb(GObject* object, + GAsyncResult* result, + gpointer user_data) { + g_autoptr(GError) error = nullptr; + gboolean r = fl_engine_add_view_finish(FL_ENGINE(object), result, &error); + EXPECT_TRUE(r); + EXPECT_EQ(error, nullptr); + + g_main_loop_quit(static_cast(user_data)); +} + +TEST(FlEngineTest, AddView) { + g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); + + g_autoptr(FlEngine) engine = make_mock_engine(); + FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine); + + bool called = false; + FlutterViewId assigned_id = 0; + embedder_api->AddView = MOCK_ENGINE_PROC( + AddView, + ([&called, &assigned_id](auto engine, const FlutterAddViewInfo* info) { + called = true; + EXPECT_EQ(info->view_metrics->width, 123u); + EXPECT_EQ(info->view_metrics->height, 456u); + EXPECT_EQ(info->view_metrics->pixel_ratio, 2.0); + + // Must not use ID 0, which is the implicit view. + EXPECT_GT(info->view_id, 0); + assigned_id = info->view_id; + + FlutterAddViewResult result; + result.struct_size = sizeof(FlutterAddViewResult); + result.added = true; + result.user_data = info->user_data; + info->add_view_callback(&result); + + return kSuccess; + })); + + FlutterViewId view_id = + fl_engine_add_view(engine, 123, 456, 2.0, nullptr, add_view_cb, loop); + EXPECT_EQ(view_id, assigned_id); + + EXPECT_TRUE(called); + + // Blocks here until add_view_cb is called. + g_main_loop_run(loop); +} + +static void add_view_error_cb(GObject* object, + GAsyncResult* result, + gpointer user_data) { + g_autoptr(GError) error = nullptr; + gboolean r = fl_engine_add_view_finish(FL_ENGINE(object), result, &error); + EXPECT_FALSE(r); + EXPECT_NE(error, nullptr); + + g_main_loop_quit(static_cast(user_data)); +} + +TEST(FlEngineTest, AddViewError) { + g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); + + g_autoptr(FlEngine) engine = make_mock_engine(); + FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine); + + embedder_api->AddView = MOCK_ENGINE_PROC( + AddView, ([](auto engine, const FlutterAddViewInfo* info) { + FlutterAddViewResult result; + result.struct_size = sizeof(FlutterAddViewResult); + result.added = false; + result.user_data = info->user_data; + info->add_view_callback(&result); + + return kSuccess; + })); + + fl_engine_add_view(engine, 123, 456, 2.0, nullptr, add_view_error_cb, loop); + + // Blocks here until add_view_error_cb is called. + g_main_loop_run(loop); +} + +static void add_view_engine_error_cb(GObject* object, + GAsyncResult* result, + gpointer user_data) { + g_autoptr(GError) error = nullptr; + gboolean r = fl_engine_add_view_finish(FL_ENGINE(object), result, &error); + EXPECT_FALSE(r); + EXPECT_NE(error, nullptr); + + g_main_loop_quit(static_cast(user_data)); +} + +TEST(FlEngineTest, AddViewEngineError) { + g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); + + g_autoptr(FlEngine) engine = make_mock_engine(); + FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine); + + embedder_api->AddView = MOCK_ENGINE_PROC( + AddView, ([](auto engine, const FlutterAddViewInfo* info) { + return kInvalidArguments; + })); + + fl_engine_add_view(engine, 123, 456, 2.0, nullptr, add_view_engine_error_cb, + loop); + + // Blocks here until remove_view_engine_error_cb is called. + g_main_loop_run(loop); +} + +static void remove_view_cb(GObject* object, + GAsyncResult* result, + gpointer user_data) { + g_autoptr(GError) error = nullptr; + gboolean r = fl_engine_remove_view_finish(FL_ENGINE(object), result, &error); + EXPECT_TRUE(r); + EXPECT_EQ(error, nullptr); + + g_main_loop_quit(static_cast(user_data)); +} + +TEST(FlEngineTest, RemoveView) { + g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); + + g_autoptr(FlEngine) engine = make_mock_engine(); + FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine); + + bool called = false; + embedder_api->RemoveView = MOCK_ENGINE_PROC( + RemoveView, ([&called](auto engine, const FlutterRemoveViewInfo* info) { + called = true; + EXPECT_EQ(info->view_id, 123); + + FlutterRemoveViewResult result; + result.struct_size = sizeof(FlutterRemoveViewResult); + result.removed = true; + result.user_data = info->user_data; + info->remove_view_callback(&result); + + return kSuccess; + })); + + fl_engine_remove_view(engine, 123, nullptr, remove_view_cb, loop); + EXPECT_TRUE(called); + + // Blocks here until remove_view_cb is called. + g_main_loop_run(loop); +} + +static void remove_view_error_cb(GObject* object, + GAsyncResult* result, + gpointer user_data) { + g_autoptr(GError) error = nullptr; + gboolean r = fl_engine_remove_view_finish(FL_ENGINE(object), result, &error); + EXPECT_FALSE(r); + EXPECT_NE(error, nullptr); + + g_main_loop_quit(static_cast(user_data)); +} + +TEST(FlEngineTest, RemoveViewError) { + g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); + + g_autoptr(FlEngine) engine = make_mock_engine(); + FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine); + + embedder_api->RemoveView = MOCK_ENGINE_PROC( + RemoveView, ([](auto engine, const FlutterRemoveViewInfo* info) { + FlutterRemoveViewResult result; + result.struct_size = sizeof(FlutterRemoveViewResult); + result.removed = false; + result.user_data = info->user_data; + info->remove_view_callback(&result); + + return kSuccess; + })); + + fl_engine_remove_view(engine, 123, nullptr, remove_view_error_cb, loop); + + // Blocks here until remove_view_error_cb is called. + g_main_loop_run(loop); +} + +static void remove_view_engine_error_cb(GObject* object, + GAsyncResult* result, + gpointer user_data) { + g_autoptr(GError) error = nullptr; + gboolean r = fl_engine_remove_view_finish(FL_ENGINE(object), result, &error); + EXPECT_FALSE(r); + EXPECT_NE(error, nullptr); + + g_main_loop_quit(static_cast(user_data)); +} + +TEST(FlEngineTest, RemoveViewEngineError) { + g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); + + g_autoptr(FlEngine) engine = make_mock_engine(); + FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine); + + embedder_api->RemoveView = MOCK_ENGINE_PROC( + RemoveView, ([](auto engine, const FlutterRemoveViewInfo* info) { + return kInvalidArguments; + })); + + fl_engine_remove_view(engine, 123, nullptr, remove_view_engine_error_cb, + loop); + + // Blocks here until remove_view_engine_error_cb is called. + g_main_loop_run(loop); +} + TEST(FlEngineTest, SendWindowStateEvent) { g_autoptr(FlEngine) engine = make_mock_engine(); FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine); From a76e0fb00e1a72b8d65c46fe75cb98bc81efdb20 Mon Sep 17 00:00:00 2001 From: Robert Ancell Date: Tue, 23 Jul 2024 10:22:14 +0100 Subject: [PATCH 2/3] Return the view ID after the asynchonous operation completes - it can't be used until this occurs. --- shell/platform/linux/fl_engine.cc | 30 ++++++++++++------------ shell/platform/linux/fl_engine_private.h | 26 ++++++++++---------- shell/platform/linux/fl_engine_test.cc | 28 +++++++++------------- 3 files changed, 38 insertions(+), 46 deletions(-) diff --git a/shell/platform/linux/fl_engine.cc b/shell/platform/linux/fl_engine.cc index 02651723c0341..50fe131bbaefc 100644 --- a/shell/platform/linux/fl_engine.cc +++ b/shell/platform/linux/fl_engine.cc @@ -133,8 +133,9 @@ static void parse_locale(const gchar* locale, static void view_added_cb(const FlutterAddViewResult* result) { g_autoptr(GTask) task = G_TASK(result->user_data); + FlutterViewId view_id = GPOINTER_TO_INT(g_task_get_task_data(task)); if (result->added) { - g_task_return_boolean(task, TRUE); + g_task_return_pointer(task, GINT_TO_POINTER(view_id), nullptr); } else { g_task_return_new_error(task, fl_engine_error_quark(), FL_ENGINE_ERROR_FAILED, "Failed to add view"); @@ -630,19 +631,20 @@ FlutterEngineProcTable* fl_engine_get_embedder_api(FlEngine* self) { return &(self->embedder_api); } -FlutterViewId fl_engine_add_view(FlEngine* self, - size_t width, - size_t height, - double pixel_ratio, - GCancellable* cancellable, - GAsyncReadyCallback callback, - gpointer user_data) { - g_return_val_if_fail(FL_IS_ENGINE(self), 0); +void fl_engine_add_view(FlEngine* self, + size_t width, + size_t height, + double pixel_ratio, + GCancellable* cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { + g_return_if_fail(FL_IS_ENGINE(self)); g_autoptr(GTask) task = g_task_new(self, cancellable, callback, user_data); FlutterViewId view_id = self->next_view_id; self->next_view_id++; + g_task_set_task_data(task, GINT_TO_POINTER(view_id), nullptr); FlutterWindowMetricsEvent metrics; metrics.struct_size = sizeof(FlutterWindowMetricsEvent); @@ -664,15 +666,13 @@ FlutterViewId fl_engine_add_view(FlEngine* self, // This would have been done in the callback, but that won't occur now. g_object_unref(task); } - - return view_id; } -gboolean fl_engine_add_view_finish(FlEngine* self, - GAsyncResult* result, - GError** error) { +FlutterViewId fl_engine_add_view_finish(FlEngine* self, + GAsyncResult* result, + GError** error) { g_return_val_if_fail(FL_IS_ENGINE(self), FALSE); - return g_task_propagate_boolean(G_TASK(result), error); + return GPOINTER_TO_INT(g_task_propagate_pointer(G_TASK(result), error)); } void fl_engine_remove_view(FlEngine* self, diff --git a/shell/platform/linux/fl_engine_private.h b/shell/platform/linux/fl_engine_private.h index 61371c3e0b44c..74482522e17d1 100644 --- a/shell/platform/linux/fl_engine_private.h +++ b/shell/platform/linux/fl_engine_private.h @@ -114,18 +114,16 @@ FlutterEngineProcTable* fl_engine_get_embedder_api(FlEngine* engine); * added. * @user_data: (closure): user data to pass to @callback. * - * Adds a new view. - * - * Returns: the ID for the new view. + * Asynchronously add a new view. * */ -FlutterViewId fl_engine_add_view(FlEngine* engine, - size_t width, - size_t height, - double pixel_ratio, - GCancellable* cancellable, - GAsyncReadyCallback callback, - gpointer user_data); +void fl_engine_add_view(FlEngine* engine, + size_t width, + size_t height, + double pixel_ratio, + GCancellable* cancellable, + GAsyncReadyCallback callback, + gpointer user_data); /** * fl_engine_add_view_finish: @@ -136,11 +134,11 @@ FlutterViewId fl_engine_add_view(FlEngine* engine, * * Completes request started with fl_engine_add_view(). * - * Returns: TRUE on succcess. + * Returns: the newly added view ID or 0 on error. */ -gboolean fl_engine_add_view_finish(FlEngine* engine, - GAsyncResult* result, - GError** error); +FlutterViewId fl_engine_add_view_finish(FlEngine* engine, + GAsyncResult* result, + GError** error); /** * fl_engine_remove_view: diff --git a/shell/platform/linux/fl_engine_test.cc b/shell/platform/linux/fl_engine_test.cc index 9c90782556c37..735aedb0f56b6 100644 --- a/shell/platform/linux/fl_engine_test.cc +++ b/shell/platform/linux/fl_engine_test.cc @@ -430,8 +430,9 @@ static void add_view_cb(GObject* object, GAsyncResult* result, gpointer user_data) { g_autoptr(GError) error = nullptr; - gboolean r = fl_engine_add_view_finish(FL_ENGINE(object), result, &error); - EXPECT_TRUE(r); + FlutterViewId view_id = + fl_engine_add_view_finish(FL_ENGINE(object), result, &error); + EXPECT_GT(view_id, 0); EXPECT_EQ(error, nullptr); g_main_loop_quit(static_cast(user_data)); @@ -444,19 +445,13 @@ TEST(FlEngineTest, AddView) { FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine); bool called = false; - FlutterViewId assigned_id = 0; embedder_api->AddView = MOCK_ENGINE_PROC( - AddView, - ([&called, &assigned_id](auto engine, const FlutterAddViewInfo* info) { + AddView, ([&called](auto engine, const FlutterAddViewInfo* info) { called = true; EXPECT_EQ(info->view_metrics->width, 123u); EXPECT_EQ(info->view_metrics->height, 456u); EXPECT_EQ(info->view_metrics->pixel_ratio, 2.0); - // Must not use ID 0, which is the implicit view. - EXPECT_GT(info->view_id, 0); - assigned_id = info->view_id; - FlutterAddViewResult result; result.struct_size = sizeof(FlutterAddViewResult); result.added = true; @@ -466,10 +461,7 @@ TEST(FlEngineTest, AddView) { return kSuccess; })); - FlutterViewId view_id = - fl_engine_add_view(engine, 123, 456, 2.0, nullptr, add_view_cb, loop); - EXPECT_EQ(view_id, assigned_id); - + fl_engine_add_view(engine, 123, 456, 2.0, nullptr, add_view_cb, loop); EXPECT_TRUE(called); // Blocks here until add_view_cb is called. @@ -480,8 +472,9 @@ static void add_view_error_cb(GObject* object, GAsyncResult* result, gpointer user_data) { g_autoptr(GError) error = nullptr; - gboolean r = fl_engine_add_view_finish(FL_ENGINE(object), result, &error); - EXPECT_FALSE(r); + FlutterViewId view_id = + fl_engine_add_view_finish(FL_ENGINE(object), result, &error); + EXPECT_EQ(view_id, 0); EXPECT_NE(error, nullptr); g_main_loop_quit(static_cast(user_data)); @@ -514,8 +507,9 @@ static void add_view_engine_error_cb(GObject* object, GAsyncResult* result, gpointer user_data) { g_autoptr(GError) error = nullptr; - gboolean r = fl_engine_add_view_finish(FL_ENGINE(object), result, &error); - EXPECT_FALSE(r); + FlutterViewId view_id = + fl_engine_add_view_finish(FL_ENGINE(object), result, &error); + EXPECT_EQ(view_id, 0); EXPECT_NE(error, nullptr); g_main_loop_quit(static_cast(user_data)); From 1b4820f04f43ef2f2e35731c218856844721a8b8 Mon Sep 17 00:00:00 2001 From: Robert Ancell Date: Tue, 23 Jul 2024 10:31:50 +0100 Subject: [PATCH 3/3] Remove unnecessary newline --- shell/platform/linux/fl_engine_private.h | 1 - 1 file changed, 1 deletion(-) diff --git a/shell/platform/linux/fl_engine_private.h b/shell/platform/linux/fl_engine_private.h index 74482522e17d1..411044f8539fd 100644 --- a/shell/platform/linux/fl_engine_private.h +++ b/shell/platform/linux/fl_engine_private.h @@ -115,7 +115,6 @@ FlutterEngineProcTable* fl_engine_get_embedder_api(FlEngine* engine); * @user_data: (closure): user data to pass to @callback. * * Asynchronously add a new view. - * */ void fl_engine_add_view(FlEngine* engine, size_t width,