| Flutter Linux Embedder |

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