mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Implement settings channel for the Linux shell (flutter/engine#22486)
Implement settings channel for the Linux shell Fixes https://github.com/flutter/flutter/issues/65591
This commit is contained in:
parent
67ffbc11be
commit
ae52e3b83c
@ -2134,6 +2134,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
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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 =
|
||||
|
||||
@ -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(
|
||||
@ -434,6 +437,9 @@ 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;
|
||||
}
|
||||
|
||||
|
||||
@ -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<size_t>(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);
|
||||
}
|
||||
|
||||
120
engine/src/flutter/shell/platform/linux/fl_settings_plugin.cc
Normal file
120
engine/src/flutter/shell/platform/linux/fl_settings_plugin.cc
Normal file
@ -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 <cstring>
|
||||
|
||||
#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);
|
||||
}
|
||||
45
engine/src/flutter/shell/platform/linux/fl_settings_plugin.h
Normal file
45
engine/src/flutter/shell/platform/linux/fl_settings_plugin.h
Normal file
@ -0,0 +1,45 @@
|
||||
// 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 the Flutter user settings
|
||||
* channel.
|
||||
*/
|
||||
|
||||
/**
|
||||
* fl_settings_plugin_new:
|
||||
* @messenger: an #FlBinaryMessenger
|
||||
*
|
||||
* Creates a new plugin that sends user settings to the Flutter engine.
|
||||
*
|
||||
* 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_
|
||||
Loading…
x
Reference in New Issue
Block a user