Flutter Engine
The Flutter Engine
fl_settings_portal.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#include "flutter/shell/platform/linux/fl_settings_portal.h"
6
7#include <gio/gio.h>
8#include <glib.h>
9
10static constexpr char kPortalName[] = "org.freedesktop.portal.Desktop";
11static constexpr char kPortalPath[] = "/org/freedesktop/portal/desktop";
12static constexpr char kPortalSettings[] = "org.freedesktop.portal.Settings";
13
14struct FlSetting {
15 const gchar* ns;
16 const gchar* key;
17 const GVariantType* type;
18};
19
20static constexpr char kXdgAppearance[] = "org.freedesktop.appearance";
21static const FlSetting kColorScheme = {
23 "color-scheme",
24 G_VARIANT_TYPE_UINT32,
25};
26
27static constexpr char kGnomeA11yInterface[] =
28 "org.gnome.desktop.a11y.interface";
29static const FlSetting kHighContrast = {
31 "high-contrast",
32 G_VARIANT_TYPE_BOOLEAN,
33};
34
35static constexpr char kGnomeDesktopInterface[] = "org.gnome.desktop.interface";
36static const FlSetting kClockFormat = {
38 "clock-format",
39 G_VARIANT_TYPE_STRING,
40};
43 "enable-animations",
44 G_VARIANT_TYPE_BOOLEAN,
45};
46static const FlSetting kGtkTheme = {
48 "gtk-theme",
49 G_VARIANT_TYPE_STRING,
50};
53 "text-scaling-factor",
54 G_VARIANT_TYPE_DOUBLE,
55};
56
57static const FlSetting kAllSettings[] = {
60};
61
62static constexpr char kClockFormat12Hour[] = "12h";
63static constexpr char kGtkThemeDarkSuffix[] = "-dark";
64
66
69
70 GDBusProxy* dbus_proxy;
71 GVariantDict* values;
72};
73
74static void fl_settings_portal_iface_init(FlSettingsInterface* iface);
75
76G_DEFINE_TYPE_WITH_CODE(FlSettingsPortal,
77 fl_settings_portal,
78 G_TYPE_OBJECT,
79 G_IMPLEMENT_INTERFACE(fl_settings_get_type(),
81
82static gchar* format_key(const FlSetting* setting) {
83 return g_strconcat(setting->ns, "::", setting->key, nullptr);
84}
85
86static gboolean get_value(FlSettingsPortal* portal,
87 const FlSetting* setting,
88 GVariant** value) {
89 g_autofree const gchar* key = format_key(setting);
90 *value = g_variant_dict_lookup_value(portal->values, key, setting->type);
91 return *value != nullptr;
92}
93
94static void set_value(FlSettingsPortal* portal,
95 const FlSetting* setting,
96 GVariant* value) {
97 g_autofree const gchar* key = format_key(setting);
98
99 // ignore redundant changes from multiple XDG desktop portal backends
100 g_autoptr(GVariant) old_value =
101 g_variant_dict_lookup_value(portal->values, key, nullptr);
102 if (old_value != nullptr && value != nullptr &&
103 g_variant_equal(old_value, value)) {
104 return;
105 }
106
107 g_variant_dict_insert_value(portal->values, key, value);
108 fl_settings_emit_changed(FL_SETTINGS(portal));
109}
110
111// Based on
112// https://gitlab.gnome.org/GNOME/Initiatives/-/wikis/Dark-Style-Preference#other
113static gboolean settings_portal_read(GDBusProxy* proxy,
114 const gchar* ns,
115 const gchar* key,
116 GVariant** out) {
117 g_autoptr(GError) error = nullptr;
118 g_autoptr(GVariant) value =
119 g_dbus_proxy_call_sync(proxy, "Read", g_variant_new("(ss)", ns, key),
120 G_DBUS_CALL_FLAGS_NONE, G_MAXINT, nullptr, &error);
121
122 if (error) {
123 if (error->domain == G_DBUS_ERROR &&
124 error->code == G_DBUS_ERROR_SERVICE_UNKNOWN) {
125 g_debug("XDG desktop portal unavailable: %s", error->message);
126 return false;
127 }
128
129 if (error->domain == G_DBUS_ERROR &&
130 error->code == G_DBUS_ERROR_UNKNOWN_METHOD) {
131 g_debug("XDG desktop portal settings unavailable: %s", error->message);
132 return false;
133 }
134
135 g_critical("Failed to read XDG desktop portal settings: %s",
136 error->message);
137 return false;
138 }
139
140 g_autoptr(GVariant) child = nullptr;
141 g_variant_get(value, "(v)", &child);
142 g_variant_get(child, "v", out);
143
144 return true;
145}
146
147static void settings_portal_changed_cb(GDBusProxy* proxy,
148 const char* sender_name,
149 const char* signal_name,
150 GVariant* parameters,
151 gpointer user_data) {
152 FlSettingsPortal* portal = FL_SETTINGS_PORTAL(user_data);
153 if (g_strcmp0(signal_name, "SettingChanged")) {
154 return;
155 }
156
157 FlSetting setting;
158 g_autoptr(GVariant) value = nullptr;
159 g_variant_get(parameters, "(&s&sv)", &setting.ns, &setting.key, &value);
160 set_value(portal, &setting, value);
161}
162
164 FlSettingsPortal* self = FL_SETTINGS_PORTAL(settings);
165
166 FlClockFormat clock_format = FL_CLOCK_FORMAT_24H;
167
168 g_autoptr(GVariant) value = nullptr;
169 if (get_value(self, &kClockFormat, &value)) {
170 const gchar* clock_format_str = g_variant_get_string(value, nullptr);
171 if (g_strcmp0(clock_format_str, kClockFormat12Hour) == 0) {
172 clock_format = FL_CLOCK_FORMAT_12H;
173 }
174 }
175
176 return clock_format;
177}
178
180 FlSettingsPortal* self = FL_SETTINGS_PORTAL(settings);
181
183
184 g_autoptr(GVariant) value = nullptr;
185 if (get_value(self, &kColorScheme, &value)) {
186 if (g_variant_get_uint32(value) == kPreferDark) {
187 color_scheme = FL_COLOR_SCHEME_DARK;
188 }
189 } else if (get_value(self, &kGtkTheme, &value)) {
190 const gchar* gtk_theme_str = g_variant_get_string(value, nullptr);
191 if (g_str_has_suffix(gtk_theme_str, kGtkThemeDarkSuffix)) {
192 color_scheme = FL_COLOR_SCHEME_DARK;
193 }
194 }
195
196 return color_scheme;
197}
198
200 FlSettingsPortal* self = FL_SETTINGS_PORTAL(settings);
201
202 gboolean enable_animations = true;
203
204 g_autoptr(GVariant) value = nullptr;
206 enable_animations = g_variant_get_boolean(value);
207 }
208
209 return enable_animations;
210}
211
212static gboolean fl_settings_portal_get_high_contrast(FlSettings* settings) {
213 FlSettingsPortal* self = FL_SETTINGS_PORTAL(settings);
214
215 gboolean high_contrast = false;
216
217 g_autoptr(GVariant) value = nullptr;
219 high_contrast = g_variant_get_boolean(value);
220 }
221
222 return high_contrast;
223}
224
226 FlSettings* settings) {
227 FlSettingsPortal* self = FL_SETTINGS_PORTAL(settings);
228
229 gdouble scaling_factor = 1.0;
230
231 g_autoptr(GVariant) value = nullptr;
233 scaling_factor = g_variant_get_double(value);
234 }
235
236 return scaling_factor;
237}
238
239static void fl_settings_portal_dispose(GObject* object) {
240 FlSettingsPortal* self = FL_SETTINGS_PORTAL(object);
241
242 g_clear_object(&self->dbus_proxy);
243 g_clear_pointer(&self->values, g_variant_dict_unref);
244
245 G_OBJECT_CLASS(fl_settings_portal_parent_class)->dispose(object);
246}
247
248static void fl_settings_portal_class_init(FlSettingsPortalClass* klass) {
249 GObjectClass* object_class = G_OBJECT_CLASS(klass);
250 object_class->dispose = fl_settings_portal_dispose;
251}
252
253static void fl_settings_portal_iface_init(FlSettingsInterface* iface) {
254 iface->get_clock_format = fl_settings_portal_get_clock_format;
255 iface->get_color_scheme = fl_settings_portal_get_color_scheme;
256 iface->get_enable_animations = fl_settings_portal_get_enable_animations;
257 iface->get_high_contrast = fl_settings_portal_get_high_contrast;
258 iface->get_text_scaling_factor = fl_settings_portal_get_text_scaling_factor;
259}
260
261static void fl_settings_portal_init(FlSettingsPortal* self) {}
262
263FlSettingsPortal* fl_settings_portal_new() {
264 g_autoptr(GVariantDict) values = g_variant_dict_new(nullptr);
266}
267
268FlSettingsPortal* fl_settings_portal_new_with_values(GVariantDict* values) {
269 g_return_val_if_fail(values != nullptr, nullptr);
270 FlSettingsPortal* portal =
271 FL_SETTINGS_PORTAL(g_object_new(fl_settings_portal_get_type(), nullptr));
272 portal->values = g_variant_dict_ref(values);
273 return portal;
274}
275
276gboolean fl_settings_portal_start(FlSettingsPortal* self, GError** error) {
277 g_return_val_if_fail(FL_IS_SETTINGS_PORTAL(self), false);
278 g_return_val_if_fail(self->dbus_proxy == nullptr, false);
279
280 self->dbus_proxy = g_dbus_proxy_new_for_bus_sync(
281 G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_NONE, nullptr, kPortalName,
283
284 if (self->dbus_proxy == nullptr) {
285 return false;
286 }
287
288 for (const FlSetting setting : kAllSettings) {
289 g_autoptr(GVariant) value = nullptr;
290 if (settings_portal_read(self->dbus_proxy, setting.ns, setting.key,
291 &value)) {
292 set_value(self, &setting, value);
293 }
294 }
295
296 g_signal_connect_object(self->dbus_proxy, "g-signal",
297 G_CALLBACK(settings_portal_changed_cb), self,
298 static_cast<GConnectFlags>(0));
299
300 return true;
301}
const uint8_t uint32_t uint32_t GError ** error
void fl_settings_emit_changed(FlSettings *self)
Definition: fl_settings.cc:50
FlColorScheme
Definition: fl_settings.h:35
@ FL_COLOR_SCHEME_DARK
Definition: fl_settings.h:38
@ FL_COLOR_SCHEME_LIGHT
Definition: fl_settings.h:37
FlClockFormat
Definition: fl_settings.h:21
@ FL_CLOCK_FORMAT_12H
Definition: fl_settings.h:23
@ FL_CLOCK_FORMAT_24H
Definition: fl_settings.h:24
static void fl_settings_portal_class_init(FlSettingsPortalClass *klass)
static gboolean settings_portal_read(GDBusProxy *proxy, const gchar *ns, const gchar *key, GVariant **out)
static constexpr char kGnomeA11yInterface[]
static constexpr char kXdgAppearance[]
static const FlSetting kColorScheme
static gdouble fl_settings_portal_get_text_scaling_factor(FlSettings *settings)
static constexpr char kGnomeDesktopInterface[]
static gboolean get_value(FlSettingsPortal *portal, const FlSetting *setting, GVariant **value)
static void fl_settings_portal_iface_init(FlSettingsInterface *iface)
static void set_value(FlSettingsPortal *portal, const FlSetting *setting, GVariant *value)
static void settings_portal_changed_cb(GDBusProxy *proxy, const char *sender_name, const char *signal_name, GVariant *parameters, gpointer user_data)
static void fl_settings_portal_dispose(GObject *object)
static const FlSetting kAllSettings[]
@ kDefault
@ kPreferDark
@ kPreferLight
static constexpr char kPortalPath[]
static const FlSetting kClockFormat
static void fl_settings_portal_init(FlSettingsPortal *self)
static constexpr char kClockFormat12Hour[]
static const FlSetting kGtkTheme
static const FlSetting kTextScalingFactor
static FlColorScheme fl_settings_portal_get_color_scheme(FlSettings *settings)
static gboolean fl_settings_portal_get_high_contrast(FlSettings *settings)
gboolean fl_settings_portal_start(FlSettingsPortal *self, GError **error)
static const FlSetting kEnableAnimations
static const FlSetting kHighContrast
static constexpr char kGtkThemeDarkSuffix[]
FlSettingsPortal * fl_settings_portal_new()
static constexpr char kPortalName[]
static FlClockFormat fl_settings_portal_get_clock_format(FlSettings *settings)
G_DEFINE_TYPE_WITH_CODE(FlSettingsPortal, fl_settings_portal, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE(fl_settings_get_type(), fl_settings_portal_iface_init)) static gchar *format_key(const FlSetting *setting)
FlSettingsPortal * fl_settings_portal_new_with_values(GVariantDict *values)
static constexpr char kPortalSettings[]
static gboolean fl_settings_portal_get_enable_animations(FlSettings *settings)
uint8_t value
const gchar * key
const gchar * ns
const GVariantType * type
GVariantDict * values
void * user_data