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