From dbc9275000918df328aef2c595eb0fb68f28b9e5 Mon Sep 17 00:00:00 2001 From: Robert Ancell Date: Wed, 11 Nov 2020 14:34:07 +1300 Subject: [PATCH 1/7] Implement settings channel for the Linux shell Fixes https://github.com/flutter/flutter/issues/65591 --- ci/licenses_golden/licenses_flutter | 2 + shell/platform/linux/BUILD.gn | 1 + shell/platform/linux/fl_settings_plugin.cc | 120 +++++++++++++++++++++ shell/platform/linux/fl_settings_plugin.h | 44 ++++++++ shell/platform/linux/fl_view.cc | 6 ++ 5 files changed, 173 insertions(+) create mode 100644 shell/platform/linux/fl_settings_plugin.cc create mode 100644 shell/platform/linux/fl_settings_plugin.h diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 93948761cd3b5..447003acddc95 100755 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1345,6 +1345,8 @@ FILE: ../../../flutter/shell/platform/linux/fl_renderer_wayland.cc FILE: ../../../flutter/shell/platform/linux/fl_renderer_wayland.h FILE: ../../../flutter/shell/platform/linux/fl_renderer_x11.cc FILE: ../../../flutter/shell/platform/linux/fl_renderer_x11.h +FILE: ../../../flutter/shell/platform/linux/fl_settings_plugin.cc +FILE: ../../../flutter/shell/platform/linux/fl_settings_plugin.h FILE: ../../../flutter/shell/platform/linux/fl_standard_message_codec.cc FILE: ../../../flutter/shell/platform/linux/fl_standard_message_codec_private.h FILE: ../../../flutter/shell/platform/linux/fl_standard_message_codec_test.cc diff --git a/shell/platform/linux/BUILD.gn b/shell/platform/linux/BUILD.gn index 6dcc1779f1930..f41ec44f9e9ed 100644 --- a/shell/platform/linux/BUILD.gn +++ b/shell/platform/linux/BUILD.gn @@ -110,6 +110,7 @@ source_set("flutter_linux_sources") { "fl_renderer_headless.cc", "fl_renderer_wayland.cc", "fl_renderer_x11.cc", + "fl_settings_plugin.cc", "fl_standard_message_codec.cc", "fl_standard_method_codec.cc", "fl_string_codec.cc", diff --git a/shell/platform/linux/fl_settings_plugin.cc b/shell/platform/linux/fl_settings_plugin.cc new file mode 100644 index 0000000000000..446ae9751c96c --- /dev/null +++ b/shell/platform/linux/fl_settings_plugin.cc @@ -0,0 +1,120 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/platform/linux/fl_settings_plugin.h" + +#include + +#include "flutter/shell/platform/linux/public/flutter_linux/fl_basic_message_channel.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_json_message_codec.h" + +static constexpr char kChannelName[] = "flutter/settings"; +static constexpr char kTextScaleFactorKey[] = "textScaleFactor"; +static constexpr char kAlwaysUse24HourFormatKey[] = "alwaysUse24HourFormat"; +static constexpr char kPlatformBrightnessKey[] = "platformBrightness"; +static constexpr char kPlatformBrightnessLight[] = "light"; +static constexpr char kPlatformBrightnessDark[] = "dark"; + +static constexpr char kDesktopInterfaceSchema[] = "org.gnome.desktop.interface"; +static constexpr char kDesktopGtkThemeKey[] = "gtk-theme"; +static constexpr char kDesktopTextScalingFactorKey[] = "text-scaling-factor"; +static constexpr char kDesktopClockFormatKey[] = "clock-format"; +static constexpr char kClockFormat24Hour[] = "24h"; + +struct _FlSettingsPlugin { + GObject parent_instance; + + FlBasicMessageChannel* channel; + + GSettings* interface_settings; +}; + +G_DEFINE_TYPE(FlSettingsPlugin, fl_settings_plugin, G_TYPE_OBJECT) + +// Sends the current settings to the Flutter engine. +static void update_settings(FlSettingsPlugin* self) { + gdouble scaling_factor = 1.0; + gboolean always_use_24hr = FALSE; + const gchar* platform_brightness = kPlatformBrightnessLight; + + if (self->interface_settings != nullptr) { + scaling_factor = g_settings_get_double(self->interface_settings, + kDesktopTextScalingFactorKey); + g_autofree gchar* clock_format = + g_settings_get_string(self->interface_settings, kDesktopClockFormatKey); + always_use_24hr = g_strcmp0(clock_format, kClockFormat24Hour) == 0; + + // GTK doesn't have a specific flag for dark themes, so we have some + // hard-coded themes for Ubuntu (Yaru) and GNOME (Adwaita). + g_autofree gchar* gtk_theme = + g_settings_get_string(self->interface_settings, kDesktopGtkThemeKey); + if (g_strcmp0(gtk_theme, "Yaru-dark") == 0 || + g_strcmp0(gtk_theme, "Adwaita-dark") == 0) { + platform_brightness = kPlatformBrightnessDark; + } + } + + g_autoptr(FlValue) message = fl_value_new_map(); + fl_value_set_string_take(message, kTextScaleFactorKey, + fl_value_new_float(scaling_factor)); + fl_value_set_string_take(message, kAlwaysUse24HourFormatKey, + fl_value_new_bool(always_use_24hr)); + fl_value_set_string_take(message, kPlatformBrightnessKey, + fl_value_new_string(platform_brightness)); + fl_basic_message_channel_send(self->channel, message, nullptr, nullptr, + nullptr); +} + +static void fl_settings_plugin_dispose(GObject* object) { + FlSettingsPlugin* self = FL_SETTINGS_PLUGIN(object); + + g_clear_object(&self->channel); + g_clear_object(&self->interface_settings); + + G_OBJECT_CLASS(fl_settings_plugin_parent_class)->dispose(object); +} + +static void fl_settings_plugin_class_init(FlSettingsPluginClass* klass) { + G_OBJECT_CLASS(klass)->dispose = fl_settings_plugin_dispose; +} + +static void fl_settings_plugin_init(FlSettingsPlugin* self) {} + +FlSettingsPlugin* fl_settings_plugin_new(FlBinaryMessenger* messenger) { + g_return_val_if_fail(FL_IS_BINARY_MESSENGER(messenger), nullptr); + + FlSettingsPlugin* self = + FL_SETTINGS_PLUGIN(g_object_new(fl_settings_plugin_get_type(), nullptr)); + + g_autoptr(FlJsonMessageCodec) codec = fl_json_message_codec_new(); + self->channel = fl_basic_message_channel_new(messenger, kChannelName, + FL_MESSAGE_CODEC(codec)); + + return self; +} + +void fl_settings_plugin_start(FlSettingsPlugin* self) { + g_return_if_fail(FL_IS_SETTINGS_PLUGIN(self)); + + // If we are on GNOME, get settings from GSettings. + GSettingsSchemaSource* source = g_settings_schema_source_get_default(); + if (source != nullptr) { + g_autoptr(GSettingsSchema) schema = + g_settings_schema_source_lookup(source, kDesktopInterfaceSchema, FALSE); + if (schema != nullptr) { + self->interface_settings = g_settings_new_full(schema, nullptr, nullptr); + g_signal_connect_object( + self->interface_settings, "changed::text-scaling-factor", + G_CALLBACK(update_settings), self, G_CONNECT_SWAPPED); + g_signal_connect_object(self->interface_settings, "changed::clock-format", + G_CALLBACK(update_settings), self, + G_CONNECT_SWAPPED); + g_signal_connect_object(self->interface_settings, "changed::gtk-theme", + G_CALLBACK(update_settings), self, + G_CONNECT_SWAPPED); + } + } + + update_settings(self); +} diff --git a/shell/platform/linux/fl_settings_plugin.h b/shell/platform/linux/fl_settings_plugin.h new file mode 100644 index 0000000000000..4583f1a08da42 --- /dev/null +++ b/shell/platform/linux/fl_settings_plugin.h @@ -0,0 +1,44 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_LINUX_FL_SETTINGS_PLUGIN_H_ +#define FLUTTER_SHELL_PLATFORM_LINUX_FL_SETTINGS_PLUGIN_H_ + +#include "flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h" + +G_BEGIN_DECLS + +G_DECLARE_FINAL_TYPE(FlSettingsPlugin, + fl_settings_plugin, + FL, + SETTINGS_PLUGIN, + GObject); + +/** + * FlSettingsPlugin: + * + * #FlSettingsPlugin is a plugin that implements FIXME. + */ + +/** + * fl_settings_plugin_new: + * @messenger: an #FlBinaryMessenger + * + * Creates a new plugin that implements FIXME. + * + * Returns: a new #FlSettingsPlugin + */ +FlSettingsPlugin* fl_settings_plugin_new(FlBinaryMessenger* messenger); + +/** + * fl_settings_plugin_start: + * @self: an #FlSettingsPlugin. + * + * Sends the current settings to the engine and updates when they change. + */ +void fl_settings_plugin_start(FlSettingsPlugin* plugin); + +G_END_DECLS + +#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_SETTINGS_PLUGIN_H_ diff --git a/shell/platform/linux/fl_view.cc b/shell/platform/linux/fl_view.cc index 87decdce97c88..f2f167659a68c 100644 --- a/shell/platform/linux/fl_view.cc +++ b/shell/platform/linux/fl_view.cc @@ -17,6 +17,7 @@ #include "flutter/shell/platform/linux/fl_plugin_registrar_private.h" #include "flutter/shell/platform/linux/fl_renderer_wayland.h" #include "flutter/shell/platform/linux/fl_renderer_x11.h" +#include "flutter/shell/platform/linux/fl_settings_plugin.h" #include "flutter/shell/platform/linux/fl_text_input_plugin.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_engine.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_plugin_registry.h" @@ -42,6 +43,7 @@ struct _FlView { FlKeyEventPlugin* key_event_plugin; FlMouseCursorPlugin* mouse_cursor_plugin; FlPlatformPlugin* platform_plugin; + FlSettingsPlugin* settings_plugin; FlTextInputPlugin* text_input_plugin; }; @@ -161,6 +163,7 @@ static void fl_view_constructed(GObject* object) { self->key_event_plugin = fl_key_event_plugin_new(messenger); self->mouse_cursor_plugin = fl_mouse_cursor_plugin_new(messenger, self); self->platform_plugin = fl_platform_plugin_new(messenger); + self->settings_plugin = fl_settings_plugin_new(messenger); self->text_input_plugin = fl_text_input_plugin_new(messenger, self); } @@ -218,6 +221,7 @@ static void fl_view_dispose(GObject* object) { g_clear_object(&self->key_event_plugin); g_clear_object(&self->mouse_cursor_plugin); g_clear_object(&self->platform_plugin); + g_clear_object(&self->settings_plugin); g_clear_object(&self->text_input_plugin); G_OBJECT_CLASS(fl_view_parent_class)->dispose(object); @@ -239,6 +243,8 @@ static void fl_view_realize(GtkWidget* widget) { g_warning("Failed to start Flutter engine: %s", error->message); return; } + + fl_settings_plugin_start(self->settings_plugin); } // Implements GtkWidget::size-allocate. From 072cb22e67d002985213cd328a70f1880f6c1968 Mon Sep 17 00:00:00 2001 From: Robert Ancell Date: Fri, 20 Nov 2020 15:55:30 +1300 Subject: [PATCH 2/7] Fill documentation for fl_settings_plugin_new --- shell/platform/linux/fl_settings_plugin.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell/platform/linux/fl_settings_plugin.h b/shell/platform/linux/fl_settings_plugin.h index 4583f1a08da42..4cd6a4b040694 100644 --- a/shell/platform/linux/fl_settings_plugin.h +++ b/shell/platform/linux/fl_settings_plugin.h @@ -25,7 +25,7 @@ G_DECLARE_FINAL_TYPE(FlSettingsPlugin, * fl_settings_plugin_new: * @messenger: an #FlBinaryMessenger * - * Creates a new plugin that implements FIXME. + * Creates a new plugin that sends user settings to the Flutter engine. * * Returns: a new #FlSettingsPlugin */ From 7dfb8769d2623e357dce274f4cd67f0959893194 Mon Sep 17 00:00:00 2001 From: Robert Ancell Date: Fri, 4 Dec 2020 10:25:12 +1300 Subject: [PATCH 3/7] Complete docstring --- shell/platform/linux/fl_settings_plugin.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/shell/platform/linux/fl_settings_plugin.h b/shell/platform/linux/fl_settings_plugin.h index 4cd6a4b040694..26c146880d4cb 100644 --- a/shell/platform/linux/fl_settings_plugin.h +++ b/shell/platform/linux/fl_settings_plugin.h @@ -18,7 +18,8 @@ G_DECLARE_FINAL_TYPE(FlSettingsPlugin, /** * FlSettingsPlugin: * - * #FlSettingsPlugin is a plugin that implements FIXME. + * #FlSettingsPlugin is a plugin that implements the Flutter user settings + * channel. */ /** From 6a60cf6c9dbad0703da68d6242cf558b0e3fd7d9 Mon Sep 17 00:00:00 2001 From: Robert Ancell Date: Fri, 4 Dec 2020 10:55:08 +1300 Subject: [PATCH 4/7] Add engine tests for Linux shell --- ci/licenses_golden/licenses_flutter | 1 + shell/platform/linux/BUILD.gn | 1 + shell/platform/linux/fl_engine_test.cc | 139 +++++++++++++++++++++++++ 3 files changed, 141 insertions(+) create mode 100644 shell/platform/linux/fl_engine_test.cc diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 14f036ee7a555..b9d66a10966ed 100755 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1314,6 +1314,7 @@ FILE: ../../../flutter/shell/platform/linux/fl_dart_project_private.h FILE: ../../../flutter/shell/platform/linux/fl_dart_project_test.cc FILE: ../../../flutter/shell/platform/linux/fl_engine.cc FILE: ../../../flutter/shell/platform/linux/fl_engine_private.h +FILE: ../../../flutter/shell/platform/linux/fl_engine_test.cc FILE: ../../../flutter/shell/platform/linux/fl_event_channel.cc FILE: ../../../flutter/shell/platform/linux/fl_event_channel_test.cc FILE: ../../../flutter/shell/platform/linux/fl_json_message_codec.cc diff --git a/shell/platform/linux/BUILD.gn b/shell/platform/linux/BUILD.gn index 1357b697f8c42..9e628bcf44396 100644 --- a/shell/platform/linux/BUILD.gn +++ b/shell/platform/linux/BUILD.gn @@ -162,6 +162,7 @@ executable("flutter_linux_unittests") { "fl_binary_codec_test.cc", "fl_binary_messenger_test.cc", "fl_dart_project_test.cc", + "fl_engine_test.cc", "fl_event_channel_test.cc", "fl_json_message_codec_test.cc", "fl_json_method_codec_test.cc", diff --git a/shell/platform/linux/fl_engine_test.cc b/shell/platform/linux/fl_engine_test.cc new file mode 100644 index 0000000000000..5353df74f8182 --- /dev/null +++ b/shell/platform/linux/fl_engine_test.cc @@ -0,0 +1,139 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Included first as it collides with the X11 headers. +#include "gtest/gtest.h" + +#include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h" +#include "flutter/shell/platform/linux/fl_engine_private.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_engine.h" +#include "flutter/shell/platform/linux/testing/fl_test.h" + +// Checks sending window metrics events works. +TEST(FlEngineTest, WindowMetrics) { + g_autoptr(FlEngine) engine = make_mock_engine(); + FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine); + + bool called = false; + embedder_api->SendWindowMetricsEvent = MOCK_ENGINE_PROC( + SendWindowMetricsEvent, + ([&called](auto engine, const FlutterWindowMetricsEvent* event) { + called = true; + EXPECT_EQ(event->width, static_cast(3840)); + EXPECT_EQ(event->height, static_cast(2160)); + EXPECT_EQ(event->pixel_ratio, 2.0); + + return kSuccess; + })); + + g_autoptr(GError) error = nullptr; + EXPECT_TRUE(fl_engine_start(engine, &error)); + EXPECT_EQ(error, nullptr); + fl_engine_send_window_metrics_event(engine, 3840, 2160, 2.0); + + EXPECT_TRUE(called); +} + +// Checks sending mouse pointer events works. +TEST(FlEngineTest, MousePointer) { + g_autoptr(FlEngine) engine = make_mock_engine(); + FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine); + + bool called = false; + embedder_api->SendPointerEvent = MOCK_ENGINE_PROC( + SendPointerEvent, + ([&called](auto engine, const FlutterPointerEvent* events, + size_t events_count) { + called = true; + EXPECT_EQ(events_count, static_cast(1)); + EXPECT_EQ(events[0].phase, kDown); + EXPECT_EQ(events[0].timestamp, static_cast(1234567890)); + EXPECT_EQ(events[0].x, 800); + EXPECT_EQ(events[0].y, 600); + EXPECT_EQ(events[0].device, static_cast(0)); + EXPECT_EQ(events[0].signal_kind, kFlutterPointerSignalKindScroll); + EXPECT_EQ(events[0].scroll_delta_x, 1.2); + EXPECT_EQ(events[0].scroll_delta_y, -3.4); + EXPECT_EQ(events[0].device_kind, kFlutterPointerDeviceKindMouse); + EXPECT_EQ(events[0].buttons, kFlutterPointerButtonMouseSecondary); + + return kSuccess; + })); + + g_autoptr(GError) error = nullptr; + EXPECT_TRUE(fl_engine_start(engine, &error)); + EXPECT_EQ(error, nullptr); + fl_engine_send_mouse_pointer_event(engine, kDown, 1234567890, 800, 600, 1.2, + -3.4, kFlutterPointerButtonMouseSecondary); + + EXPECT_TRUE(called); +} + +// Checks sending platform messages works. +TEST(FlEngineTest, PlatformMessage) { + g_autoptr(FlEngine) engine = make_mock_engine(); + FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine); + + bool called = false; + embedder_api->SendPlatformMessage = MOCK_ENGINE_PROC( + SendPlatformMessage, + ([&called](auto engine, const FlutterPlatformMessage* message) { + called = true; + + EXPECT_STREQ(message->channel, "test"); + EXPECT_EQ(message->message_size, static_cast(4)); + EXPECT_EQ(message->message[0], 't'); + EXPECT_EQ(message->message[1], 'e'); + EXPECT_EQ(message->message[2], 's'); + EXPECT_EQ(message->message[3], 't'); + + return kSuccess; + })); + + g_autoptr(GError) error = nullptr; + EXPECT_TRUE(fl_engine_start(engine, &error)); + EXPECT_EQ(error, nullptr); + g_autoptr(GBytes) message = g_bytes_new_static("test", 4); + fl_engine_send_platform_message(engine, "test", message, nullptr, nullptr, + nullptr); + + EXPECT_TRUE(called); +} + +// Checks sending platform message responses works. +TEST(FlEngineTest, PlatformMessageResponse) { + g_autoptr(FlEngine) engine = make_mock_engine(); + FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine); + + bool called = false; + embedder_api->SendPlatformMessageResponse = MOCK_ENGINE_PROC( + SendPlatformMessageResponse, + ([&called](auto engine, + const FlutterPlatformMessageResponseHandle* handle, + const uint8_t* data, size_t data_length) { + called = true; + + EXPECT_EQ( + handle, + reinterpret_cast(42)); + EXPECT_EQ(data_length, static_cast(4)); + EXPECT_EQ(data[0], 't'); + EXPECT_EQ(data[1], 'e'); + EXPECT_EQ(data[2], 's'); + EXPECT_EQ(data[3], 't'); + + return kSuccess; + })); + + g_autoptr(GError) error = nullptr; + EXPECT_TRUE(fl_engine_start(engine, &error)); + EXPECT_EQ(error, nullptr); + g_autoptr(GBytes) response = g_bytes_new_static("test", 4); + EXPECT_TRUE(fl_engine_send_platform_message_response( + engine, reinterpret_cast(42), + response, &error)); + EXPECT_EQ(error, nullptr); + + EXPECT_TRUE(called); +} From 37f03062b768750e273474d64581bd0d4624ba1b Mon Sep 17 00:00:00 2001 From: Robert Ancell Date: Mon, 7 Dec 2020 15:40:41 +1300 Subject: [PATCH 5/7] Move settings plugin to FlEngine --- shell/platform/linux/fl_engine.cc | 5 +++++ shell/platform/linux/fl_view.cc | 6 ------ 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/shell/platform/linux/fl_engine.cc b/shell/platform/linux/fl_engine.cc index a5a05eb759095..ff7e5bc3ce9f9 100644 --- a/shell/platform/linux/fl_engine.cc +++ b/shell/platform/linux/fl_engine.cc @@ -14,6 +14,7 @@ #include "flutter/shell/platform/linux/fl_plugin_registrar_private.h" #include "flutter/shell/platform/linux/fl_renderer.h" #include "flutter/shell/platform/linux/fl_renderer_headless.h" +#include "flutter/shell/platform/linux/fl_settings_plugin.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_plugin_registry.h" static constexpr int kMicrosecondsPerNanosecond = 1000; @@ -30,6 +31,7 @@ struct _FlEngine { FlDartProject* project; FlRenderer* renderer; FlBinaryMessenger* binary_messenger; + FlSettingsPlugin* settings_plugin; FlutterEngineAOTData aot_data; FLUTTER_API_SYMBOL(FlutterEngine) engine; FlutterEngineProcTable embedder_api; @@ -315,6 +317,7 @@ static void fl_engine_dispose(GObject* object) { g_clear_object(&self->project); g_clear_object(&self->renderer); g_clear_object(&self->binary_messenger); + g_clear_object(&self->settings_plugin); if (self->platform_message_handler_destroy_notify) { self->platform_message_handler_destroy_notify( @@ -337,6 +340,7 @@ static void fl_engine_init(FlEngine* self) { FlutterEngineGetProcAddresses(&self->embedder_api); self->binary_messenger = fl_binary_messenger_new(self); + self->settings_plugin = fl_settings_plugin_new(self->binary_messenger); } FlEngine* fl_engine_new(FlDartProject* project, FlRenderer* renderer) { @@ -433,6 +437,7 @@ gboolean fl_engine_start(FlEngine* self, GError** error) { } setup_locales(self); + fl_settings_plugin_start(self->settings_plugin); return TRUE; } diff --git a/shell/platform/linux/fl_view.cc b/shell/platform/linux/fl_view.cc index 5963b389e865f..cde22c27ce61b 100644 --- a/shell/platform/linux/fl_view.cc +++ b/shell/platform/linux/fl_view.cc @@ -17,7 +17,6 @@ #include "flutter/shell/platform/linux/fl_plugin_registrar_private.h" #include "flutter/shell/platform/linux/fl_renderer_wayland.h" #include "flutter/shell/platform/linux/fl_renderer_x11.h" -#include "flutter/shell/platform/linux/fl_settings_plugin.h" #include "flutter/shell/platform/linux/fl_text_input_plugin.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_engine.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_plugin_registry.h" @@ -43,7 +42,6 @@ struct _FlView { FlKeyEventPlugin* key_event_plugin; FlMouseCursorPlugin* mouse_cursor_plugin; FlPlatformPlugin* platform_plugin; - FlSettingsPlugin* settings_plugin; FlTextInputPlugin* text_input_plugin; }; @@ -164,7 +162,6 @@ static void fl_view_constructed(GObject* object) { fl_key_event_plugin_new(messenger, self->text_input_plugin); self->mouse_cursor_plugin = fl_mouse_cursor_plugin_new(messenger, self); self->platform_plugin = fl_platform_plugin_new(messenger); - self->settings_plugin = fl_settings_plugin_new(messenger); self->text_input_plugin = fl_text_input_plugin_new(messenger, self); } @@ -222,7 +219,6 @@ static void fl_view_dispose(GObject* object) { g_clear_object(&self->key_event_plugin); g_clear_object(&self->mouse_cursor_plugin); g_clear_object(&self->platform_plugin); - g_clear_object(&self->settings_plugin); g_clear_object(&self->text_input_plugin); G_OBJECT_CLASS(fl_view_parent_class)->dispose(object); @@ -244,8 +240,6 @@ static void fl_view_realize(GtkWidget* widget) { g_warning("Failed to start Flutter engine: %s", error->message); return; } - - fl_settings_plugin_start(self->settings_plugin); } // Implements GtkWidget::size-allocate. From c0f366748c4994b7a6b3fc438a2deebda43b0aab Mon Sep 17 00:00:00 2001 From: Robert Ancell Date: Wed, 9 Dec 2020 11:00:51 +1300 Subject: [PATCH 6/7] Add settings plugin tests --- .../linux/fl_basic_message_channel_test.cc | 10 +++- shell/platform/linux/fl_engine.cc | 3 +- shell/platform/linux/fl_engine_test.cc | 60 ++++++++++++++++++- shell/platform/linux/fl_view.cc | 2 +- 4 files changed, 69 insertions(+), 6 deletions(-) diff --git a/shell/platform/linux/fl_basic_message_channel_test.cc b/shell/platform/linux/fl_basic_message_channel_test.cc index 91ac762f9d53e..a806a8c81aaa6 100644 --- a/shell/platform/linux/fl_basic_message_channel_test.cc +++ b/shell/platform/linux/fl_basic_message_channel_test.cc @@ -24,11 +24,17 @@ TEST(FlBasicMessageChannelTest, SendMessageWithoutResponse) { FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine); bool called = false; + FlutterEngineSendPlatformMessageFnPtr old_handler = + embedder_api->SendPlatformMessage; embedder_api->SendPlatformMessage = MOCK_ENGINE_PROC( SendPlatformMessage, - ([&called](auto engine, const FlutterPlatformMessage* message) { + ([&called, old_handler](auto engine, + const FlutterPlatformMessage* message) { + if (strcmp(message->channel, "test") != 0) { + return old_handler(engine, message); + } + called = true; - EXPECT_STREQ(message->channel, "test"); EXPECT_EQ(message->response_handle, nullptr); g_autoptr(GBytes) message_bytes = diff --git a/shell/platform/linux/fl_engine.cc b/shell/platform/linux/fl_engine.cc index ff7e5bc3ce9f9..741a5fa0ae5de 100644 --- a/shell/platform/linux/fl_engine.cc +++ b/shell/platform/linux/fl_engine.cc @@ -340,7 +340,6 @@ static void fl_engine_init(FlEngine* self) { FlutterEngineGetProcAddresses(&self->embedder_api); self->binary_messenger = fl_binary_messenger_new(self); - self->settings_plugin = fl_settings_plugin_new(self->binary_messenger); } FlEngine* fl_engine_new(FlDartProject* project, FlRenderer* renderer) { @@ -437,6 +436,8 @@ gboolean fl_engine_start(FlEngine* self, GError** error) { } setup_locales(self); + + self->settings_plugin = fl_settings_plugin_new(self->binary_messenger); fl_settings_plugin_start(self->settings_plugin); return TRUE; diff --git a/shell/platform/linux/fl_engine_test.cc b/shell/platform/linux/fl_engine_test.cc index 5353df74f8182..418f151899e18 100644 --- a/shell/platform/linux/fl_engine_test.cc +++ b/shell/platform/linux/fl_engine_test.cc @@ -8,6 +8,7 @@ #include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h" #include "flutter/shell/platform/linux/fl_engine_private.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_engine.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_json_message_codec.h" #include "flutter/shell/platform/linux/testing/fl_test.h" // Checks sending window metrics events works. @@ -76,12 +77,18 @@ TEST(FlEngineTest, PlatformMessage) { FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine); bool called = false; + FlutterEngineSendPlatformMessageFnPtr old_handler = + embedder_api->SendPlatformMessage; embedder_api->SendPlatformMessage = MOCK_ENGINE_PROC( SendPlatformMessage, - ([&called](auto engine, const FlutterPlatformMessage* message) { + ([&called, old_handler](auto engine, + const FlutterPlatformMessage* message) { + if (strcmp(message->channel, "test") != 0) { + return old_handler(engine, message); + } + called = true; - EXPECT_STREQ(message->channel, "test"); EXPECT_EQ(message->message_size, static_cast(4)); EXPECT_EQ(message->message[0], 't'); EXPECT_EQ(message->message[1], 'e'); @@ -137,3 +144,52 @@ TEST(FlEngineTest, PlatformMessageResponse) { EXPECT_TRUE(called); } + +// Checks settings plugin sends settings on startup. +TEST(FlEngineTest, SettingsPlugin) { + g_autoptr(FlEngine) engine = make_mock_engine(); + FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine); + + bool called = false; + embedder_api->SendPlatformMessage = MOCK_ENGINE_PROC( + SendPlatformMessage, + ([&called](auto engine, const FlutterPlatformMessage* message) { + called = true; + + EXPECT_STREQ(message->channel, "flutter/settings"); + + g_autoptr(FlJsonMessageCodec) codec = fl_json_message_codec_new(); + g_autoptr(GBytes) data = + g_bytes_new(message->message, message->message_size); + g_autoptr(GError) error = nullptr; + g_autoptr(FlValue) settings = fl_message_codec_decode_message( + FL_MESSAGE_CODEC(codec), data, &error); + EXPECT_NE(settings, nullptr); + EXPECT_EQ(error, nullptr); + g_printerr("%s\n", fl_value_to_string(settings)); + + g_autoptr(FlValue) text_scale_factor = + fl_value_lookup_string(settings, "textScaleFactor"); + EXPECT_NE(text_scale_factor, nullptr); + EXPECT_EQ(fl_value_get_type(text_scale_factor), FL_VALUE_TYPE_FLOAT); + + g_autoptr(FlValue) always_use_24hr_format = + fl_value_lookup_string(settings, "alwaysUse24HourFormat"); + EXPECT_NE(always_use_24hr_format, nullptr); + EXPECT_EQ(fl_value_get_type(always_use_24hr_format), + FL_VALUE_TYPE_BOOL); + + g_autoptr(FlValue) platform_brightness = + fl_value_lookup_string(settings, "platformBrightness"); + EXPECT_NE(platform_brightness, nullptr); + EXPECT_EQ(fl_value_get_type(platform_brightness), FL_VALUE_TYPE_STRING); + + return kSuccess; + })); + + g_autoptr(GError) error = nullptr; + EXPECT_TRUE(fl_engine_start(engine, &error)); + EXPECT_EQ(error, nullptr); + + EXPECT_TRUE(called); +} diff --git a/shell/platform/linux/fl_view.cc b/shell/platform/linux/fl_view.cc index cde22c27ce61b..6f1565e9bcf0c 100644 --- a/shell/platform/linux/fl_view.cc +++ b/shell/platform/linux/fl_view.cc @@ -158,11 +158,11 @@ static void fl_view_constructed(GObject* object) { // Create system channel handlers. FlBinaryMessenger* messenger = fl_engine_get_binary_messenger(self->engine); + self->text_input_plugin = fl_text_input_plugin_new(messenger, self); self->key_event_plugin = fl_key_event_plugin_new(messenger, self->text_input_plugin); self->mouse_cursor_plugin = fl_mouse_cursor_plugin_new(messenger, self); self->platform_plugin = fl_platform_plugin_new(messenger); - self->text_input_plugin = fl_text_input_plugin_new(messenger, self); } static void fl_view_set_property(GObject* object, From 84f371ccf453ba6193aa753a10d070c004995f37 Mon Sep 17 00:00:00 2001 From: Robert Ancell Date: Tue, 5 Jan 2021 10:44:14 +1300 Subject: [PATCH 7/7] Fix test change not merged in correctly --- shell/platform/linux/fl_engine_test.cc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/shell/platform/linux/fl_engine_test.cc b/shell/platform/linux/fl_engine_test.cc index b4bc21ea79fc8..418f151899e18 100644 --- a/shell/platform/linux/fl_engine_test.cc +++ b/shell/platform/linux/fl_engine_test.cc @@ -77,12 +77,18 @@ TEST(FlEngineTest, PlatformMessage) { FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine); bool called = false; + FlutterEngineSendPlatformMessageFnPtr old_handler = + embedder_api->SendPlatformMessage; embedder_api->SendPlatformMessage = MOCK_ENGINE_PROC( SendPlatformMessage, - ([&called](auto engine, const FlutterPlatformMessage* message) { + ([&called, old_handler](auto engine, + const FlutterPlatformMessage* message) { + if (strcmp(message->channel, "test") != 0) { + return old_handler(engine, message); + } + called = true; - EXPECT_STREQ(message->channel, "test"); EXPECT_EQ(message->message_size, static_cast(4)); EXPECT_EQ(message->message[0], 't'); EXPECT_EQ(message->message[1], 'e');