1 /**
2  * SECTION:clutter-settings
3  * @Title: ClutterSettings
4  * @Short_Description: Settings configuration
5  *
6  * Clutter depends on some settings to perform operations like detecting
7  * multiple button press events, or font options to render text.
8  *
9  * Usually, Clutter will strive to use the platform's settings in order
10  * to be as much integrated as possible. It is, however, possible to
11  * change these settings on a per-application basis, by using the
12  * #ClutterSettings singleton object and setting its properties. It is
13  * also possible, for toolkit developers, to retrieve the settings from
14  * the #ClutterSettings properties when implementing new UI elements,
15  * for instance the default font name.
16  *
17  * #ClutterSettings is available since Clutter 1.4
18  */
19 
20 #include "clutter-build-config.h"
21 
22 #include "clutter-settings.h"
23 
24 #ifdef HAVE_PANGO_FT2
25 /* for pango_fc_font_map_cache_clear() */
26 #define PANGO_ENABLE_BACKEND
27 #include <pango/pangofc-fontmap.h>
28 #endif /* HAVE_PANGO_FT2 */
29 
30 #include "clutter-debug.h"
31 #include "clutter-settings-private.h"
32 #include "clutter-stage-private.h"
33 #include "clutter-private.h"
34 
35 #include <gdesktop-enums.h>
36 #include <stdlib.h>
37 
38 #define DEFAULT_FONT_NAME       "Sans 12"
39 
40 #define CLUTTER_SETTINGS_CLASS(klass)           (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_SETTINGS, ClutterSettingsClass))
41 #define CLUTTER_IS_SETTINGS_CLASS(klass)        (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_SETTINGS))
42 #define CLUTTER_SETTINGS_GET_CLASS(obj)         (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_SETTINGS, ClutterSettingsClass))
43 
44 typedef struct
45 {
46   cairo_antialias_t cairo_antialias;
47   gint clutter_font_antialias;
48 
49   cairo_hint_style_t cairo_hint_style;
50   const char *clutter_font_hint_style;
51 
52   cairo_subpixel_order_t cairo_subpixel_order;
53   const char *clutter_font_subpixel_order;
54 } FontSettings;
55 
56 /**
57  * ClutterSettings:
58  *
59  * `ClutterSettings` is an opaque structure whose
60  * members cannot be directly accessed.
61  *
62  * Since: 1.4
63  */
64 struct _ClutterSettings
65 {
66   GObject parent_instance;
67 
68   ClutterBackend *backend;
69   GSettings *font_settings;
70   GSettings *mouse_settings;
71   GSettings *mouse_a11y_settings;
72 
73   gint double_click_time;
74   gint double_click_distance;
75 
76   gint dnd_drag_threshold;
77 
78   gdouble resolution;
79 
80   gchar *font_name;
81   gint font_dpi;
82 
83   gint xft_hinting;
84   gint xft_antialias;
85   gchar *xft_hint_style;
86   gchar *xft_rgba;
87 
88   gint long_press_duration;
89 
90   guint last_fontconfig_timestamp;
91 
92   guint password_hint_time;
93 
94   gint unscaled_font_dpi;
95 };
96 
97 struct _ClutterSettingsClass
98 {
99   GObjectClass parent_class;
100 };
101 
102 enum
103 {
104   PROP_0,
105 
106   PROP_BACKEND,
107 
108   PROP_DOUBLE_CLICK_TIME,
109   PROP_DOUBLE_CLICK_DISTANCE,
110 
111   PROP_DND_DRAG_THRESHOLD,
112 
113   PROP_FONT_NAME,
114 
115   PROP_FONT_ANTIALIAS,
116   PROP_FONT_DPI,
117   PROP_FONT_HINTING,
118   PROP_FONT_HINT_STYLE,
119   PROP_FONT_RGBA,
120 
121   PROP_LONG_PRESS_DURATION,
122 
123   PROP_FONTCONFIG_TIMESTAMP,
124 
125   PROP_PASSWORD_HINT_TIME,
126 
127   PROP_UNSCALED_FONT_DPI,
128 
129   PROP_LAST
130 };
131 
132 static GParamSpec *obj_props[PROP_LAST];
133 
134 G_DEFINE_TYPE (ClutterSettings, clutter_settings, G_TYPE_OBJECT);
135 
136 static inline void
settings_update_font_options(ClutterSettings * self)137 settings_update_font_options (ClutterSettings *self)
138 {
139   cairo_hint_style_t hint_style = CAIRO_HINT_STYLE_NONE;
140   cairo_antialias_t antialias_mode = CAIRO_ANTIALIAS_GRAY;
141   cairo_subpixel_order_t subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT;
142   cairo_font_options_t *options;
143 
144   if (self->backend == NULL)
145     return;
146 
147   options = cairo_font_options_create ();
148 
149   cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_ON);
150 
151   if (self->xft_hinting >= 0 &&
152       self->xft_hint_style == NULL)
153     {
154       hint_style = CAIRO_HINT_STYLE_NONE;
155     }
156   else if (self->xft_hint_style != NULL)
157     {
158       if (strcmp (self->xft_hint_style, "hintnone") == 0)
159         hint_style = CAIRO_HINT_STYLE_NONE;
160       else if (strcmp (self->xft_hint_style, "hintslight") == 0)
161         hint_style = CAIRO_HINT_STYLE_SLIGHT;
162       else if (strcmp (self->xft_hint_style, "hintmedium") == 0)
163         hint_style = CAIRO_HINT_STYLE_MEDIUM;
164       else if (strcmp (self->xft_hint_style, "hintfull") == 0)
165         hint_style = CAIRO_HINT_STYLE_FULL;
166     }
167 
168   cairo_font_options_set_hint_style (options, hint_style);
169 
170   if (self->xft_rgba)
171     {
172       if (strcmp (self->xft_rgba, "rgb") == 0)
173         subpixel_order = CAIRO_SUBPIXEL_ORDER_RGB;
174       else if (strcmp (self->xft_rgba, "bgr") == 0)
175         subpixel_order = CAIRO_SUBPIXEL_ORDER_BGR;
176       else if (strcmp (self->xft_rgba, "vrgb") == 0)
177         subpixel_order = CAIRO_SUBPIXEL_ORDER_VRGB;
178       else if (strcmp (self->xft_rgba, "vbgr") == 0)
179         subpixel_order = CAIRO_SUBPIXEL_ORDER_VBGR;
180     }
181 
182   cairo_font_options_set_subpixel_order (options, subpixel_order);
183 
184   if (self->xft_antialias >= 0 && !self->xft_antialias)
185     antialias_mode = CAIRO_ANTIALIAS_NONE;
186   else if (subpixel_order != CAIRO_SUBPIXEL_ORDER_DEFAULT)
187     antialias_mode = CAIRO_ANTIALIAS_SUBPIXEL;
188   else if (self->xft_antialias >= 0)
189     antialias_mode = CAIRO_ANTIALIAS_GRAY;
190 
191   cairo_font_options_set_antialias (options, antialias_mode);
192 
193   CLUTTER_NOTE (BACKEND, "New font options:\n"
194                 " - font-name:  %s\n"
195                 " - antialias:  %d\n"
196                 " - hinting:    %d\n"
197                 " - hint-style: %s\n"
198                 " - rgba:       %s\n",
199                 self->font_name != NULL ? self->font_name : DEFAULT_FONT_NAME,
200                 self->xft_antialias,
201                 self->xft_hinting,
202                 self->xft_hint_style != NULL ? self->xft_hint_style : "<null>",
203                 self->xft_rgba != NULL ? self->xft_rgba : "<null>");
204 
205   clutter_backend_set_font_options (self->backend, options);
206   cairo_font_options_destroy (options);
207 }
208 
209 static void
settings_update_font_name(ClutterSettings * self)210 settings_update_font_name (ClutterSettings *self)
211 {
212   CLUTTER_NOTE (BACKEND, "New font-name: %s", self->font_name);
213 
214   if (self->backend != NULL)
215     g_signal_emit_by_name (self->backend, "font-changed");
216 }
217 
218 static void
settings_update_resolution(ClutterSettings * self)219 settings_update_resolution (ClutterSettings *self)
220 {
221   const char *scale_env = NULL;
222 
223   if (self->font_dpi > 0)
224     self->resolution = (gdouble) self->font_dpi / 1024.0;
225   else
226     self->resolution = 96.0;
227 
228   scale_env = g_getenv ("GDK_DPI_SCALE");
229   if (scale_env != NULL)
230     {
231       double scale = g_ascii_strtod (scale_env, NULL);
232       if (scale != 0 && self->resolution > 0)
233         self->resolution *= scale;
234     }
235 
236   CLUTTER_NOTE (BACKEND, "New resolution: %.2f (%s)",
237                 self->resolution,
238                 self->unscaled_font_dpi > 0 ? "unscaled" : "scaled");
239 
240   if (self->backend != NULL)
241     g_signal_emit_by_name (self->backend, "resolution-changed");
242 }
243 
244 static void
settings_update_fontmap(ClutterSettings * self,guint stamp)245 settings_update_fontmap (ClutterSettings *self,
246                          guint            stamp)
247 {
248   if (self->backend == NULL)
249     return;
250 
251 #ifdef HAVE_PANGO_FT2
252   CLUTTER_NOTE (BACKEND, "Update fontmaps (stamp: %d)", stamp);
253 
254   if (self->last_fontconfig_timestamp != stamp)
255     {
256       ClutterMainContext *context;
257       gboolean update_needed = FALSE;
258 
259       context = _clutter_context_get_default ();
260 
261       /* If there is no font map yet then we don't need to do anything
262        * because the config for fontconfig will be read when it is
263        * created */
264       if (context->font_map)
265         {
266           PangoFontMap *fontmap = PANGO_FONT_MAP (context->font_map);
267 
268           if (PANGO_IS_FC_FONT_MAP (fontmap) &&
269               !FcConfigUptoDate (NULL))
270             {
271               pango_fc_font_map_cache_clear (PANGO_FC_FONT_MAP (fontmap));
272 
273               if (FcInitReinitialize ())
274                 update_needed = TRUE;
275             }
276         }
277 
278       self->last_fontconfig_timestamp = stamp;
279 
280       if (update_needed)
281         g_signal_emit_by_name (self->backend, "font-changed");
282     }
283 #endif /* HAVE_PANGO_FT2 */
284 }
285 
286 static void
get_font_gsettings(GSettings * settings,FontSettings * output)287 get_font_gsettings (GSettings    *settings,
288                     FontSettings *output)
289 {
290   /* org.gnome.desktop.GDesktopFontAntialiasingMode */
291   static const struct
292   {
293     cairo_antialias_t cairo_antialias;
294     gint clutter_font_antialias;
295   }
296   antialiasings[] =
297   {
298     /* none=0      */ {CAIRO_ANTIALIAS_NONE,     0},
299     /* grayscale=1 */ {CAIRO_ANTIALIAS_GRAY,     1},
300     /* rgba=2      */ {CAIRO_ANTIALIAS_SUBPIXEL, 1},
301   };
302 
303   /* org.gnome.desktop.GDesktopFontHinting */
304   static const struct
305   {
306     cairo_hint_style_t cairo_hint_style;
307     const char *clutter_font_hint_style;
308   }
309   hintings[] =
310   {
311     /* none=0   */ {CAIRO_HINT_STYLE_NONE,   "hintnone"},
312     /* slight=1 */ {CAIRO_HINT_STYLE_SLIGHT, "hintslight"},
313     /* medium=2 */ {CAIRO_HINT_STYLE_MEDIUM, "hintmedium"},
314     /* full=3   */ {CAIRO_HINT_STYLE_FULL,   "hintfull"},
315   };
316 
317   /* org.gnome.desktop.GDesktopFontRgbaOrder */
318   static const struct
319   {
320     cairo_subpixel_order_t cairo_subpixel_order;
321     const char *clutter_font_subpixel_order;
322   }
323   rgba_orders[] =
324   {
325     /* rgba=0 */ {CAIRO_SUBPIXEL_ORDER_RGB,  "rgb"}, /* XXX what is 'rgba'? */
326     /* rgb=1  */ {CAIRO_SUBPIXEL_ORDER_RGB,  "rgb"},
327     /* bgr=2  */ {CAIRO_SUBPIXEL_ORDER_BGR,  "bgr"},
328     /* vrgb=3 */ {CAIRO_SUBPIXEL_ORDER_VRGB, "vrgb"},
329     /* vbgr=4 */ {CAIRO_SUBPIXEL_ORDER_VBGR, "vbgr"},
330   };
331   guint i;
332 
333   i = g_settings_get_enum (settings, "font-hinting");
334   if (i < G_N_ELEMENTS (hintings))
335     {
336       output->cairo_hint_style = hintings[i].cairo_hint_style;
337       output->clutter_font_hint_style = hintings[i].clutter_font_hint_style;
338     }
339   else
340     {
341       output->cairo_hint_style = CAIRO_HINT_STYLE_DEFAULT;
342       output->clutter_font_hint_style = NULL;
343     }
344 
345   i = g_settings_get_enum (settings, "font-antialiasing");
346   if (i < G_N_ELEMENTS (antialiasings))
347     {
348       output->cairo_antialias = antialiasings[i].cairo_antialias;
349       output->clutter_font_antialias = antialiasings[i].clutter_font_antialias;
350     }
351   else
352     {
353       output->cairo_antialias = CAIRO_ANTIALIAS_DEFAULT;
354       output->clutter_font_antialias = -1;
355     }
356 
357   i = g_settings_get_enum (settings, "font-rgba-order");
358   if (i < G_N_ELEMENTS (rgba_orders))
359     {
360       output->cairo_subpixel_order = rgba_orders[i].cairo_subpixel_order;
361       output->clutter_font_subpixel_order = rgba_orders[i].clutter_font_subpixel_order;
362     }
363   else
364     {
365       output->cairo_subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT;
366       output->clutter_font_subpixel_order = NULL;
367     }
368 
369   if (output->cairo_antialias == CAIRO_ANTIALIAS_GRAY)
370     output->clutter_font_subpixel_order = "none";
371 }
372 
373 static void
init_font_options(ClutterSettings * self)374 init_font_options (ClutterSettings *self)
375 {
376   GSettings *settings = self->font_settings;
377   cairo_font_options_t *options = cairo_font_options_create ();
378   FontSettings fs;
379 
380   get_font_gsettings (settings, &fs);
381 
382   cairo_font_options_set_hint_style (options, fs.cairo_hint_style);
383   cairo_font_options_set_antialias (options, fs.cairo_antialias);
384   cairo_font_options_set_subpixel_order (options, fs.cairo_subpixel_order);
385 
386   clutter_backend_set_font_options (self->backend, options);
387 
388   cairo_font_options_destroy (options);
389 }
390 
391 static void
sync_mouse_options(ClutterSettings * self)392 sync_mouse_options (ClutterSettings *self)
393 {
394   int double_click;
395   int drag_threshold;
396 
397   double_click = g_settings_get_int (self->mouse_settings, "double-click");
398   drag_threshold = g_settings_get_int (self->mouse_settings, "drag-threshold");
399 
400   g_object_set (self,
401 		"double-click-time", double_click,
402 		"dnd-drag-threshold", drag_threshold,
403                 NULL);
404 }
405 
406 static gboolean
on_font_settings_change_event(GSettings * settings,gpointer keys,gint n_keys,gpointer user_data)407 on_font_settings_change_event (GSettings *settings,
408 			       gpointer   keys,
409 			       gint       n_keys,
410 			       gpointer   user_data)
411 {
412   ClutterSettings *self = CLUTTER_SETTINGS (user_data);
413   FontSettings fs;
414   gint hinting;
415 
416   get_font_gsettings (settings, &fs);
417   hinting = fs.cairo_hint_style == CAIRO_HINT_STYLE_NONE ? 0 : 1;
418   g_object_set (self,
419                 "font-hinting",        hinting,
420                 "font-hint-style",     fs.clutter_font_hint_style,
421                 "font-antialias",      fs.clutter_font_antialias,
422                 "font-subpixel-order", fs.clutter_font_subpixel_order,
423                 NULL);
424 
425   return FALSE;
426 }
427 
428 static gboolean
on_mouse_settings_change_event(GSettings * settings,gpointer keys,gint n_keys,gpointer user_data)429 on_mouse_settings_change_event (GSettings *settings,
430 				gpointer   keys,
431 				gint       n_keys,
432 				gpointer   user_data)
433 {
434   ClutterSettings *self = CLUTTER_SETTINGS (user_data);
435 
436   sync_mouse_options (self);
437 
438   return FALSE;
439 }
440 
441 struct _pointer_a11y_settings_flags_pair {
442   const char *name;
443   ClutterPointerA11yFlags flag;
444 } pointer_a11y_settings_flags_pair[] = {
445   { "secondary-click-enabled", CLUTTER_A11Y_SECONDARY_CLICK_ENABLED },
446   { "dwell-click-enabled",     CLUTTER_A11Y_DWELL_ENABLED },
447 };
448 
449 static ClutterPointerA11yDwellDirection
pointer_a11y_dwell_direction_from_setting(ClutterSettings * self,const char * key)450 pointer_a11y_dwell_direction_from_setting (ClutterSettings *self,
451                                            const char      *key)
452 {
453   GDesktopMouseDwellDirection dwell_gesture_direction;
454 
455   dwell_gesture_direction = g_settings_get_enum (self->mouse_a11y_settings,
456                                                  key);
457   switch (dwell_gesture_direction)
458     {
459     case G_DESKTOP_MOUSE_DWELL_DIRECTION_LEFT:
460       return CLUTTER_A11Y_DWELL_DIRECTION_LEFT;
461       break;
462     case G_DESKTOP_MOUSE_DWELL_DIRECTION_RIGHT:
463       return CLUTTER_A11Y_DWELL_DIRECTION_RIGHT;
464       break;
465     case G_DESKTOP_MOUSE_DWELL_DIRECTION_UP:
466       return CLUTTER_A11Y_DWELL_DIRECTION_UP;
467       break;
468     case G_DESKTOP_MOUSE_DWELL_DIRECTION_DOWN:
469       return CLUTTER_A11Y_DWELL_DIRECTION_DOWN;
470       break;
471     default:
472       break;
473     }
474   return CLUTTER_A11Y_DWELL_DIRECTION_NONE;
475 }
476 
477 static void
sync_pointer_a11y_settings(ClutterSettings * self,ClutterSeat * seat)478 sync_pointer_a11y_settings (ClutterSettings *self,
479                             ClutterSeat     *seat)
480 {
481   ClutterPointerA11ySettings pointer_a11y_settings;
482   GDesktopMouseDwellMode dwell_mode;
483   int i;
484 
485   clutter_seat_get_pointer_a11y_settings (seat, &pointer_a11y_settings);
486   pointer_a11y_settings.controls = 0;
487   for (i = 0; i < G_N_ELEMENTS (pointer_a11y_settings_flags_pair); i++)
488     {
489       if (!g_settings_get_boolean (self->mouse_a11y_settings,
490                                    pointer_a11y_settings_flags_pair[i].name))
491         continue;
492 
493       pointer_a11y_settings.controls |=
494         pointer_a11y_settings_flags_pair[i].flag;
495     }
496 
497   /* "secondary-click-time" is expressed in seconds */
498   pointer_a11y_settings.secondary_click_delay =
499     (1000 * g_settings_get_double (self->mouse_a11y_settings,
500                                    "secondary-click-time"));
501   /* "dwell-time" is expressed in seconds */
502   pointer_a11y_settings.dwell_delay =
503     (1000 * g_settings_get_double (self->mouse_a11y_settings, "dwell-time"));
504   pointer_a11y_settings.dwell_threshold =
505     g_settings_get_int (self->mouse_a11y_settings, "dwell-threshold");
506 
507   dwell_mode = g_settings_get_enum (self->mouse_a11y_settings, "dwell-mode");
508   if (dwell_mode == G_DESKTOP_MOUSE_DWELL_MODE_WINDOW)
509     pointer_a11y_settings.dwell_mode = CLUTTER_A11Y_DWELL_MODE_WINDOW;
510   else
511     pointer_a11y_settings.dwell_mode = CLUTTER_A11Y_DWELL_MODE_GESTURE;
512 
513   pointer_a11y_settings.dwell_gesture_single =
514     pointer_a11y_dwell_direction_from_setting (self, "dwell-gesture-single");
515   pointer_a11y_settings.dwell_gesture_double =
516     pointer_a11y_dwell_direction_from_setting (self, "dwell-gesture-double");
517   pointer_a11y_settings.dwell_gesture_drag =
518     pointer_a11y_dwell_direction_from_setting (self, "dwell-gesture-drag");
519   pointer_a11y_settings.dwell_gesture_secondary =
520     pointer_a11y_dwell_direction_from_setting (self, "dwell-gesture-secondary");
521 
522   clutter_seat_set_pointer_a11y_settings (seat, &pointer_a11y_settings);
523 }
524 
525 static gboolean
on_mouse_a11y_settings_change_event(GSettings * settings,gpointer keys,int n_keys,gpointer user_data)526 on_mouse_a11y_settings_change_event (GSettings *settings,
527                                      gpointer   keys,
528                                      int        n_keys,
529                                      gpointer   user_data)
530 {
531   ClutterSettings *self = CLUTTER_SETTINGS (user_data);
532   ClutterSeat *seat = clutter_backend_get_default_seat (self->backend);
533 
534   sync_pointer_a11y_settings (self, seat);
535 
536   return FALSE;
537 }
538 
539 static void
load_initial_settings(ClutterSettings * self)540 load_initial_settings (ClutterSettings *self)
541 {
542   static const gchar *font_settings_path = "org.gnome.desktop.interface";
543   static const gchar *mouse_settings_path = "org.gnome.desktop.peripherals.mouse";
544   static const char *mouse_a11y_settings_path = "org.gnome.desktop.a11y.mouse";
545   GSettingsSchemaSource *source = g_settings_schema_source_get_default ();
546   GSettingsSchema *schema;
547 
548   schema = g_settings_schema_source_lookup (source, font_settings_path, TRUE);
549   if (!schema)
550     {
551       g_warning ("Failed to find schema: %s", font_settings_path);
552     }
553   else
554     {
555       self->font_settings = g_settings_new_full (schema, NULL, NULL);
556       if (self->font_settings)
557         {
558           init_font_options (self);
559           g_signal_connect (self->font_settings, "change-event",
560                             G_CALLBACK (on_font_settings_change_event),
561                             self);
562         }
563     }
564 
565   schema = g_settings_schema_source_lookup (source, mouse_settings_path, TRUE);
566   if (!schema)
567     {
568       g_warning ("Failed to find schema: %s", mouse_settings_path);
569     }
570   else
571     {
572       self->mouse_settings = g_settings_new_full (schema, NULL, NULL);
573       if (self->mouse_settings)
574         {
575           sync_mouse_options (self);
576           g_signal_connect (self->mouse_settings, "change-event",
577                             G_CALLBACK (on_mouse_settings_change_event),
578                             self);
579         }
580     }
581 
582   schema = g_settings_schema_source_lookup (source, mouse_a11y_settings_path, TRUE);
583   if (!schema)
584     {
585       g_warning ("Failed to find schema: %s", mouse_settings_path);
586     }
587   else
588     {
589       self->mouse_a11y_settings = g_settings_new_full (schema, NULL, NULL);
590       g_signal_connect (self->mouse_a11y_settings, "change-event",
591                         G_CALLBACK (on_mouse_a11y_settings_change_event),
592                         self);
593     }
594 }
595 
596 static void
clutter_settings_finalize(GObject * gobject)597 clutter_settings_finalize (GObject *gobject)
598 {
599   ClutterSettings *self = CLUTTER_SETTINGS (gobject);
600 
601   g_free (self->font_name);
602   g_free (self->xft_hint_style);
603   g_free (self->xft_rgba);
604 
605   g_clear_object (&self->font_settings);
606   g_clear_object (&self->mouse_settings);
607   g_clear_object (&self->mouse_a11y_settings);
608 
609   G_OBJECT_CLASS (clutter_settings_parent_class)->finalize (gobject);
610 }
611 
612 static void
clutter_settings_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * pspec)613 clutter_settings_set_property (GObject      *gobject,
614                                guint         prop_id,
615                                const GValue *value,
616                                GParamSpec   *pspec)
617 {
618   ClutterSettings *self = CLUTTER_SETTINGS (gobject);
619 
620   switch (prop_id)
621     {
622     case PROP_BACKEND:
623       self->backend = g_value_get_object (value);
624       break;
625 
626     case PROP_DOUBLE_CLICK_TIME:
627       self->double_click_time = g_value_get_int (value);
628       break;
629 
630     case PROP_DOUBLE_CLICK_DISTANCE:
631       self->double_click_distance = g_value_get_int (value);
632       break;
633 
634     case PROP_DND_DRAG_THRESHOLD:
635       self->dnd_drag_threshold = g_value_get_int (value);
636       break;
637 
638     case PROP_FONT_NAME:
639       g_free (self->font_name);
640       self->font_name = g_value_dup_string (value);
641       settings_update_font_name (self);
642       break;
643 
644     case PROP_FONT_ANTIALIAS:
645       self->xft_antialias = g_value_get_int (value);
646       settings_update_font_options (self);
647       break;
648 
649     case PROP_FONT_DPI:
650       self->font_dpi = g_value_get_int (value);
651       settings_update_resolution (self);
652       break;
653 
654     case PROP_FONT_HINTING:
655       self->xft_hinting = g_value_get_int (value);
656       settings_update_font_options (self);
657       break;
658 
659     case PROP_FONT_HINT_STYLE:
660       g_free (self->xft_hint_style);
661       self->xft_hint_style = g_value_dup_string (value);
662       settings_update_font_options (self);
663       break;
664 
665     case PROP_FONT_RGBA:
666       g_free (self->xft_rgba);
667       self->xft_rgba = g_value_dup_string (value);
668       settings_update_font_options (self);
669       break;
670 
671     case PROP_LONG_PRESS_DURATION:
672       self->long_press_duration = g_value_get_int (value);
673       break;
674 
675     case PROP_FONTCONFIG_TIMESTAMP:
676       settings_update_fontmap (self, g_value_get_uint (value));
677       break;
678 
679     case PROP_PASSWORD_HINT_TIME:
680       self->password_hint_time = g_value_get_uint (value);
681       break;
682 
683     case PROP_UNSCALED_FONT_DPI:
684       self->font_dpi = g_value_get_int (value);
685       settings_update_resolution (self);
686       break;
687 
688     default:
689       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
690       break;
691     }
692 }
693 
694 void
clutter_settings_set_property_internal(ClutterSettings * self,const char * property,GValue * value)695 clutter_settings_set_property_internal (ClutterSettings *self,
696                                         const char *property,
697                                         GValue *value)
698 {
699 
700   property = g_intern_string (property);
701 
702   g_object_set_property (G_OBJECT (self), property, value);
703 }
704 
705 static void
clutter_settings_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * pspec)706 clutter_settings_get_property (GObject    *gobject,
707                                guint       prop_id,
708                                GValue     *value,
709                                GParamSpec *pspec)
710 {
711   ClutterSettings *self = CLUTTER_SETTINGS (gobject);
712 
713   switch (prop_id)
714     {
715     case PROP_DOUBLE_CLICK_TIME:
716       g_value_set_int (value, self->double_click_time);
717       break;
718 
719     case PROP_DOUBLE_CLICK_DISTANCE:
720       g_value_set_int (value, self->double_click_distance);
721       break;
722 
723     case PROP_DND_DRAG_THRESHOLD:
724       g_value_set_int (value, self->dnd_drag_threshold);
725       break;
726 
727     case PROP_FONT_NAME:
728       g_value_set_string (value, self->font_name);
729       break;
730 
731     case PROP_FONT_ANTIALIAS:
732       g_value_set_int (value, self->xft_antialias);
733       break;
734 
735     case PROP_FONT_DPI:
736       g_value_set_int (value, self->resolution * 1024);
737       break;
738 
739     case PROP_FONT_HINTING:
740       g_value_set_int (value, self->xft_hinting);
741       break;
742 
743     case PROP_FONT_HINT_STYLE:
744       g_value_set_string (value, self->xft_hint_style);
745       break;
746 
747     case PROP_FONT_RGBA:
748       g_value_set_string (value, self->xft_rgba);
749       break;
750 
751     case PROP_LONG_PRESS_DURATION:
752       g_value_set_int (value, self->long_press_duration);
753       break;
754 
755     case PROP_PASSWORD_HINT_TIME:
756       g_value_set_uint (value, self->password_hint_time);
757       break;
758 
759     default:
760       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
761       break;
762     }
763 }
764 
765 static void
clutter_settings_dispatch_properties_changed(GObject * gobject,guint n_pspecs,GParamSpec ** pspecs)766 clutter_settings_dispatch_properties_changed (GObject     *gobject,
767                                               guint        n_pspecs,
768                                               GParamSpec **pspecs)
769 {
770   ClutterSettings *self = CLUTTER_SETTINGS (gobject);
771   GObjectClass *klass;
772 
773   /* chain up to emit ::notify */
774   klass = G_OBJECT_CLASS (clutter_settings_parent_class);
775   klass->dispatch_properties_changed (gobject, n_pspecs, pspecs);
776 
777   /* emit settings-changed just once for multiple properties */
778   if (self->backend != NULL)
779     g_signal_emit_by_name (self->backend, "settings-changed");
780 }
781 
782 static void
clutter_settings_class_init(ClutterSettingsClass * klass)783 clutter_settings_class_init (ClutterSettingsClass *klass)
784 {
785   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
786 
787   /**
788    * ClutterSettings:backend:
789    *
790    * A back pointer to the #ClutterBackend
791    *
792    * Since: 1.4
793    *
794    * Deprecated: 1.10
795    */
796   obj_props[PROP_BACKEND] =
797     g_param_spec_object ("backend",
798                          "Backend",
799                          "A pointer to the backend",
800                          CLUTTER_TYPE_BACKEND,
801                          CLUTTER_PARAM_WRITABLE |
802                          G_PARAM_DEPRECATED |
803                          G_PARAM_CONSTRUCT_ONLY);
804 
805   /**
806    * ClutterSettings:double-click-time:
807    *
808    * The time, in milliseconds, that should elapse between button-press
809    * events in order to increase the click count by 1.
810    *
811    * Since: 1.4
812    */
813   obj_props[PROP_DOUBLE_CLICK_TIME] =
814     g_param_spec_int ("double-click-time",
815                       P_("Double Click Time"),
816                       P_("The time between clicks necessary to detect a multiple click"),
817                       0, G_MAXINT,
818                       250,
819                       CLUTTER_PARAM_READWRITE);
820 
821   /**
822    * ClutterSettings:double-click-distance:
823    *
824    * The maximum distance, in pixels, between button-press events that
825    * determines whether or not to increase the click count by 1.
826    *
827    * Since: 1.4
828    */
829   obj_props[PROP_DOUBLE_CLICK_DISTANCE] =
830     g_param_spec_int ("double-click-distance",
831                       P_("Double Click Distance"),
832                       P_("The distance between clicks necessary to detect a multiple click"),
833                       0, G_MAXINT,
834                       5,
835                       CLUTTER_PARAM_READWRITE);
836 
837   /**
838    * ClutterSettings:dnd-drag-threshold:
839    *
840    * The default distance that the cursor of a pointer device
841    * should travel before a drag operation should start.
842    *
843    * Since: 1.8
844    */
845   obj_props[PROP_DND_DRAG_THRESHOLD] =
846     g_param_spec_int ("dnd-drag-threshold",
847                       P_("Drag Threshold"),
848                       P_("The distance the cursor should travel before starting to drag"),
849                       1, G_MAXINT,
850                       8,
851                       CLUTTER_PARAM_READWRITE);
852 
853   /**
854    * ClutterSettings:font-name:
855    *
856    * The default font name that should be used by text actors, as
857    * a string that can be passed to pango_font_description_from_string().
858    *
859    * Since: 1.4
860    */
861   obj_props[PROP_FONT_NAME] =
862     g_param_spec_string ("font-name",
863                          P_("Font Name"),
864                          P_("The description of the default font, as one that could be parsed by Pango"),
865                          NULL,
866                          CLUTTER_PARAM_READWRITE);
867 
868   /**
869    * ClutterSettings:font-antialias:
870    *
871    * Whether or not to use antialiasing when rendering text; a value
872    * of 1 enables it unconditionally; a value of 0 disables it
873    * unconditionally; and -1 will use the system's default.
874    *
875    * Since: 1.4
876    */
877   obj_props[PROP_FONT_ANTIALIAS] =
878     g_param_spec_int ("font-antialias",
879                       P_("Font Antialias"),
880                       P_("Whether to use antialiasing (1 to enable, 0 to disable, and -1 to use the default)"),
881                       -1, 1,
882                       -1,
883                       CLUTTER_PARAM_READWRITE);
884 
885   /**
886    * ClutterSettings:font-dpi:
887    *
888    * The DPI used when rendering text, as a value of 1024 * dots/inch.
889    *
890    * If set to -1, the system's default will be used instead
891    *
892    * Since: 1.4
893    */
894   obj_props[PROP_FONT_DPI] =
895     g_param_spec_int ("font-dpi",
896                       P_("Font DPI"),
897                       P_("The resolution of the font, in 1024 * dots/inch, or -1 to use the default"),
898                       -1, 1024 * 1024,
899                       -1,
900                       CLUTTER_PARAM_READWRITE);
901 
902   obj_props[PROP_UNSCALED_FONT_DPI] =
903     g_param_spec_int ("unscaled-font-dpi",
904                       P_("Font DPI"),
905                       P_("The resolution of the font, in 1024 * dots/inch, or -1 to use the default"),
906                       -1, 1024 * 1024,
907                       -1,
908                       CLUTTER_PARAM_WRITABLE);
909 
910   /**
911    * ClutterSettings:font-hinting:
912    *
913    * Whether or not to use hinting when rendering text; a value of 1
914    * unconditionally enables it; a value of 0 unconditionally disables
915    * it; and a value of -1 will use the system's default.
916    *
917    * Since: 1.4
918    */
919   obj_props[PROP_FONT_HINTING] =
920     g_param_spec_int ("font-hinting",
921                       P_("Font Hinting"),
922                       P_("Whether to use hinting (1 to enable, 0 to disable and -1 to use the default)"),
923                       -1, 1,
924                       -1,
925                       CLUTTER_PARAM_READWRITE);
926 
927   /**
928    * ClutterSettings:font-hint-style:
929    *
930    * The style of the hinting used when rendering text. Valid values
931    * are:
932    *
933    *   - hintnone
934    *   - hintslight
935    *   - hintmedium
936    *   - hintfull
937    *
938    * Since: 1.4
939    */
940   obj_props[PROP_FONT_HINT_STYLE] =
941     g_param_spec_string ("font-hint-style",
942                          P_("Font Hint Style"),
943                          P_("The style of hinting (hintnone, hintslight, hintmedium, hintfull)"),
944                          NULL,
945                          CLUTTER_PARAM_READWRITE);
946 
947   /**
948    * ClutterSettings:font-subpixel-order:
949    *
950    * The type of sub-pixel antialiasing used when rendering text. Valid
951    * values are:
952    *
953    *   - none
954    *   - rgb
955    *   - bgr
956    *   - vrgb
957    *   - vbgr
958    *
959    * Since: 1.4
960    */
961   obj_props[PROP_FONT_RGBA] =
962     g_param_spec_string ("font-subpixel-order",
963                          P_("Font Subpixel Order"),
964                          P_("The type of subpixel antialiasing (none, rgb, bgr, vrgb, vbgr)"),
965                          NULL,
966                          CLUTTER_PARAM_READWRITE);
967 
968   /**
969    * ClutterSettings:long-press-duration:
970    *
971    * Sets the minimum duration for a press to be recognized as a long press
972    * gesture. The duration is expressed in milliseconds.
973    *
974    * See also #ClutterClickAction:long-press-duration.
975    *
976    * Since: 1.8
977    */
978   obj_props[PROP_LONG_PRESS_DURATION] =
979     g_param_spec_int ("long-press-duration",
980                       P_("Long Press Duration"),
981                       P_("The minimum duration for a long press gesture to be recognized"),
982                       0, G_MAXINT,
983                       500,
984                       CLUTTER_PARAM_READWRITE);
985 
986   obj_props[PROP_FONTCONFIG_TIMESTAMP] =
987     g_param_spec_uint ("fontconfig-timestamp",
988                        P_("Fontconfig configuration timestamp"),
989                        P_("Timestamp of the current fontconfig configuration"),
990                        0, G_MAXUINT,
991                        0,
992                        CLUTTER_PARAM_WRITABLE);
993 
994   /**
995    * ClutterText:password-hint-time:
996    *
997    * How long should Clutter show the last input character in editable
998    * ClutterText actors. The value is in milliseconds. A value of 0
999    * disables showing the password hint. 600 is a good value for
1000    * enabling the hint.
1001    *
1002    * Since: 1.10
1003    */
1004   obj_props[PROP_PASSWORD_HINT_TIME] =
1005     g_param_spec_uint ("password-hint-time",
1006                        P_("Password Hint Time"),
1007                        P_("How long to show the last input character in hidden entries"),
1008                        0, G_MAXUINT,
1009                        0,
1010                        CLUTTER_PARAM_READWRITE);
1011 
1012   gobject_class->set_property = clutter_settings_set_property;
1013   gobject_class->get_property = clutter_settings_get_property;
1014   gobject_class->dispatch_properties_changed =
1015     clutter_settings_dispatch_properties_changed;
1016   gobject_class->finalize = clutter_settings_finalize;
1017   g_object_class_install_properties (gobject_class, PROP_LAST, obj_props);
1018 }
1019 
1020 static void
clutter_settings_init(ClutterSettings * self)1021 clutter_settings_init (ClutterSettings *self)
1022 {
1023   self->resolution = -1.0;
1024 
1025   self->font_dpi = -1;
1026   self->unscaled_font_dpi = -1;
1027 
1028   self->double_click_time = 250;
1029   self->double_click_distance = 5;
1030 
1031   self->dnd_drag_threshold = 8;
1032 
1033   self->font_name = g_strdup (DEFAULT_FONT_NAME);
1034 
1035   self->xft_antialias = -1;
1036   self->xft_hinting = -1;
1037   self->xft_hint_style = NULL;
1038   self->xft_rgba = NULL;
1039 
1040   self->long_press_duration = 500;
1041 }
1042 
1043 /**
1044  * clutter_settings_get_default:
1045  *
1046  * Retrieves the singleton instance of #ClutterSettings
1047  *
1048  * Return value: (transfer none): the instance of #ClutterSettings. The
1049  *   returned object is owned by Clutter and it should not be unreferenced
1050  *   directly
1051  *
1052  * Since: 1.4
1053  */
1054 ClutterSettings *
clutter_settings_get_default(void)1055 clutter_settings_get_default (void)
1056 {
1057   static ClutterSettings *settings = NULL;
1058 
1059   if (G_UNLIKELY (settings == NULL))
1060     settings = g_object_new (CLUTTER_TYPE_SETTINGS, NULL);
1061 
1062   return settings;
1063 }
1064 
1065 void
_clutter_settings_set_backend(ClutterSettings * settings,ClutterBackend * backend)1066 _clutter_settings_set_backend (ClutterSettings *settings,
1067                                ClutterBackend  *backend)
1068 {
1069   g_assert (CLUTTER_IS_SETTINGS (settings));
1070   g_assert (CLUTTER_IS_BACKEND (backend));
1071 
1072   settings->backend = backend;
1073 
1074   load_initial_settings (settings);
1075 }
1076 
1077 void
clutter_settings_ensure_pointer_a11y_settings(ClutterSettings * settings,ClutterSeat * seat)1078 clutter_settings_ensure_pointer_a11y_settings (ClutterSettings *settings,
1079                                                ClutterSeat     *seat)
1080 {
1081   sync_pointer_a11y_settings (settings, seat);
1082 }
1083