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