1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3 /*
4 * Copyright (C) 2017 Red Hat
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 * 02111-1307, USA.
20 */
21
22 #include "config.h"
23
24 #include "backends/meta-settings-private.h"
25
26 #include <gio/gio.h>
27
28 #include "backends/meta-backend-private.h"
29 #include "backends/meta-logical-monitor.h"
30 #include "backends/meta-monitor-manager-private.h"
31 #include "ui/theme-private.h"
32
33 #ifndef XWAYLAND_GRAB_DEFAULT_ACCESS_RULES
34 # warning "XWAYLAND_GRAB_DEFAULT_ACCESS_RULES is not set"
35 # define XWAYLAND_GRAB_DEFAULT_ACCESS_RULES ""
36 #endif
37
38 enum
39 {
40 UI_SCALING_FACTOR_CHANGED,
41 GLOBAL_SCALING_FACTOR_CHANGED,
42 FONT_DPI_CHANGED,
43 EXPERIMENTAL_FEATURES_CHANGED,
44
45 N_SIGNALS
46 };
47
48 static guint signals[N_SIGNALS];
49
50 struct _MetaSettings
51 {
52 GObject parent;
53
54 MetaBackend *backend;
55
56 GSettings *interface_settings;
57 GSettings *mutter_settings;
58 GSettings *wayland_settings;
59
60 int ui_scaling_factor;
61 int global_scaling_factor;
62
63 int font_dpi;
64
65 MetaExperimentalFeature experimental_features;
66 gboolean experimental_features_overridden;
67
68 gboolean xwayland_allow_grabs;
69 GPtrArray *xwayland_grab_allow_list_patterns;
70 GPtrArray *xwayland_grab_deny_list_patterns;
71
72 /* A bitmask of MetaXwaylandExtension enum */
73 int xwayland_disable_extensions;
74 };
75
G_DEFINE_TYPE(MetaSettings,meta_settings,G_TYPE_OBJECT)76 G_DEFINE_TYPE (MetaSettings, meta_settings, G_TYPE_OBJECT)
77
78 static int
79 calculate_ui_scaling_factor (MetaSettings *settings)
80 {
81 MetaMonitorManager *monitor_manager =
82 meta_backend_get_monitor_manager (settings->backend);
83 MetaLogicalMonitor *primary_logical_monitor;
84
85 primary_logical_monitor =
86 meta_monitor_manager_get_primary_logical_monitor (monitor_manager);
87 if (!primary_logical_monitor)
88 return 1;
89
90 return (int) meta_logical_monitor_get_scale (primary_logical_monitor);
91 }
92
93 static gboolean
update_ui_scaling_factor(MetaSettings * settings)94 update_ui_scaling_factor (MetaSettings *settings)
95 {
96 int ui_scaling_factor;
97
98 if (meta_is_stage_views_scaled ())
99 ui_scaling_factor = 1;
100 else
101 ui_scaling_factor = calculate_ui_scaling_factor (settings);
102
103 if (settings->ui_scaling_factor != ui_scaling_factor)
104 {
105 settings->ui_scaling_factor = ui_scaling_factor;
106 return TRUE;
107 }
108 else
109 {
110 return FALSE;
111 }
112 }
113
114 void
meta_settings_update_ui_scaling_factor(MetaSettings * settings)115 meta_settings_update_ui_scaling_factor (MetaSettings *settings)
116 {
117 if (update_ui_scaling_factor (settings))
118 g_signal_emit (settings, signals[UI_SCALING_FACTOR_CHANGED], 0);
119 }
120
121 int
meta_settings_get_ui_scaling_factor(MetaSettings * settings)122 meta_settings_get_ui_scaling_factor (MetaSettings *settings)
123 {
124 g_assert (settings->ui_scaling_factor != 0);
125
126 return settings->ui_scaling_factor;
127 }
128
129 static gboolean
update_global_scaling_factor(MetaSettings * settings)130 update_global_scaling_factor (MetaSettings *settings)
131 {
132 int global_scaling_factor;
133
134 global_scaling_factor =
135 (int) g_settings_get_uint (settings->interface_settings,
136 "scaling-factor");
137
138 if (settings->global_scaling_factor != global_scaling_factor)
139 {
140 settings->global_scaling_factor = global_scaling_factor;
141 return TRUE;
142 }
143 else
144 {
145 return FALSE;
146 }
147 }
148
149 gboolean
meta_settings_get_global_scaling_factor(MetaSettings * settings,int * out_scaling_factor)150 meta_settings_get_global_scaling_factor (MetaSettings *settings,
151 int *out_scaling_factor)
152 {
153 if (settings->global_scaling_factor == 0)
154 return FALSE;
155
156 *out_scaling_factor = settings->global_scaling_factor;
157 return TRUE;
158 }
159
160 static gboolean
update_font_dpi(MetaSettings * settings)161 update_font_dpi (MetaSettings *settings)
162 {
163 double text_scaling_factor;
164 /* Number of logical pixels on an inch when unscaled */
165 const double dots_per_inch = 96;
166 /* Being based on Xft, API users expect the DPI to be 1/1024th of an inch. */
167 const double xft_factor = 1024;
168 int font_dpi;
169
170 text_scaling_factor = g_settings_get_double (settings->interface_settings,
171 "text-scaling-factor");
172 font_dpi = (int) (text_scaling_factor *
173 dots_per_inch *
174 xft_factor *
175 settings->ui_scaling_factor);
176
177 if (font_dpi != settings->font_dpi)
178 {
179 settings->font_dpi = font_dpi;
180
181 g_object_set (clutter_settings_get_default (),
182 "font-dpi", font_dpi,
183 NULL);
184
185 return TRUE;
186 }
187 else
188 {
189 return FALSE;
190 }
191 }
192
193 static void
meta_settings_update_font_dpi(MetaSettings * settings)194 meta_settings_update_font_dpi (MetaSettings *settings)
195 {
196 if (update_font_dpi (settings))
197 g_signal_emit (settings, signals[FONT_DPI_CHANGED], 0);
198 }
199
200 int
meta_settings_get_font_dpi(MetaSettings * settings)201 meta_settings_get_font_dpi (MetaSettings *settings)
202 {
203 g_assert (settings->font_dpi != 0);
204
205 return settings->font_dpi;
206 }
207
208 static void
interface_settings_changed(GSettings * interface_settings,const char * key,MetaSettings * settings)209 interface_settings_changed (GSettings *interface_settings,
210 const char *key,
211 MetaSettings *settings)
212 {
213 if (g_str_equal (key, "scaling-factor"))
214 {
215 if (update_global_scaling_factor (settings))
216 g_signal_emit (settings, signals[GLOBAL_SCALING_FACTOR_CHANGED], 0);
217 }
218 else if (g_str_equal (key, "text-scaling-factor"))
219 {
220 meta_settings_update_font_dpi (settings);
221 }
222 }
223
224 gboolean
meta_settings_is_experimental_feature_enabled(MetaSettings * settings,MetaExperimentalFeature feature)225 meta_settings_is_experimental_feature_enabled (MetaSettings *settings,
226 MetaExperimentalFeature feature)
227 {
228 return !!(settings->experimental_features & feature);
229 }
230
231 void
meta_settings_override_experimental_features(MetaSettings * settings)232 meta_settings_override_experimental_features (MetaSettings *settings)
233 {
234 settings->experimental_features = META_EXPERIMENTAL_FEATURE_NONE;
235 settings->experimental_features_overridden = TRUE;
236 }
237
238 void
meta_settings_enable_experimental_feature(MetaSettings * settings,MetaExperimentalFeature feature)239 meta_settings_enable_experimental_feature (MetaSettings *settings,
240 MetaExperimentalFeature feature)
241 {
242 g_assert (settings->experimental_features_overridden);
243
244 settings->experimental_features |= feature;
245 }
246
247 static gboolean
experimental_features_handler(GVariant * features_variant,gpointer * result,gpointer data)248 experimental_features_handler (GVariant *features_variant,
249 gpointer *result,
250 gpointer data)
251 {
252 MetaSettings *settings = data;
253 GVariantIter features_iter;
254 char *feature_str;
255 MetaExperimentalFeature features = META_EXPERIMENTAL_FEATURE_NONE;
256
257 if (settings->experimental_features_overridden)
258 {
259 *result = GINT_TO_POINTER (FALSE);
260 return TRUE;
261 }
262
263 g_variant_iter_init (&features_iter, features_variant);
264 while (g_variant_iter_loop (&features_iter, "s", &feature_str))
265 {
266 MetaExperimentalFeature feature = META_EXPERIMENTAL_FEATURE_NONE;
267
268 if (g_str_equal (feature_str, "scale-monitor-framebuffer"))
269 feature = META_EXPERIMENTAL_FEATURE_SCALE_MONITOR_FRAMEBUFFER;
270 else if (g_str_equal (feature_str, "kms-modifiers"))
271 feature = META_EXPERIMENTAL_FEATURE_KMS_MODIFIERS;
272 else if (g_str_equal (feature_str, "rt-scheduler"))
273 feature = META_EXPERIMENTAL_FEATURE_RT_SCHEDULER;
274 else if (g_str_equal (feature_str, "dma-buf-screen-sharing"))
275 feature = META_EXPERIMENTAL_FEATURE_DMA_BUF_SCREEN_SHARING;
276 else if (g_str_equal (feature_str, "autoclose-xwayland"))
277 feature = META_EXPERIMENTAL_FEATURE_AUTOCLOSE_XWAYLAND;
278
279 if (feature)
280 g_message ("Enabling experimental feature '%s'", feature_str);
281 else
282 g_warning ("Unknown experimental feature '%s'", feature_str);
283
284 features |= feature;
285 }
286
287 if (features != settings->experimental_features)
288 {
289 settings->experimental_features = features;
290 *result = GINT_TO_POINTER (TRUE);
291 }
292 else
293 {
294 *result = GINT_TO_POINTER (FALSE);
295 }
296
297 return TRUE;
298 }
299
300 static gboolean
update_experimental_features(MetaSettings * settings)301 update_experimental_features (MetaSettings *settings)
302 {
303 return GPOINTER_TO_INT (g_settings_get_mapped (settings->mutter_settings,
304 "experimental-features",
305 experimental_features_handler,
306 settings));
307 }
308
309 static void
mutter_settings_changed(GSettings * mutter_settings,gchar * key,MetaSettings * settings)310 mutter_settings_changed (GSettings *mutter_settings,
311 gchar *key,
312 MetaSettings *settings)
313 {
314 MetaExperimentalFeature old_experimental_features;
315
316 if (!g_str_equal (key, "experimental-features"))
317 return;
318
319 old_experimental_features = settings->experimental_features;
320 if (update_experimental_features (settings))
321 g_signal_emit (settings, signals[EXPERIMENTAL_FEATURES_CHANGED], 0,
322 (unsigned int) old_experimental_features);
323 }
324
325 static void
xwayland_grab_list_add_item(MetaSettings * settings,char * item)326 xwayland_grab_list_add_item (MetaSettings *settings,
327 char *item)
328 {
329 /* If first character is '!', it's a denied value */
330 if (item[0] != '!')
331 g_ptr_array_add (settings->xwayland_grab_allow_list_patterns,
332 g_pattern_spec_new (item));
333 else if (item[1] != 0)
334 g_ptr_array_add (settings->xwayland_grab_deny_list_patterns,
335 g_pattern_spec_new (&item[1]));
336 }
337
338 static gboolean
xwayland_grab_access_rules_handler(GVariant * variant,gpointer * result,gpointer data)339 xwayland_grab_access_rules_handler (GVariant *variant,
340 gpointer *result,
341 gpointer data)
342 {
343 MetaSettings *settings = data;
344 GVariantIter iter;
345 char *item;
346
347 /* Create a GPatternSpec for each element */
348 g_variant_iter_init (&iter, variant);
349 while (g_variant_iter_loop (&iter, "s", &item))
350 xwayland_grab_list_add_item (settings, item);
351
352 *result = GINT_TO_POINTER (TRUE);
353
354 return TRUE;
355 }
356
357 static void
update_xwayland_grab_access_rules(MetaSettings * settings)358 update_xwayland_grab_access_rules (MetaSettings *settings)
359 {
360 gchar **system_defaults;
361 int i;
362
363 /* Free previous patterns and create new arrays */
364 g_clear_pointer (&settings->xwayland_grab_allow_list_patterns,
365 g_ptr_array_unref);
366 settings->xwayland_grab_allow_list_patterns =
367 g_ptr_array_new_with_free_func ((GDestroyNotify) g_pattern_spec_free);
368
369 g_clear_pointer (&settings->xwayland_grab_deny_list_patterns,
370 g_ptr_array_unref);
371 settings->xwayland_grab_deny_list_patterns =
372 g_ptr_array_new_with_free_func ((GDestroyNotify) g_pattern_spec_free);
373
374 /* Add system defaults values */
375 system_defaults = g_strsplit (XWAYLAND_GRAB_DEFAULT_ACCESS_RULES, ",", -1);
376 for (i = 0; system_defaults[i]; i++)
377 xwayland_grab_list_add_item (settings, system_defaults[i]);
378 g_strfreev (system_defaults);
379
380 /* Then add gsettings values */
381 g_settings_get_mapped (settings->wayland_settings,
382 "xwayland-grab-access-rules",
383 xwayland_grab_access_rules_handler,
384 settings);
385 }
386
387 static void
update_xwayland_allow_grabs(MetaSettings * settings)388 update_xwayland_allow_grabs (MetaSettings *settings)
389 {
390 settings->xwayland_allow_grabs =
391 g_settings_get_boolean (settings->wayland_settings,
392 "xwayland-allow-grabs");
393 }
394
395 static void
update_xwayland_disable_extensions(MetaSettings * settings)396 update_xwayland_disable_extensions (MetaSettings *settings)
397 {
398 settings->xwayland_disable_extensions =
399 g_settings_get_flags (settings->wayland_settings,
400 "xwayland-disable-extension");
401 }
402
403 static void
wayland_settings_changed(GSettings * wayland_settings,gchar * key,MetaSettings * settings)404 wayland_settings_changed (GSettings *wayland_settings,
405 gchar *key,
406 MetaSettings *settings)
407 {
408
409 if (g_str_equal (key, "xwayland-allow-grabs"))
410 {
411 update_xwayland_allow_grabs (settings);
412 }
413 else if (g_str_equal (key, "xwayland-grab-access-rules"))
414 {
415 update_xwayland_grab_access_rules (settings);
416 }
417 else if (g_str_equal (key, "xwayland-disable-extension"))
418 {
419 update_xwayland_disable_extensions (settings);
420 }
421 }
422
423 void
meta_settings_get_xwayland_grab_patterns(MetaSettings * settings,GPtrArray ** allow_list_patterns,GPtrArray ** deny_list_patterns)424 meta_settings_get_xwayland_grab_patterns (MetaSettings *settings,
425 GPtrArray **allow_list_patterns,
426 GPtrArray **deny_list_patterns)
427 {
428 *allow_list_patterns = settings->xwayland_grab_allow_list_patterns;
429 *deny_list_patterns = settings->xwayland_grab_deny_list_patterns;
430 }
431
432 gboolean
meta_settings_are_xwayland_grabs_allowed(MetaSettings * settings)433 meta_settings_are_xwayland_grabs_allowed (MetaSettings *settings)
434 {
435 return (settings->xwayland_allow_grabs);
436 }
437
438 int
meta_settings_get_xwayland_disable_extensions(MetaSettings * settings)439 meta_settings_get_xwayland_disable_extensions (MetaSettings *settings)
440 {
441 return (settings->xwayland_disable_extensions);
442 }
443
444 MetaSettings *
meta_settings_new(MetaBackend * backend)445 meta_settings_new (MetaBackend *backend)
446 {
447 MetaSettings *settings;
448
449 settings = g_object_new (META_TYPE_SETTINGS, NULL);
450 settings->backend = backend;
451
452 return settings;
453 }
454
455 static void
meta_settings_dispose(GObject * object)456 meta_settings_dispose (GObject *object)
457 {
458 MetaSettings *settings = META_SETTINGS (object);
459
460 g_clear_object (&settings->mutter_settings);
461 g_clear_object (&settings->interface_settings);
462 g_clear_object (&settings->wayland_settings);
463 g_clear_pointer (&settings->xwayland_grab_allow_list_patterns,
464 g_ptr_array_unref);
465 g_clear_pointer (&settings->xwayland_grab_deny_list_patterns,
466 g_ptr_array_unref);
467
468 G_OBJECT_CLASS (meta_settings_parent_class)->dispose (object);
469 }
470
471 static void
meta_settings_init(MetaSettings * settings)472 meta_settings_init (MetaSettings *settings)
473 {
474 settings->interface_settings = g_settings_new ("org.gnome.desktop.interface");
475 g_signal_connect (settings->interface_settings, "changed",
476 G_CALLBACK (interface_settings_changed),
477 settings);
478 settings->mutter_settings = g_settings_new ("org.gnome.mutter");
479 g_signal_connect (settings->mutter_settings, "changed",
480 G_CALLBACK (mutter_settings_changed),
481 settings);
482 settings->wayland_settings = g_settings_new ("org.gnome.mutter.wayland");
483 g_signal_connect (settings->wayland_settings, "changed",
484 G_CALLBACK (wayland_settings_changed),
485 settings);
486
487 /* Chain up inter-dependent settings. */
488 g_signal_connect (settings, "global-scaling-factor-changed",
489 G_CALLBACK (meta_settings_update_ui_scaling_factor), NULL);
490 g_signal_connect (settings, "ui-scaling-factor-changed",
491 G_CALLBACK (meta_settings_update_font_dpi), NULL);
492
493 update_global_scaling_factor (settings);
494 update_experimental_features (settings);
495 update_xwayland_grab_access_rules (settings);
496 update_xwayland_allow_grabs (settings);
497 update_xwayland_disable_extensions (settings);
498 }
499
500 static void
on_monitors_changed(MetaMonitorManager * monitor_manager,MetaSettings * settings)501 on_monitors_changed (MetaMonitorManager *monitor_manager,
502 MetaSettings *settings)
503 {
504 meta_settings_update_ui_scaling_factor (settings);
505 }
506
507 void
meta_settings_post_init(MetaSettings * settings)508 meta_settings_post_init (MetaSettings *settings)
509 {
510 MetaMonitorManager *monitor_manager =
511 meta_backend_get_monitor_manager (settings->backend);
512
513 update_ui_scaling_factor (settings);
514 update_font_dpi (settings);
515
516 g_signal_connect_object (monitor_manager, "monitors-changed-internal",
517 G_CALLBACK (on_monitors_changed),
518 settings, G_CONNECT_AFTER);
519 }
520
521 static void
meta_settings_class_init(MetaSettingsClass * klass)522 meta_settings_class_init (MetaSettingsClass *klass)
523 {
524 GObjectClass *object_class = G_OBJECT_CLASS (klass);
525
526 object_class->dispose = meta_settings_dispose;
527
528 signals[UI_SCALING_FACTOR_CHANGED] =
529 g_signal_new ("ui-scaling-factor-changed",
530 G_TYPE_FROM_CLASS (object_class),
531 G_SIGNAL_RUN_LAST,
532 0,
533 NULL, NULL, NULL,
534 G_TYPE_NONE, 0);
535
536 signals[GLOBAL_SCALING_FACTOR_CHANGED] =
537 g_signal_new ("global-scaling-factor-changed",
538 G_TYPE_FROM_CLASS (object_class),
539 G_SIGNAL_RUN_LAST,
540 0,
541 NULL, NULL, NULL,
542 G_TYPE_NONE, 0);
543
544 signals[FONT_DPI_CHANGED] =
545 g_signal_new ("font-dpi-changed",
546 G_TYPE_FROM_CLASS (object_class),
547 G_SIGNAL_RUN_LAST,
548 0,
549 NULL, NULL, NULL,
550 G_TYPE_NONE, 0);
551
552 signals[EXPERIMENTAL_FEATURES_CHANGED] =
553 g_signal_new ("experimental-features-changed",
554 G_TYPE_FROM_CLASS (object_class),
555 G_SIGNAL_RUN_LAST,
556 0,
557 NULL, NULL, NULL,
558 G_TYPE_NONE, 1, G_TYPE_UINT);
559 }
560