From e3b2d11dba3aee4666737ea9dc50f0b9cfc701b7 Mon Sep 17 00:00:00 2001 From: Robert Ancell Date: Tue, 2 Jul 2024 17:18:07 +1200 Subject: [PATCH] Restore creation of engine before Linux widget is realized. (flutter/engine#53604) Due to changes in the renderer in fc560d4 the engine was created once a widget is realized, not when the widget is created. If a Flutter application changed the default my_application.cc template to show the Flutter widget after plugins are run then these plugins would not be able to access the engine. Solved by removing the GdkWindow from the renderer constructor and setting in later when the widget is realized. This works because the renderer is not used until the widget is realized. Fixes https://github.com/flutter/flutter/issues/144873 --- .../platform/linux/fl_binary_messenger.cc | 38 ++++++------ .../linux/fl_binary_messenger_private.h | 8 +++ .../linux/fl_binary_messenger_test.cc | 2 +- .../flutter/shell/platform/linux/fl_engine.cc | 3 + .../shell/platform/linux/fl_renderer_gdk.cc | 13 +++- .../shell/platform/linux/fl_renderer_gdk.h | 13 +++- .../shell/platform/linux/fl_task_runner.cc | 34 ++++------- .../platform/linux/fl_texture_registrar.cc | 60 ++++++++++--------- .../linux/fl_texture_registrar_private.h | 8 +++ .../flutter/shell/platform/linux/fl_view.cc | 21 ++++--- .../shell/platform/linux/fl_view_test.cc | 13 ++++ .../flutter_linux/fl_binary_messenger.h | 2 + .../flutter_linux/fl_texture_registrar.h | 2 + .../linux/testing/mock_binary_messenger.cc | 3 + 14 files changed, 139 insertions(+), 81 deletions(-) diff --git a/engine/src/flutter/shell/platform/linux/fl_binary_messenger.cc b/engine/src/flutter/shell/platform/linux/fl_binary_messenger.cc index 3a1a998e59..16dcd2b86b 100644 --- a/engine/src/flutter/shell/platform/linux/fl_binary_messenger.cc +++ b/engine/src/flutter/shell/platform/linux/fl_binary_messenger.cc @@ -149,18 +149,6 @@ static void platform_message_handler_free(gpointer data) { g_free(self); } -static void engine_weak_notify_cb(gpointer user_data, - GObject* where_the_object_was) { - FlBinaryMessengerImpl* self = FL_BINARY_MESSENGER_IMPL(user_data); - - // Disconnect any handlers. - // Take the reference in case a handler tries to modify this table. - g_autoptr(GHashTable) handlers = self->platform_message_handlers; - self->platform_message_handlers = g_hash_table_new_full( - g_str_hash, g_str_equal, g_free, platform_message_handler_free); - g_hash_table_remove_all(handlers); -} - static gboolean fl_binary_messenger_platform_message_cb( FlEngine* engine, const gchar* channel, @@ -187,13 +175,6 @@ static gboolean fl_binary_messenger_platform_message_cb( static void fl_binary_messenger_impl_dispose(GObject* object) { FlBinaryMessengerImpl* self = FL_BINARY_MESSENGER_IMPL(object); - { - g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine)); - if (engine) { - g_object_weak_unref(G_OBJECT(engine), engine_weak_notify_cb, self); - } - } - g_weak_ref_clear(&self->engine); g_clear_pointer(&self->platform_message_handlers, g_hash_table_unref); @@ -383,6 +364,17 @@ static void set_warns_on_channel_overflow(FlBinaryMessenger* messenger, set_warns_on_channel_overflow_response_cb, nullptr); } +static void shutdown(FlBinaryMessenger* messenger) { + FlBinaryMessengerImpl* self = FL_BINARY_MESSENGER_IMPL(messenger); + + // Disconnect any handlers. + // Take the reference in case a handler tries to modify this table. + g_autoptr(GHashTable) handlers = self->platform_message_handlers; + self->platform_message_handlers = g_hash_table_new_full( + g_str_hash, g_str_equal, g_free, platform_message_handler_free); + g_hash_table_remove_all(handlers); +} + static void fl_binary_messenger_impl_class_init( FlBinaryMessengerImplClass* klass) { G_OBJECT_CLASS(klass)->dispose = fl_binary_messenger_impl_dispose; @@ -396,6 +388,7 @@ static void fl_binary_messenger_impl_iface_init( iface->send_on_channel_finish = send_on_channel_finish; iface->resize_channel = resize_channel; iface->set_warns_on_channel_overflow = set_warns_on_channel_overflow; + iface->shutdown = shutdown; } static void fl_binary_messenger_impl_init(FlBinaryMessengerImpl* self) { @@ -413,7 +406,6 @@ FlBinaryMessenger* fl_binary_messenger_new(FlEngine* engine) { FL_IS_BINARY_MESSENGER_IMPL(self); g_weak_ref_init(&self->engine, G_OBJECT(engine)); - g_object_weak_ref(G_OBJECT(engine), engine_weak_notify_cb, self); fl_engine_set_platform_message_handler( engine, fl_binary_messenger_platform_message_cb, self, NULL); @@ -490,3 +482,9 @@ G_MODULE_EXPORT void fl_binary_messenger_set_warns_on_channel_overflow( return FL_BINARY_MESSENGER_GET_IFACE(self)->set_warns_on_channel_overflow( self, channel, warns); } + +void fl_binary_messenger_shutdown(FlBinaryMessenger* self) { + g_return_if_fail(FL_IS_BINARY_MESSENGER(self)); + + return FL_BINARY_MESSENGER_GET_IFACE(self)->shutdown(self); +} diff --git a/engine/src/flutter/shell/platform/linux/fl_binary_messenger_private.h b/engine/src/flutter/shell/platform/linux/fl_binary_messenger_private.h index ce70c51dc6..e444e8f94e 100644 --- a/engine/src/flutter/shell/platform/linux/fl_binary_messenger_private.h +++ b/engine/src/flutter/shell/platform/linux/fl_binary_messenger_private.h @@ -22,6 +22,14 @@ G_BEGIN_DECLS */ FlBinaryMessenger* fl_binary_messenger_new(FlEngine* engine); +/** + * fl_binary_messenger_shutdown: + * @messenger: an #FlBinaryMessenger. + * + * Shutdown the messenger closing any open channels. + */ +void fl_binary_messenger_shutdown(FlBinaryMessenger* messenger); + G_END_DECLS #endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_BINARY_MESSENGER_PRIVATE_H_ diff --git a/engine/src/flutter/shell/platform/linux/fl_binary_messenger_test.cc b/engine/src/flutter/shell/platform/linux/fl_binary_messenger_test.cc index d27e07d8af..85cbed4de9 100644 --- a/engine/src/flutter/shell/platform/linux/fl_binary_messenger_test.cc +++ b/engine/src/flutter/shell/platform/linux/fl_binary_messenger_test.cc @@ -634,7 +634,7 @@ static void kill_handler_notify_cb(gpointer was_called) { TEST(FlBinaryMessengerTest, DeletingEngineClearsHandlers) { FlEngine* engine = make_mock_engine(); - g_autoptr(FlBinaryMessenger) messenger = fl_binary_messenger_new(engine); + FlBinaryMessenger* messenger = fl_engine_get_binary_messenger(engine); gboolean was_killed = FALSE; // Listen for messages from the engine. diff --git a/engine/src/flutter/shell/platform/linux/fl_engine.cc b/engine/src/flutter/shell/platform/linux/fl_engine.cc index 42001f1dec..ace289a1b0 100644 --- a/engine/src/flutter/shell/platform/linux/fl_engine.cc +++ b/engine/src/flutter/shell/platform/linux/fl_engine.cc @@ -399,6 +399,9 @@ static void fl_engine_dispose(GObject* object) { self->aot_data = nullptr; } + fl_binary_messenger_shutdown(self->binary_messenger); + fl_texture_registrar_shutdown(self->texture_registrar); + g_clear_object(&self->project); g_clear_object(&self->renderer); g_clear_object(&self->texture_registrar); diff --git a/engine/src/flutter/shell/platform/linux/fl_renderer_gdk.cc b/engine/src/flutter/shell/platform/linux/fl_renderer_gdk.cc index f48a6c78f1..2cbb46e37d 100644 --- a/engine/src/flutter/shell/platform/linux/fl_renderer_gdk.cc +++ b/engine/src/flutter/shell/platform/linux/fl_renderer_gdk.cc @@ -39,6 +39,7 @@ static void fl_renderer_gdk_clear_current(FlRenderer* renderer) { gdk_gl_context_clear_current(); } +// Implements FlRenderer::get_refresh_rate. static gdouble fl_renderer_gdk_get_refresh_rate(FlRenderer* renderer) { FlRendererGdk* self = FL_RENDERER_GDK(renderer); GdkDisplay* display = gdk_window_get_display(self->window); @@ -78,14 +79,22 @@ static void fl_renderer_gdk_class_init(FlRendererGdkClass* klass) { static void fl_renderer_gdk_init(FlRendererGdk* self) {} -FlRendererGdk* fl_renderer_gdk_new(GdkWindow* window) { +FlRendererGdk* fl_renderer_gdk_new() { FlRendererGdk* self = FL_RENDERER_GDK(g_object_new(fl_renderer_gdk_get_type(), nullptr)); - self->window = window; return self; } +void fl_renderer_gdk_set_window(FlRendererGdk* self, GdkWindow* window) { + g_return_if_fail(FL_IS_RENDERER_GDK(self)); + + g_assert(self->window == nullptr); + self->window = window; +} + gboolean fl_renderer_gdk_create_contexts(FlRendererGdk* self, GError** error) { + g_return_val_if_fail(FL_IS_RENDERER_GDK(self), FALSE); + self->gdk_context = gdk_window_create_gl_context(self->window, error); if (self->gdk_context == nullptr) { return FALSE; diff --git a/engine/src/flutter/shell/platform/linux/fl_renderer_gdk.h b/engine/src/flutter/shell/platform/linux/fl_renderer_gdk.h index e2b3f7bb1f..89a8ee212a 100644 --- a/engine/src/flutter/shell/platform/linux/fl_renderer_gdk.h +++ b/engine/src/flutter/shell/platform/linux/fl_renderer_gdk.h @@ -23,13 +23,22 @@ G_DECLARE_FINAL_TYPE(FlRendererGdk, /** * fl_renderer_gdk_new: - * @window: the window that is being rendered on. * * Creates an object that allows Flutter to render by OpenGL ES. * * Returns: a new #FlRendererGdk. */ -FlRendererGdk* fl_renderer_gdk_new(GdkWindow* window); +FlRendererGdk* fl_renderer_gdk_new(); + +/** + * fl_renderer_gdk_set_window: + * @renderer: an #FlRendererGdk. + * @window: the window that is being rendered on. + * + * Set the window that is being rendered on. This is only called once when the + * window is available. + */ +void fl_renderer_gdk_set_window(FlRendererGdk* renderer, GdkWindow* window); /** * fl_renderer_gdk_create_contexts: diff --git a/engine/src/flutter/shell/platform/linux/fl_task_runner.cc b/engine/src/flutter/shell/platform/linux/fl_task_runner.cc index ce9938915c..147550c504 100644 --- a/engine/src/flutter/shell/platform/linux/fl_task_runner.cc +++ b/engine/src/flutter/shell/platform/linux/fl_task_runner.cc @@ -11,7 +11,7 @@ static constexpr int kMillisecondsPerMicrosecond = 1000; struct _FlTaskRunner { GObject parent_instance; - FlEngine* engine; + GWeakRef engine; GMutex mutex; GCond cond; @@ -51,11 +51,14 @@ static void fl_task_runner_process_expired_tasks_locked(FlTaskRunner* self) { g_mutex_unlock(&self->mutex); - l = expired_tasks; - while (l != nullptr && self->engine) { - FlTaskRunnerTask* task = static_cast(l->data); - fl_engine_execute_task(self->engine, &task->task); - l = l->next; + g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine)); + if (engine != nullptr) { + l = expired_tasks; + while (l != nullptr) { + FlTaskRunnerTask* task = static_cast(l->data); + fl_engine_execute_task(engine, &task->task); + l = l->next; + } } g_list_free_full(expired_tasks, g_free); @@ -120,12 +123,6 @@ static void fl_task_runner_tasks_did_change_locked(FlTaskRunner* self) { } } -static void engine_weak_notify_cb(gpointer user_data, - GObject* where_the_object_was) { - FlTaskRunner* self = FL_TASK_RUNNER(user_data); - self->engine = nullptr; -} - void fl_task_runner_dispose(GObject* object) { FlTaskRunner* self = FL_TASK_RUNNER(object); @@ -133,11 +130,7 @@ void fl_task_runner_dispose(GObject* object) { // main thread g_assert(!self->blocking_main_thread); - if (self->engine != nullptr) { - g_object_weak_unref(G_OBJECT(self->engine), engine_weak_notify_cb, self); - self->engine = nullptr; - } - + g_weak_ref_clear(&self->engine); g_mutex_clear(&self->mutex); g_cond_clear(&self->cond); @@ -159,11 +152,10 @@ static void fl_task_runner_init(FlTaskRunner* self) { } FlTaskRunner* fl_task_runner_new(FlEngine* engine) { - FlTaskRunner* res = + FlTaskRunner* self = FL_TASK_RUNNER(g_object_new(fl_task_runner_get_type(), nullptr)); - res->engine = engine; - g_object_weak_ref(G_OBJECT(engine), engine_weak_notify_cb, res); - return res; + g_weak_ref_init(&self->engine, G_OBJECT(engine)); + return self; } void fl_task_runner_post_task(FlTaskRunner* self, diff --git a/engine/src/flutter/shell/platform/linux/fl_texture_registrar.cc b/engine/src/flutter/shell/platform/linux/fl_texture_registrar.cc index 7ef0f85a04..1b373f4d14 100644 --- a/engine/src/flutter/shell/platform/linux/fl_texture_registrar.cc +++ b/engine/src/flutter/shell/platform/linux/fl_texture_registrar.cc @@ -23,7 +23,7 @@ struct _FlTextureRegistrarImpl { GObject parent_instance; // Weak reference to the engine this texture registrar is created for. - FlEngine* engine; + GWeakRef engine; // ID to assign to the next new texture. int64_t next_id; @@ -54,20 +54,6 @@ G_DEFINE_TYPE_WITH_CODE( static void fl_texture_registrar_default_init( FlTextureRegistrarInterface* iface) {} -static void engine_weak_notify_cb(gpointer user_data, - GObject* where_the_object_was) { - FlTextureRegistrarImpl* self = FL_TEXTURE_REGISTRAR_IMPL(user_data); - self->engine = nullptr; - - // Unregister any textures. - g_mutex_lock(&self->textures_mutex); - g_autoptr(GHashTable) textures = self->textures; - self->textures = g_hash_table_new_full(g_direct_hash, g_direct_equal, nullptr, - g_object_unref); - g_hash_table_remove_all(textures); - g_mutex_unlock(&self->textures_mutex); -} - static void fl_texture_registrar_impl_dispose(GObject* object) { FlTextureRegistrarImpl* self = FL_TEXTURE_REGISTRAR_IMPL(object); @@ -75,10 +61,7 @@ static void fl_texture_registrar_impl_dispose(GObject* object) { g_clear_pointer(&self->textures, g_hash_table_unref); g_mutex_unlock(&self->textures_mutex); - if (self->engine != nullptr) { - g_object_weak_unref(G_OBJECT(self->engine), engine_weak_notify_cb, self); - self->engine = nullptr; - } + g_weak_ref_clear(&self->engine); g_mutex_clear(&self->textures_mutex); G_OBJECT_CLASS(fl_texture_registrar_impl_parent_class)->dispose(object); @@ -94,7 +77,8 @@ static gboolean register_texture(FlTextureRegistrar* registrar, FlTextureRegistrarImpl* self = FL_TEXTURE_REGISTRAR_IMPL(registrar); if (FL_IS_TEXTURE_GL(texture) || FL_IS_PIXEL_BUFFER_TEXTURE(texture)) { - if (self->engine == nullptr) { + g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine)); + if (engine == nullptr) { return FALSE; } @@ -104,7 +88,7 @@ static gboolean register_texture(FlTextureRegistrar* registrar, // https://github.com/flutter/flutter/issues/124009 int64_t id = // self->next_id++; int64_t id = reinterpret_cast(texture); - if (fl_engine_register_external_texture(self->engine, id)) { + if (fl_engine_register_external_texture(engine, id)) { fl_texture_set_id(texture, id); g_mutex_lock(&self->textures_mutex); g_hash_table_insert(self->textures, GINT_TO_POINTER(id), @@ -134,11 +118,12 @@ static gboolean mark_texture_frame_available(FlTextureRegistrar* registrar, FlTexture* texture) { FlTextureRegistrarImpl* self = FL_TEXTURE_REGISTRAR_IMPL(registrar); - if (self->engine == nullptr) { + g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine)); + if (engine == nullptr) { return FALSE; } - return fl_engine_mark_texture_frame_available(self->engine, + return fl_engine_mark_texture_frame_available(engine, fl_texture_get_id(texture)); } @@ -146,12 +131,13 @@ static gboolean unregister_texture(FlTextureRegistrar* registrar, FlTexture* texture) { FlTextureRegistrarImpl* self = FL_TEXTURE_REGISTRAR_IMPL(registrar); - if (self->engine == nullptr) { + g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine)); + if (engine == nullptr) { return FALSE; } - gboolean result = fl_engine_unregister_external_texture( - self->engine, fl_texture_get_id(texture)); + gboolean result = + fl_engine_unregister_external_texture(engine, fl_texture_get_id(texture)); g_mutex_lock(&self->textures_mutex); if (!g_hash_table_remove(self->textures, @@ -163,12 +149,25 @@ static gboolean unregister_texture(FlTextureRegistrar* registrar, return result; } +static void shutdown(FlTextureRegistrar* registrar) { + FlTextureRegistrarImpl* self = FL_TEXTURE_REGISTRAR_IMPL(registrar); + + // Unregister any textures. + g_mutex_lock(&self->textures_mutex); + g_autoptr(GHashTable) textures = self->textures; + self->textures = g_hash_table_new_full(g_direct_hash, g_direct_equal, nullptr, + g_object_unref); + g_hash_table_remove_all(textures); + g_mutex_unlock(&self->textures_mutex); +} + static void fl_texture_registrar_impl_iface_init( FlTextureRegistrarInterface* iface) { iface->register_texture = register_texture; iface->lookup_texture = lookup_texture; iface->mark_texture_frame_available = mark_texture_frame_available; iface->unregister_texture = unregister_texture; + iface->shutdown = shutdown; } static void fl_texture_registrar_impl_init(FlTextureRegistrarImpl* self) { @@ -213,6 +212,12 @@ G_MODULE_EXPORT gboolean fl_texture_registrar_unregister_texture( texture); } +void fl_texture_registrar_shutdown(FlTextureRegistrar* self) { + g_return_if_fail(FL_IS_TEXTURE_REGISTRAR(self)); + + return FL_TEXTURE_REGISTRAR_GET_IFACE(self)->shutdown(self); +} + FlTextureRegistrar* fl_texture_registrar_new(FlEngine* engine) { FlTextureRegistrarImpl* self = FL_TEXTURE_REGISTRAR_IMPL( g_object_new(fl_texture_registrar_impl_get_type(), nullptr)); @@ -220,8 +225,7 @@ FlTextureRegistrar* fl_texture_registrar_new(FlEngine* engine) { // Added to stop compiler complaining about an unused function. FL_IS_TEXTURE_REGISTRAR_IMPL(self); - self->engine = engine; - g_object_weak_ref(G_OBJECT(engine), engine_weak_notify_cb, self); + g_weak_ref_init(&self->engine, G_OBJECT(engine)); return FL_TEXTURE_REGISTRAR(self); } diff --git a/engine/src/flutter/shell/platform/linux/fl_texture_registrar_private.h b/engine/src/flutter/shell/platform/linux/fl_texture_registrar_private.h index 3f1e69b7fe..0ebbf48df4 100644 --- a/engine/src/flutter/shell/platform/linux/fl_texture_registrar_private.h +++ b/engine/src/flutter/shell/platform/linux/fl_texture_registrar_private.h @@ -33,6 +33,14 @@ FlTextureRegistrar* fl_texture_registrar_new(FlEngine* engine); FlTexture* fl_texture_registrar_lookup_texture(FlTextureRegistrar* registrar, int64_t texture_id); +/** + * fl_texture_registrar_shutdown: + * @registrar: an #FlTextureRegistrar. + * + * Shutdown the registrary and unregister any textures. + */ +void fl_texture_registrar_shutdown(FlTextureRegistrar* registrar); + G_END_DECLS #endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_TEXTURE_REGISTRAR_PRIVATE_H_ diff --git a/engine/src/flutter/shell/platform/linux/fl_view.cc b/engine/src/flutter/shell/platform/linux/fl_view.cc index 854749296b..150de42b88 100644 --- a/engine/src/flutter/shell/platform/linux/fl_view.cc +++ b/engine/src/flutter/shell/platform/linux/fl_view.cc @@ -550,13 +550,8 @@ static gboolean window_state_event_cb(FlView* self, GdkEvent* event) { } static GdkGLContext* create_context_cb(FlView* self) { - self->renderer = - fl_renderer_gdk_new(gtk_widget_get_parent_window(GTK_WIDGET(self))); - self->engine = fl_engine_new(self->project, FL_RENDERER(self->renderer)); - fl_engine_set_update_semantics_handler(self->engine, update_semantics_cb, - self, nullptr); - fl_engine_set_on_pre_engine_restart_handler( - self->engine, on_pre_engine_restart_cb, self, nullptr); + fl_renderer_gdk_set_window(self->renderer, + gtk_widget_get_parent_window(GTK_WIDGET(self))); // Must initialize the keymap before the keyboard. self->keymap = gdk_keymap_get_for_display(gdk_display_get_default()); @@ -654,6 +649,17 @@ static void size_allocate_cb(FlView* self) { handle_geometry_changed(self); } +static void fl_view_constructed(GObject* object) { + FlView* self = FL_VIEW(object); + + self->renderer = fl_renderer_gdk_new(); + self->engine = fl_engine_new(self->project, FL_RENDERER(self->renderer)); + fl_engine_set_update_semantics_handler(self->engine, update_semantics_cb, + self, nullptr); + fl_engine_set_on_pre_engine_restart_handler( + self->engine, on_pre_engine_restart_cb, self, nullptr); +} + static void fl_view_set_property(GObject* object, guint prop_id, const GValue* value, @@ -750,6 +756,7 @@ static gboolean fl_view_key_release_event(GtkWidget* widget, static void fl_view_class_init(FlViewClass* klass) { GObjectClass* object_class = G_OBJECT_CLASS(klass); + object_class->constructed = fl_view_constructed; object_class->set_property = fl_view_set_property; object_class->get_property = fl_view_get_property; object_class->notify = fl_view_notify; diff --git a/engine/src/flutter/shell/platform/linux/fl_view_test.cc b/engine/src/flutter/shell/platform/linux/fl_view_test.cc index c36323cb04..db87bf8b2f 100644 --- a/engine/src/flutter/shell/platform/linux/fl_view_test.cc +++ b/engine/src/flutter/shell/platform/linux/fl_view_test.cc @@ -7,6 +7,19 @@ #include "gtest/gtest.h" +TEST(FlViewTest, GetEngine) { + flutter::testing::fl_ensure_gtk_init(); + g_autoptr(FlDartProject) project = fl_dart_project_new(); + g_autoptr(FlView) view = fl_view_new(project); + + // Check the engine is immediately available (i.e. before the widget is + // realized). + FlEngine* engine = fl_view_get_engine(view); + EXPECT_NE(engine, nullptr); + + g_object_ref_sink(view); +} + TEST(FlViewTest, StateUpdateDoesNotHappenInInit) { flutter::testing::fl_ensure_gtk_init(); g_autoptr(FlDartProject) project = fl_dart_project_new(); diff --git a/engine/src/flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h b/engine/src/flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h index 4ac81862ed..bdff02d40d 100644 --- a/engine/src/flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h +++ b/engine/src/flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h @@ -104,6 +104,8 @@ struct _FlBinaryMessengerInterface { void (*set_warns_on_channel_overflow)(FlBinaryMessenger* messenger, const gchar* channel, bool warns); + + void (*shutdown)(FlBinaryMessenger* messenger); }; struct _FlBinaryMessengerResponseHandleClass { diff --git a/engine/src/flutter/shell/platform/linux/public/flutter_linux/fl_texture_registrar.h b/engine/src/flutter/shell/platform/linux/public/flutter_linux/fl_texture_registrar.h index 0034d345e9..291f1644be 100644 --- a/engine/src/flutter/shell/platform/linux/public/flutter_linux/fl_texture_registrar.h +++ b/engine/src/flutter/shell/platform/linux/public/flutter_linux/fl_texture_registrar.h @@ -37,6 +37,8 @@ struct _FlTextureRegistrarInterface { gboolean (*unregister_texture)(FlTextureRegistrar* registrar, FlTexture* texture); + + void (*shutdown)(FlTextureRegistrar* registrar); }; /** diff --git a/engine/src/flutter/shell/platform/linux/testing/mock_binary_messenger.cc b/engine/src/flutter/shell/platform/linux/testing/mock_binary_messenger.cc index ac1b05af33..8b22f2291b 100644 --- a/engine/src/flutter/shell/platform/linux/testing/mock_binary_messenger.cc +++ b/engine/src/flutter/shell/platform/linux/testing/mock_binary_messenger.cc @@ -141,6 +141,8 @@ static void fl_mock_binary_messenger_set_warns_on_channel_overflow( channel, warns); } +static void fl_mock_binary_messenger_shutdown(FlBinaryMessenger* messenger) {} + static void fl_mock_binary_messenger_iface_init( FlBinaryMessengerInterface* iface) { iface->set_message_handler_on_channel = @@ -152,6 +154,7 @@ static void fl_mock_binary_messenger_iface_init( iface->resize_channel = fl_mock_binary_messenger_resize_channel; iface->set_warns_on_channel_overflow = fl_mock_binary_messenger_set_warns_on_channel_overflow; + iface->shutdown = fl_mock_binary_messenger_shutdown; } static void fl_mock_binary_messenger_init(FlMockBinaryMessenger* self) {}