1/* GTK - The GIMP Toolkit
2 * Copyright (C) 2000 Red Hat, Inc.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.Free
16 */
17
18
19#include "config.h"
20
21#include "gtksettingsprivate.h"
22
23#include "gtkcssproviderprivate.h"
24#include "gtkintl.h"
25#include "gtkprivate.h"
26#include "gtkscrolledwindow.h"
27#include "gtkstylecontextprivate.h"
28#include "gtkstyleproviderprivate.h"
29#include "gtktypebuiltins.h"
30#include "gtkversion.h"
31#include "gtkwidgetprivate.h"
32
33#include "gdk/gdk-private.h"
34
35#include <string.h>
36
37#ifdef GDK_WINDOWING_X11
38#include "x11/gdkx.h"
39#include <pango/pangofc-fontmap.h>
40#endif
41
42#ifdef GDK_WINDOWING_WAYLAND
43#include "wayland/gdkwayland.h"
44#include <pango/pangofc-fontmap.h>
45#endif
46
47#ifdef GDK_WINDOWING_BROADWAY
48#include "broadway/gdkbroadway.h"
49#endif
50
51#ifdef GDK_WINDOWING_MACOS
52#include "macos/gdkmacos.h"
53#endif
54
55#ifdef GDK_WINDOWING_WIN32
56#include "win32/gdkwin32.h"
57#endif
58
59#ifdef GDK_WINDOWING_MACOS
60#define PRINT_PREVIEW_COMMAND "open -b com.apple.Preview %f"
61#else
62#define PRINT_PREVIEW_COMMAND "evince --unlink-tempfile --preview --print-settings %s %f"
63#endif
64
65/**
66 * GtkSettings:
67 *
68 * `GtkSettings` provides a mechanism to share global settings between
69 * applications.
70 *
71 * On the X window system, this sharing is realized by an
72 * [XSettings](http://www.freedesktop.org/wiki/Specifications/xsettings-spec)
73 * manager that is usually part of the desktop environment, along with
74 * utilities that let the user change these settings.
75 *
76 * On Wayland, the settings are obtained either via a settings portal,
77 * or by reading desktop settings from DConf.
78 *
79 * In the absence of these sharing mechanisms, GTK reads default values for
80 * settings from `settings.ini` files in `/etc/gtk-4.0`, `$XDG_CONFIG_DIRS/gtk-4.0`
81 * and `$XDG_CONFIG_HOME/gtk-4.0`. These files must be valid key files (see
82 * `GKeyFile`), and have a section called Settings. Themes can also provide
83 * default values for settings by installing a `settings.ini` file
84 * next to their `gtk.css` file.
85 *
86 * Applications can override system-wide settings by setting the property
87 * of the `GtkSettings` object with g_object_set(). This should be restricted
88 * to special cases though; `GtkSettings` are not meant as an application
89 * configuration facility.
90 *
91 * There is one `GtkSettings` instance per display. It can be obtained with
92 * [func@Gtk.Settings.get_for_display], but in many cases, it is more
93 * convenient to use [method@Gtk.Widget.get_settings].
94 */
95
96/* --- typedefs --- */
97typedef struct _GtkSettingsValue GtkSettingsValue;
98
99/*< private >
100 * GtkSettingsValue:
101 * @origin: Origin should be something like “filename:linenumber” for
102 * rc files, or e.g. “XProperty” for other sources.
103 * @value: Valid types are LONG, DOUBLE and STRING corresponding to
104 * the token parsed, or a GSTRING holding an unparsed statement
105 */
106struct _GtkSettingsValue
107{
108 /* origin should be something like "filename:linenumber" for rc files,
109 * or e.g. "XProperty" for other sources
110 */
111 char *origin;
112
113 /* valid types are LONG, DOUBLE and STRING corresponding to the token parsed,
114 * or a GSTRING holding an unparsed statement
115 */
116 GValue value;
117
118 /* the settings source */
119 GtkSettingsSource source;
120};
121
122typedef struct _GtkSettingsClass GtkSettingsClass;
123typedef struct _GtkSettingsPropertyValue GtkSettingsPropertyValue;
124
125struct _GtkSettings
126{
127 GObject parent_instance;
128
129 GData *queued_settings; /* of type GtkSettingsValue* */
130 GtkSettingsPropertyValue *property_values;
131 GdkDisplay *display;
132 GSList *style_cascades;
133 GtkCssProvider *theme_provider;
134 int font_size;
135 gboolean font_size_absolute;
136 char *font_family;
137 cairo_font_options_t *font_options;
138};
139
140struct _GtkSettingsClass
141{
142 GObjectClass parent_class;
143};
144
145struct _GtkSettingsPropertyValue
146{
147 GValue value;
148 GtkSettingsSource source;
149};
150
151enum {
152 PROP_0,
153 PROP_DOUBLE_CLICK_TIME,
154 PROP_DOUBLE_CLICK_DISTANCE,
155 PROP_CURSOR_BLINK,
156 PROP_CURSOR_BLINK_TIME,
157 PROP_CURSOR_BLINK_TIMEOUT,
158 PROP_SPLIT_CURSOR,
159 PROP_CURSOR_ASPECT_RATIO,
160 PROP_THEME_NAME,
161 PROP_ICON_THEME_NAME,
162 PROP_DND_DRAG_THRESHOLD,
163 PROP_FONT_NAME,
164 PROP_XFT_ANTIALIAS,
165 PROP_XFT_HINTING,
166 PROP_XFT_HINTSTYLE,
167 PROP_XFT_RGBA,
168 PROP_XFT_DPI,
169 PROP_HINT_FONT_METRICS,
170 PROP_CURSOR_THEME_NAME,
171 PROP_CURSOR_THEME_SIZE,
172 PROP_ALTERNATIVE_BUTTON_ORDER,
173 PROP_ALTERNATIVE_SORT_ARROWS,
174 PROP_ENABLE_ANIMATIONS,
175 PROP_ERROR_BELL,
176 PROP_PRINT_BACKENDS,
177 PROP_PRINT_PREVIEW_COMMAND,
178 PROP_ENABLE_ACCELS,
179 PROP_IM_MODULE,
180 PROP_RECENT_FILES_MAX_AGE,
181 PROP_FONTCONFIG_TIMESTAMP,
182 PROP_SOUND_THEME_NAME,
183 PROP_ENABLE_INPUT_FEEDBACK_SOUNDS,
184 PROP_ENABLE_EVENT_SOUNDS,
185 PROP_PRIMARY_BUTTON_WARPS_SLIDER,
186 PROP_APPLICATION_PREFER_DARK_THEME,
187 PROP_ENTRY_SELECT_ON_FOCUS,
188 PROP_ENTRY_PASSWORD_HINT_TIMEOUT,
189 PROP_LABEL_SELECT_ON_FOCUS,
190 PROP_SHELL_SHOWS_APP_MENU,
191 PROP_SHELL_SHOWS_MENUBAR,
192 PROP_SHELL_SHOWS_DESKTOP,
193 PROP_DECORATION_LAYOUT,
194 PROP_TITLEBAR_DOUBLE_CLICK,
195 PROP_TITLEBAR_MIDDLE_CLICK,
196 PROP_TITLEBAR_RIGHT_CLICK,
197 PROP_DIALOGS_USE_HEADER,
198 PROP_ENABLE_PRIMARY_PASTE,
199 PROP_RECENT_FILES_ENABLED,
200 PROP_LONG_PRESS_TIME,
201 PROP_KEYNAV_USE_CARET,
202 PROP_OVERLAY_SCROLLING
203};
204
205/* --- prototypes --- */
206static void gtk_settings_provider_iface_init (GtkStyleProviderInterface *iface);
207
208static void gtk_settings_finalize (GObject *object);
209static void gtk_settings_get_property (GObject *object,
210 guint property_id,
211 GValue *value,
212 GParamSpec *pspec);
213static void gtk_settings_set_property (GObject *object,
214 guint property_id,
215 const GValue *value,
216 GParamSpec *pspec);
217static void gtk_settings_notify (GObject *object,
218 GParamSpec *pspec);
219static guint settings_install_property_parser (GtkSettingsClass *class,
220 GParamSpec *pspec);
221static void settings_update_double_click (GtkSettings *settings);
222
223static void settings_update_cursor_theme (GtkSettings *settings);
224static void settings_update_font_options (GtkSettings *settings);
225static void settings_update_font_values (GtkSettings *settings);
226static gboolean settings_update_fontconfig (GtkSettings *settings);
227static void settings_update_theme (GtkSettings *settings);
228static gboolean settings_update_xsetting (GtkSettings *settings,
229 GParamSpec *pspec,
230 gboolean force);
231static void settings_update_xsettings (GtkSettings *settings);
232
233static void gtk_settings_load_from_key_file (GtkSettings *settings,
234 const char *path,
235 GtkSettingsSource source);
236static void settings_update_provider (GdkDisplay *display,
237 GtkCssProvider **old,
238 GtkCssProvider *new);
239
240/* --- variables --- */
241static GQuark quark_gtk_settings = 0;
242static GSList *object_list = NULL;
243static guint class_n_properties = 0;
244
245static GPtrArray *display_settings;
246
247
248G_DEFINE_TYPE_EXTENDED (GtkSettings, gtk_settings, G_TYPE_OBJECT, 0,
249 G_IMPLEMENT_INTERFACE (GTK_TYPE_STYLE_PROVIDER,
250 gtk_settings_provider_iface_init));
251
252/* --- functions --- */
253static void
254gtk_settings_init (GtkSettings *settings)
255{
256 GParamSpec **pspecs, **p;
257 guint n_pspecs;
258 guint i = 0;
259 char *path;
260 const char * const *config_dirs;
261
262 g_datalist_init (datalist: &settings->queued_settings);
263 object_list = g_slist_prepend (list: object_list, data: settings);
264
265 settings->style_cascades = g_slist_prepend (NULL, data: _gtk_style_cascade_new ());
266 settings->theme_provider = gtk_css_provider_new ();
267
268 /* build up property array for all yet existing properties and queue
269 * notification for them (at least notification for internal properties
270 * will instantly be caught)
271 */
272 pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (settings), n_properties: &n_pspecs);
273 settings->property_values = g_new0 (GtkSettingsPropertyValue, n_pspecs);
274 g_object_freeze_notify (G_OBJECT (settings));
275
276 i = 0;
277 for (p = pspecs; *p; p++)
278 {
279 GParamSpec *pspec = *p;
280 GType value_type = G_PARAM_SPEC_VALUE_TYPE (pspec);
281
282 if (pspec->owner_type != G_OBJECT_TYPE (settings))
283 continue;
284 g_value_init (value: &settings->property_values[i].value, g_type: value_type);
285 g_param_value_set_default (pspec, value: &settings->property_values[i].value);
286
287 g_object_notify_by_pspec (G_OBJECT (settings), pspec);
288 settings->property_values[i].source = GTK_SETTINGS_SOURCE_DEFAULT;
289 i++;
290 }
291 g_free (mem: pspecs);
292
293 path = g_build_filename (first_element: _gtk_get_data_prefix (), "share", "gtk-4.0", "settings.ini", NULL);
294 gtk_settings_load_from_key_file (settings, path, source: GTK_SETTINGS_SOURCE_DEFAULT);
295 g_free (mem: path);
296
297 path = g_build_filename (first_element: _gtk_get_sysconfdir (), "gtk-4.0", "settings.ini", NULL);
298 gtk_settings_load_from_key_file (settings, path, source: GTK_SETTINGS_SOURCE_DEFAULT);
299 g_free (mem: path);
300
301 config_dirs = g_get_system_config_dirs ();
302 for (i = 0; config_dirs[i] != NULL; i++)
303 {
304 path = g_build_filename (first_element: config_dirs[i], "gtk-4.0", "settings.ini", NULL);
305 gtk_settings_load_from_key_file (settings, path, source: GTK_SETTINGS_SOURCE_DEFAULT);
306 g_free (mem: path);
307 }
308
309 path = g_build_filename (first_element: g_get_user_config_dir (), "gtk-4.0", "settings.ini", NULL);
310 gtk_settings_load_from_key_file (settings, path, source: GTK_SETTINGS_SOURCE_DEFAULT);
311 g_free (mem: path);
312
313 g_object_thaw_notify (G_OBJECT (settings));
314
315 /* ensure that derived fields are initialized */
316 if (settings->font_size == 0)
317 settings_update_font_values (settings);
318}
319
320static void
321gtk_settings_class_init (GtkSettingsClass *class)
322{
323 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
324 guint result G_GNUC_UNUSED;
325
326 gobject_class->finalize = gtk_settings_finalize;
327 gobject_class->get_property = gtk_settings_get_property;
328 gobject_class->set_property = gtk_settings_set_property;
329 gobject_class->notify = gtk_settings_notify;
330
331 quark_gtk_settings = g_quark_from_static_string (string: "gtk-settings");
332
333 /**
334 * GtkSettings:gtk-double-click-time:
335 *
336 * The maximum time to allow between two clicks for them to be considered
337 * a double click, in milliseconds.
338 */
339 result = settings_install_property_parser (class,
340 pspec: g_param_spec_int (name: "gtk-double-click-time",
341 P_("Double Click Time"),
342 P_("Maximum time allowed between two clicks for them to be considered a double click (in milliseconds)"),
343 minimum: 0, G_MAXINT, default_value: 400,
344 GTK_PARAM_READWRITE));
345 g_assert (result == PROP_DOUBLE_CLICK_TIME);
346
347 /**
348 * GtkSettings:gtk-double-click-distance:
349 *
350 * The maximum distance allowed between two clicks for them to be considered
351 * a double click, in pixels.
352 */
353 result = settings_install_property_parser (class,
354 pspec: g_param_spec_int (name: "gtk-double-click-distance",
355 P_("Double Click Distance"),
356 P_("Maximum distance allowed between two clicks for them to be considered a double click (in pixels)"),
357 minimum: 0, G_MAXINT, default_value: 5,
358 GTK_PARAM_READWRITE));
359 g_assert (result == PROP_DOUBLE_CLICK_DISTANCE);
360
361 /**
362 * GtkSettings:gtk-cursor-blink:
363 *
364 * Whether the cursor should blink.
365 *
366 * Also see the [property@Gtk.Settings:gtk-cursor-blink-timeout] setting,
367 * which allows more flexible control over cursor blinking.
368 */
369 result = settings_install_property_parser (class,
370 pspec: g_param_spec_boolean (name: "gtk-cursor-blink",
371 P_("Cursor Blink"),
372 P_("Whether the cursor should blink"),
373 TRUE,
374 GTK_PARAM_READWRITE));
375 g_assert (result == PROP_CURSOR_BLINK);
376
377 /**
378 * GtkSettings:gtk-cursor-blink-time:
379 *
380 * Length of the cursor blink cycle, in milliseconds.
381 */
382 result = settings_install_property_parser (class,
383 pspec: g_param_spec_int (name: "gtk-cursor-blink-time",
384 P_("Cursor Blink Time"),
385 P_("Length of the cursor blink cycle, in milliseconds"),
386 minimum: 100, G_MAXINT, default_value: 1200,
387 GTK_PARAM_READWRITE));
388 g_assert (result == PROP_CURSOR_BLINK_TIME);
389
390 /**
391 * GtkSettings:gtk-cursor-blink-timeout:
392 *
393 * Time after which the cursor stops blinking, in seconds.
394 *
395 * The timer is reset after each user interaction.
396 *
397 * Setting this to zero has the same effect as setting
398 * [property@Gtk.Settings:gtk-cursor-blink] to %FALSE.
399 */
400 result = settings_install_property_parser (class,
401 pspec: g_param_spec_int (name: "gtk-cursor-blink-timeout",
402 P_("Cursor Blink Timeout"),
403 P_("Time after which the cursor stops blinking, in seconds"),
404 minimum: 1, G_MAXINT, default_value: 10,
405 GTK_PARAM_READWRITE));
406 g_assert (result == PROP_CURSOR_BLINK_TIMEOUT);
407
408 /**
409 * GtkSettings:gtk-split-cursor:
410 *
411 * Whether two cursors should be displayed for mixed left-to-right and
412 * right-to-left text.
413 */
414 result = settings_install_property_parser (class,
415 pspec: g_param_spec_boolean (name: "gtk-split-cursor",
416 P_("Split Cursor"),
417 P_("Whether two cursors should be displayed for mixed left-to-right and right-to-left text"),
418 FALSE,
419 GTK_PARAM_READWRITE));
420 g_assert (result == PROP_SPLIT_CURSOR);
421
422 /**
423 * GtkSettings:gtk-cursor-aspect-ratio:
424 *
425 * The aspect ratio of the text caret.
426 */
427 result = settings_install_property_parser (class,
428 pspec: g_param_spec_double (name: "gtk-cursor-aspect-ratio",
429 P_("Cursor Aspect Ratio"),
430 P_("The aspect ratio of the text caret"),
431 minimum: 0.0, maximum: 1.0, default_value: 0.04,
432 GTK_PARAM_READWRITE));
433 g_assert (result == PROP_CURSOR_ASPECT_RATIO);
434
435 /**
436 * GtkSettings:gtk-theme-name:
437 *
438 * Name of the theme to load.
439 *
440 * See [class@Gtk.CssProvider] for details about how
441 * GTK finds the CSS stylesheet for a theme.
442 */
443 result = settings_install_property_parser (class,
444 pspec: g_param_spec_string (name: "gtk-theme-name",
445 P_("Theme Name"),
446 P_("Name of theme to load"),
447 DEFAULT_THEME_NAME,
448 GTK_PARAM_READWRITE));
449 g_assert (result == PROP_THEME_NAME);
450
451 /**
452 * GtkSettings:gtk-icon-theme-name:
453 *
454 * Name of the icon theme to use.
455 *
456 * See [class@Gtk.IconTheme] for details about how
457 * GTK handles icon themes.
458 */
459 result = settings_install_property_parser (class,
460 pspec: g_param_spec_string (name: "gtk-icon-theme-name",
461 P_("Icon Theme Name"),
462 P_("Name of icon theme to use"),
463 DEFAULT_ICON_THEME,
464 GTK_PARAM_READWRITE));
465 g_assert (result == PROP_ICON_THEME_NAME);
466
467 /**
468 * GtkSettings:gtk-dnd-drag-threshold:
469 *
470 * The number of pixels the cursor can move before dragging.
471 */
472 result = settings_install_property_parser (class,
473 pspec: g_param_spec_int (name: "gtk-dnd-drag-threshold",
474 P_("Drag threshold"),
475 P_("Number of pixels the cursor can move before dragging"),
476 minimum: 1, G_MAXINT, default_value: 8,
477 GTK_PARAM_READWRITE));
478 g_assert (result == PROP_DND_DRAG_THRESHOLD);
479
480 /**
481 * GtkSettings:gtk-font-name:
482 *
483 * The default font to use.
484 *
485 * GTK uses the family name and size from this string.
486 */
487 result = settings_install_property_parser (class,
488 pspec: g_param_spec_string (name: "gtk-font-name",
489 P_("Font Name"),
490 P_("The default font family and size to use"),
491 default_value: "Sans 10",
492 GTK_PARAM_READWRITE));
493 g_assert (result == PROP_FONT_NAME);
494
495 /**
496 * GtkSettings:gtk-xft-antialias:
497 *
498 * Whether to antialias fonts.
499 *
500 * The values are 0 for no, 1 for yes, or -1 for the system default.
501 */
502 result = settings_install_property_parser (class,
503 pspec: g_param_spec_int (name: "gtk-xft-antialias",
504 P_("Xft Antialias"),
505 P_("Whether to antialias Xft fonts; 0=no, 1=yes, -1=default"),
506 minimum: -1, maximum: 1, default_value: -1,
507 GTK_PARAM_READWRITE));
508
509 g_assert (result == PROP_XFT_ANTIALIAS);
510
511 /**
512 * GtkSettings:gtk-xft-hinting:
513 *
514 * Whether to enable font hinting.
515 *
516 * The values are 0 for no, 1 for yes, or -1 for the system default.
517 */
518 result = settings_install_property_parser (class,
519 pspec: g_param_spec_int (name: "gtk-xft-hinting",
520 P_("Xft Hinting"),
521 P_("Whether to hint Xft fonts; 0=no, 1=yes, -1=default"),
522 minimum: -1, maximum: 1, default_value: -1,
523 GTK_PARAM_READWRITE));
524
525 g_assert (result == PROP_XFT_HINTING);
526
527 /**
528 * GtkSettings:gtk-xft-hintstyle:
529 *
530 * What degree of font hinting to use.
531 *
532 * The possible vaues are hintnone, hintslight,
533 * hintmedium, hintfull.
534 */
535 result = settings_install_property_parser (class,
536 pspec: g_param_spec_string (name: "gtk-xft-hintstyle",
537 P_("Xft Hint Style"),
538 P_("What degree of hinting to use; hintnone, hintslight, hintmedium, or hintfull"),
539 NULL,
540 GTK_PARAM_READWRITE));
541
542 g_assert (result == PROP_XFT_HINTSTYLE);
543
544 /**
545 * GtkSettings:gtk-xft-rgba:
546 *
547 * The type of subpixel antialiasing to use.
548 *
549 * The possible values are none, rgb, bgr, vrgb, vbgr.
550 */
551 result = settings_install_property_parser (class,
552 pspec: g_param_spec_string (name: "gtk-xft-rgba",
553 P_("Xft RGBA"),
554 P_("Type of subpixel antialiasing; none, rgb, bgr, vrgb, vbgr"),
555 NULL,
556 GTK_PARAM_READWRITE));
557
558 g_assert (result == PROP_XFT_RGBA);
559
560
561 /**
562 * GtkSettings:gtk-xft-dpi:
563 *
564 * The font resolution, in 1024 * dots/inch.
565 *
566 * -1 to use the default value.
567 */
568 result = settings_install_property_parser (class,
569 pspec: g_param_spec_int (name: "gtk-xft-dpi",
570 P_("Xft DPI"),
571 P_("Resolution for Xft, in 1024 * dots/inch. -1 to use default value"),
572 minimum: -1, maximum: 1024*1024, default_value: -1,
573 GTK_PARAM_READWRITE));
574
575 g_assert (result == PROP_XFT_DPI);
576
577 /**
578 * GtkSettings:gtk-hint-font-metrics:
579 *
580 * Whether hinting should be applied to font metrics.
581 *
582 * Note that this also turns off subpixel positioning of glyphs,
583 * since it conflicts with metrics hinting.
584 *
585 * Since: 4.6
586 */
587 result = settings_install_property_parser (class,
588 pspec: g_param_spec_boolean (name: "gtk-hint-font-metrics",
589 P_("Hint Font Metrics"),
590 P_("Whether hinting should be applied to font metrics"),
591 FALSE,
592 GTK_PARAM_READWRITE));
593
594 g_assert (result == PROP_HINT_FONT_METRICS);
595
596 /**
597 * GtkSettings:gtk-cursor-theme-name:
598 *
599 * Name of the cursor theme to use.
600 *
601 * Use %NULL to use the default theme.
602 */
603 result = settings_install_property_parser (class,
604 pspec: g_param_spec_string (name: "gtk-cursor-theme-name",
605 P_("Cursor theme name"),
606 P_("Name of the cursor theme to use, or NULL to use the default theme"),
607 NULL,
608 GTK_PARAM_READWRITE));
609 g_assert (result == PROP_CURSOR_THEME_NAME);
610
611 /**
612 * GtkSettings:gtk-cursor-theme-size:
613 *
614 * The size to use for cursors.
615 *
616 * 0 means to use the default size.
617 */
618 result = settings_install_property_parser (class,
619 pspec: g_param_spec_int (name: "gtk-cursor-theme-size",
620 P_("Cursor theme size"),
621 P_("Size to use for cursors, or 0 to use the default size"),
622 minimum: 0, maximum: 128, default_value: 0,
623 GTK_PARAM_READWRITE));
624
625 g_assert (result == PROP_CURSOR_THEME_SIZE);
626
627 /**
628 * GtkSettings:gtk-alternative-button-order:
629 *
630 * Whether buttons in dialogs should use the alternative button order.
631 */
632 result = settings_install_property_parser (class,
633 pspec: g_param_spec_boolean (name: "gtk-alternative-button-order",
634 P_("Alternative button order"),
635 P_("Whether buttons in dialogs should use the alternative button order"),
636 FALSE,
637 GTK_PARAM_READWRITE));
638 g_assert (result == PROP_ALTERNATIVE_BUTTON_ORDER);
639
640 /**
641 * GtkSettings:gtk-alternative-sort-arrows:
642 *
643 * Controls the direction of the sort indicators in sorted list and tree
644 * views.
645 *
646 * By default an arrow pointing down means the column is sorted
647 * in ascending order. When set to %TRUE, this order will be inverted.
648 */
649 result = settings_install_property_parser (class,
650 pspec: g_param_spec_boolean (name: "gtk-alternative-sort-arrows",
651 P_("Alternative sort indicator direction"),
652 P_("Whether the direction of the sort indicators in list and tree views is inverted compared to the default (where down means ascending)"),
653 FALSE,
654 GTK_PARAM_READWRITE));
655 g_assert (result == PROP_ALTERNATIVE_SORT_ARROWS);
656
657 /**
658 * GtkSettings:gtk-enable-animations:
659 *
660 * Whether to enable toolkit-wide animations.
661 */
662 result = settings_install_property_parser (class,
663 pspec: g_param_spec_boolean (name: "gtk-enable-animations",
664 P_("Enable Animations"),
665 P_("Whether to enable toolkit-wide animations."),
666 TRUE,
667 GTK_PARAM_READWRITE));
668
669 g_assert (result == PROP_ENABLE_ANIMATIONS);
670
671 /**
672 * GtkSettings:gtk-error-bell:
673 *
674 * When %TRUE, keyboard navigation and other input-related errors
675 * will cause a beep.
676 *
677 * Since the error bell is implemented using gdk_surface_beep(), the
678 * windowing system may offer ways to configure the error bell in many
679 * ways, such as flashing the window or similar visual effects.
680 */
681 result = settings_install_property_parser (class,
682 pspec: g_param_spec_boolean (name: "gtk-error-bell",
683 P_("Error Bell"),
684 P_("When TRUE, keyboard navigation and other errors will cause a beep"),
685 TRUE,
686 GTK_PARAM_READWRITE));
687
688 g_assert (result == PROP_ERROR_BELL);
689
690 /**
691 * GtkSettings:gtk-print-backends:
692 *
693 * A comma-separated list of print backends to use in the print
694 * dialog.
695 *
696 * Available print backends depend on the GTK installation,
697 * and may include "file", "cups", "lpr" or "papi".
698 */
699 result = settings_install_property_parser (class,
700 pspec: g_param_spec_string (name: "gtk-print-backends",
701 P_("Default print backend"),
702 P_("List of the GtkPrintBackend backends to use by default"),
703 GTK_PRINT_BACKENDS,
704 GTK_PARAM_READWRITE));
705 g_assert (result == PROP_PRINT_BACKENDS);
706
707 /**
708 * GtkSettings:gtk-print-preview-command:
709 *
710 * A command to run for displaying the print preview.
711 *
712 * The command should contain a `%f` placeholder, which will get
713 * replaced by the path to the pdf file. The command may also
714 * contain a `%s` placeholder, which will get replaced by the
715 * path to a file containing the print settings in the format
716 * produced by [method@Gtk.PrintSettings.to_file].
717 *
718 * The preview application is responsible for removing the pdf
719 * file and the print settings file when it is done.
720 */
721 result = settings_install_property_parser (class,
722 pspec: g_param_spec_string (name: "gtk-print-preview-command",
723 P_("Default command to run when displaying a print preview"),
724 P_("Command to run when displaying a print preview"),
725 PRINT_PREVIEW_COMMAND,
726 GTK_PARAM_READWRITE));
727 g_assert (result == PROP_PRINT_PREVIEW_COMMAND);
728
729 /**
730 * GtkSettings:gtk-enable-accels:
731 *
732 * Whether menu items should have visible accelerators which can be
733 * activated.
734 */
735 result = settings_install_property_parser (class,
736 pspec: g_param_spec_boolean (name: "gtk-enable-accels",
737 P_("Enable Accelerators"),
738 P_("Whether menu items should have accelerators"),
739 TRUE,
740 GTK_PARAM_READWRITE));
741 g_assert (result == PROP_ENABLE_ACCELS);
742
743 /**
744 * GtkSettings:gtk-im-module:
745 *
746 * Which IM (input method) module should be used by default.
747 *
748 * This is the input method that will be used if the user has not
749 * explicitly chosen another input method from the IM context menu.
750 * This also can be a colon-separated list of input methods, which GTK
751 * will try in turn until it finds one available on the system.
752 *
753 * See [class@Gtk.IMContext].
754 */
755 result = settings_install_property_parser (class,
756 pspec: g_param_spec_string (name: "gtk-im-module",
757 P_("Default IM module"),
758 P_("Which IM module should be used by default"),
759 NULL,
760 GTK_PARAM_READWRITE));
761 g_assert (result == PROP_IM_MODULE);
762
763 /**
764 * GtkSettings:gtk-recent-files-max-age:
765 *
766 * The maximum age, in days, of the items inside the recently used
767 * resources list.
768 *
769 * Items older than this setting will be excised from the list.
770 * If set to 0, the list will always be empty; if set to -1, no
771 * item will be removed.
772 */
773 result = settings_install_property_parser (class,
774 pspec: g_param_spec_int (name: "gtk-recent-files-max-age",
775 P_("Recent Files Max Age"),
776 P_("Maximum age of recently used files, in days"),
777 minimum: -1, G_MAXINT,
778 default_value: 30,
779 GTK_PARAM_READWRITE));
780 g_assert (result == PROP_RECENT_FILES_MAX_AGE);
781
782 /**
783 * GtkSettings:gtk-fontconfig-timestamp:
784 *
785 * Timestamp of the curent fontconfig configuration.
786 */
787 result = settings_install_property_parser (class,
788 pspec: g_param_spec_uint (name: "gtk-fontconfig-timestamp",
789 P_("Fontconfig configuration timestamp"),
790 P_("Timestamp of current fontconfig configuration"),
791 minimum: 0, G_MAXUINT, default_value: 0,
792 GTK_PARAM_READWRITE));
793
794 g_assert (result == PROP_FONTCONFIG_TIMESTAMP);
795
796 /**
797 * GtkSettings:gtk-sound-theme-name:
798 *
799 * The XDG sound theme to use for event sounds.
800 *
801 * See the [Sound Theme Specifications](http://www.freedesktop.org/wiki/Specifications/sound-theme-spec)
802 * for more information on event sounds and sound themes.
803 *
804 * GTK itself does not support event sounds, you have to use
805 * a loadable module like the one that comes with libcanberra.
806 */
807 result = settings_install_property_parser (class,
808 pspec: g_param_spec_string (name: "gtk-sound-theme-name",
809 P_("Sound Theme Name"),
810 P_("XDG sound theme name"),
811 default_value: "freedesktop",
812 GTK_PARAM_READWRITE));
813 g_assert (result == PROP_SOUND_THEME_NAME);
814
815 /**
816 * GtkSettings:gtk-enable-input-feedback-sounds:
817 *
818 * Whether to play event sounds as feedback to user input.
819 *
820 * See the [Sound Theme Specifications](http://www.freedesktop.org/wiki/Specifications/sound-theme-spec)
821 * for more information on event sounds and sound themes.
822 *
823 * GTK itself does not support event sounds, you have to use a loadable
824 * module like the one that comes with libcanberra.
825 */
826 result = settings_install_property_parser (class,
827 pspec: g_param_spec_boolean (name: "gtk-enable-input-feedback-sounds",
828 /* Translators: this means sounds that are played as feedback to user input */
829 P_("Audible Input Feedback"),
830 P_("Whether to play event sounds as feedback to user input"),
831 TRUE,
832 GTK_PARAM_READWRITE));
833 g_assert (result == PROP_ENABLE_INPUT_FEEDBACK_SOUNDS);
834
835 /**
836 * GtkSettings:gtk-enable-event-sounds:
837 *
838 * Whether to play any event sounds at all.
839 *
840 * See the [Sound Theme Specifications](http://www.freedesktop.org/wiki/Specifications/sound-theme-spec)
841 * for more information on event sounds and sound themes.
842 *
843 * GTK itself does not support event sounds, you have to use a loadable
844 * module like the one that comes with libcanberra.
845 */
846 result = settings_install_property_parser (class,
847 pspec: g_param_spec_boolean (name: "gtk-enable-event-sounds",
848 P_("Enable Event Sounds"),
849 P_("Whether to play any event sounds at all"),
850 TRUE,
851 GTK_PARAM_READWRITE));
852 g_assert (result == PROP_ENABLE_EVENT_SOUNDS);
853
854 /**
855 * GtkSettings:gtk-primary-button-warps-slider:
856 *
857 * If the value of this setting is %TRUE, clicking the primary button in a
858 * `GtkRange` trough will move the slider, and hence set the range’s value, to
859 * the point that you clicked.
860 *
861 * If it is %FALSE, a primary click will cause the slider/value to move
862 * by the range’s page-size towards the point clicked.
863 *
864 * Whichever action you choose for the primary button, the other action will
865 * be available by holding Shift and primary-clicking, or clicking the middle
866 * mouse button.
867 */
868 result = settings_install_property_parser (class,
869 pspec: g_param_spec_boolean (name: "gtk-primary-button-warps-slider",
870 P_("Primary button warps slider"),
871 P_("Whether a primary click on the trough should warp the slider into position"),
872 TRUE,
873 GTK_PARAM_READWRITE));
874 g_assert (result == PROP_PRIMARY_BUTTON_WARPS_SLIDER);
875
876 /**
877 * GtkSettings:gtk-application-prefer-dark-theme:
878 *
879 * Whether the application prefers to use a dark theme.
880 *
881 * If a GTK theme includes a dark variant, it will be used
882 * instead of the configured theme.
883 *
884 * Some applications benefit from minimizing the amount of light
885 * pollution that interferes with the content. Good candidates for
886 * dark themes are photo and video editors that make the actual
887 * content get all the attention and minimize the distraction of
888 * the chrome.
889 *
890 * Dark themes should not be used for documents, where large spaces
891 * are white/light and the dark chrome creates too much contrast
892 * (web browser, text editor...).
893 */
894 result = settings_install_property_parser (class,
895 pspec: g_param_spec_boolean (name: "gtk-application-prefer-dark-theme",
896 P_("Application prefers a dark theme"),
897 P_("Whether the application prefers to have a dark theme."),
898 FALSE,
899 GTK_PARAM_READWRITE));
900 g_assert (result == PROP_APPLICATION_PREFER_DARK_THEME);
901
902 /**
903 * GtkSettings:gkt-entry-select-on-focus:
904 *
905 * Whether to select the contents of an entry when it is focused.
906 */
907 result = settings_install_property_parser (class,
908 pspec: g_param_spec_boolean (name: "gtk-entry-select-on-focus",
909 P_("Select on focus"),
910 P_("Whether to select the contents of an entry when it is focused"),
911 TRUE,
912 GTK_PARAM_READWRITE));
913 g_assert (result == PROP_ENTRY_SELECT_ON_FOCUS);
914
915 /**
916 * GtkSettings:gtk-entry-password-hint-timeout:
917 *
918 * How long to show the last input character in hidden
919 * entries.
920 *
921 * This value is in milliseconds. 0 disables showing the
922 * last char. 600 is a good value for enabling it.
923 */
924 result = settings_install_property_parser (class,
925 pspec: g_param_spec_uint (name: "gtk-entry-password-hint-timeout",
926 P_("Password Hint Timeout"),
927 P_("How long to show the last input character in hidden entries"),
928 minimum: 0, G_MAXUINT,
929 default_value: 0,
930 GTK_PARAM_READWRITE));
931 g_assert (result == PROP_ENTRY_PASSWORD_HINT_TIMEOUT);
932
933 /**
934 * GtkSettings:gtk-label-select-on-focus:
935 *
936 * Whether to select the contents of a selectable
937 * label when it is focused.
938 */
939 result = settings_install_property_parser (class,
940 pspec: g_param_spec_boolean (name: "gtk-label-select-on-focus",
941 P_("Select on focus"),
942 P_("Whether to select the contents of a selectable label when it is focused"),
943 TRUE,
944 GTK_PARAM_READWRITE));
945 g_assert (result == PROP_LABEL_SELECT_ON_FOCUS);
946
947 /**
948 * GtkSettings:gtk-shell-shows-app-menu:
949 *
950 * Set to %TRUE if the desktop environment is displaying
951 * the app menu, %FALSE if the app should display it itself.
952 */
953 result = settings_install_property_parser (class,
954 pspec: g_param_spec_boolean (name: "gtk-shell-shows-app-menu",
955 P_("Desktop shell shows app menu"),
956 P_("Set to TRUE if the desktop environment "
957 "is displaying the app menu, FALSE if "
958 "the app should display it itself."),
959 FALSE, GTK_PARAM_READWRITE));
960 g_assert (result == PROP_SHELL_SHOWS_APP_MENU);
961
962 /**
963 * GtkSettings:gtk-shell-shows-menubar:
964 *
965 * Set to %TRUE if the desktop environment is displaying
966 * the menubar, %FALSE if the app should display it itself.
967 */
968 result = settings_install_property_parser (class,
969 pspec: g_param_spec_boolean (name: "gtk-shell-shows-menubar",
970 P_("Desktop shell shows the menubar"),
971 P_("Set to TRUE if the desktop environment "
972 "is displaying the menubar, FALSE if "
973 "the app should display it itself."),
974 FALSE, GTK_PARAM_READWRITE));
975 g_assert (result == PROP_SHELL_SHOWS_MENUBAR);
976
977 /**
978 * GtkSettings:gtk-shell-shows-desktop:
979 *
980 * Set to %TRUE if the desktop environment is displaying
981 * the desktop folder, %FALSE if not.
982 */
983 result = settings_install_property_parser (class,
984 pspec: g_param_spec_boolean (name: "gtk-shell-shows-desktop",
985 P_("Desktop environment shows the desktop folder"),
986 P_("Set to TRUE if the desktop environment "
987 "is displaying the desktop folder, FALSE "
988 "if not."),
989 TRUE, GTK_PARAM_READWRITE));
990 g_assert (result == PROP_SHELL_SHOWS_DESKTOP);
991
992 /**
993 * GtkSettings:gtk-decoration-layout:
994 *
995 * Determines which buttons should be put in the
996 * titlebar of client-side decorated windows, and whether they
997 * should be placed at the left of right.
998 *
999 * The format of the string is button names, separated by commas.
1000 * A colon separates the buttons that should appear on the left
1001 * from those on the right. Recognized button names are minimize,
1002 * maximize, close, icon (the window icon) and menu (a menu button
1003 * for the fallback app menu).
1004 *
1005 * For example, "menu:minimize,maximize,close" specifies a menu
1006 * on the left, and minimize, maximize and close buttons on the right.
1007 *
1008 * Note that buttons will only be shown when they are meaningful.
1009 * E.g. a menu button only appears when the desktop shell does not
1010 * show the app menu, and a close button only appears on a window
1011 * that can be closed.
1012 *
1013 * Also note that the setting can be overridden with the
1014 * [property@Gtk.HeaderBar:decoration-layout] property.
1015 */
1016 result = settings_install_property_parser (class,
1017 pspec: g_param_spec_string (name: "gtk-decoration-layout",
1018 P_("Decoration Layout"),
1019 P_("The layout for window decorations"),
1020 default_value: "menu:minimize,maximize,close", GTK_PARAM_READWRITE));
1021 g_assert (result == PROP_DECORATION_LAYOUT);
1022
1023 /**
1024 * GtkSettings:gtk-titlebar-double-click:
1025 *
1026 * Determines the action to take when a double-click
1027 * occurs on the titlebar of client-side decorated windows.
1028 *
1029 * Recognized actions are minimize, toggle-maximize, menu, lower
1030 * or none.
1031 */
1032 result = settings_install_property_parser (class,
1033 pspec: g_param_spec_string (name: "gtk-titlebar-double-click",
1034 P_("Titlebar double-click action"),
1035 P_("The action to take on titlebar double-click"),
1036 default_value: "toggle-maximize", GTK_PARAM_READWRITE));
1037 g_assert (result == PROP_TITLEBAR_DOUBLE_CLICK);
1038
1039 /**
1040 * GtkSettings:gtk-titlebar-middle-click:
1041 *
1042 * Determines the action to take when a middle-click
1043 * occurs on the titlebar of client-side decorated windows.
1044 *
1045 * Recognized actions are minimize, toggle-maximize, menu, lower
1046 * or none.
1047 */
1048 result = settings_install_property_parser (class,
1049 pspec: g_param_spec_string (name: "gtk-titlebar-middle-click",
1050 P_("Titlebar middle-click action"),
1051 P_("The action to take on titlebar middle-click"),
1052 default_value: "none", GTK_PARAM_READWRITE));
1053 g_assert (result == PROP_TITLEBAR_MIDDLE_CLICK);
1054
1055 /**
1056 * GtkSettings:gtk-titlebar-right-click:
1057 *
1058 * Determines the action to take when a right-click
1059 * occurs on the titlebar of client-side decorated windows.
1060 *
1061 * Recognized actions are minimize, toggle-maximize, menu, lower
1062 * or none.
1063 */
1064 result = settings_install_property_parser (class,
1065 pspec: g_param_spec_string (name: "gtk-titlebar-right-click",
1066 P_("Titlebar right-click action"),
1067 P_("The action to take on titlebar right-click"),
1068 default_value: "menu", GTK_PARAM_READWRITE));
1069 g_assert (result == PROP_TITLEBAR_RIGHT_CLICK);
1070
1071 /**
1072 * GtkSettings:gtk-dialogs-use-header:
1073 *
1074 * Whether builtin GTK dialogs such as the file chooser, the
1075 * color chooser or the font chooser will use a header bar at
1076 * the top to show action widgets, or an action area at the bottom.
1077 *
1078 * This setting does not affect custom dialogs using `GtkDialog`
1079 * directly, or message dialogs.
1080 */
1081 result = settings_install_property_parser (class,
1082 pspec: g_param_spec_boolean (name: "gtk-dialogs-use-header",
1083 P_("Dialogs use header bar"),
1084 P_("Whether builtin GTK dialogs should use a header bar instead of an action area."),
1085 FALSE,
1086 GTK_PARAM_READWRITE));
1087 g_assert (result == PROP_DIALOGS_USE_HEADER);
1088
1089 /**
1090 * GtkSettings:gtk-enable-primary-paste:
1091 *
1092 * Whether a middle click on a mouse should paste the
1093 * 'PRIMARY' clipboard content at the cursor location.
1094 */
1095 result = settings_install_property_parser (class,
1096 pspec: g_param_spec_boolean (name: "gtk-enable-primary-paste",
1097 P_("Enable primary paste"),
1098 P_("Whether a middle click on a mouse should paste the “PRIMARY” clipboard content at the cursor location."),
1099 TRUE,
1100 GTK_PARAM_READWRITE));
1101 g_assert (result == PROP_ENABLE_PRIMARY_PASTE);
1102
1103 /**
1104 * GtkSettings:gtk-recent-files-enabled:
1105 *
1106 * Whether GTK should keep track of items inside the recently used
1107 * resources list.
1108 *
1109 * If set to %FALSE, the list will always be empty.
1110 */
1111 result = settings_install_property_parser (class,
1112 pspec: g_param_spec_boolean (name: "gtk-recent-files-enabled",
1113 P_("Recent Files Enabled"),
1114 P_("Whether GTK remembers recent files"),
1115 TRUE,
1116 GTK_PARAM_READWRITE));
1117 g_assert (result == PROP_RECENT_FILES_ENABLED);
1118
1119 /**
1120 * GtkSettings:gtk-long-press-time:
1121 *
1122 * The time for a button or touch press to be considered a “long press”.
1123 *
1124 * See [class@Gtk.GestureLongPress].
1125 */
1126 result = settings_install_property_parser (class,
1127 pspec: g_param_spec_uint (name: "gtk-long-press-time",
1128 P_("Long press time"),
1129 P_("Time for a button/touch press to be considered a long press (in milliseconds)"),
1130 minimum: 0, G_MAXINT, default_value: 500,
1131 GTK_PARAM_READWRITE));
1132 g_assert (result == PROP_LONG_PRESS_TIME);
1133
1134 /**
1135 * GtkSettings:gtk-keynav-use-caret:
1136 *
1137 * Whether GTK should make sure that text can be navigated with
1138 * a caret, even if it is not editable.
1139 *
1140 * This is useful when using a screen reader.
1141 */
1142 result = settings_install_property_parser (class,
1143 pspec: g_param_spec_boolean (name: "gtk-keynav-use-caret",
1144 P_("Whether to show cursor in text"),
1145 P_("Whether to show cursor in text"),
1146 FALSE,
1147 GTK_PARAM_READWRITE));
1148 g_assert (result == PROP_KEYNAV_USE_CARET);
1149
1150 /**
1151 * GtkSettings:gtk-overlay-scrolling:
1152 *
1153 * Whether scrolled windows may use overlaid scrolling indicators.
1154 *
1155 * If this is set to %FALSE, scrolled windows will have permanent
1156 * scrollbars.
1157 */
1158 result = settings_install_property_parser (class,
1159 pspec: g_param_spec_boolean (name: "gtk-overlay-scrolling",
1160 P_("Whether to use overlay scrollbars"),
1161 P_("Whether to use overlay scrollbars"),
1162 TRUE,
1163 GTK_PARAM_READWRITE));
1164 g_assert (result == PROP_OVERLAY_SCROLLING);
1165}
1166
1167static GtkSettings *
1168gtk_settings_style_provider_get_settings (GtkStyleProvider *provider)
1169{
1170 return GTK_SETTINGS (provider);
1171}
1172
1173static void
1174gtk_settings_provider_iface_init (GtkStyleProviderInterface *iface)
1175{
1176 iface->get_settings = gtk_settings_style_provider_get_settings;
1177}
1178
1179static void
1180gtk_settings_finalize (GObject *object)
1181{
1182 GtkSettings *settings = GTK_SETTINGS (object);
1183 guint i;
1184
1185 object_list = g_slist_remove (list: object_list, data: settings);
1186
1187 for (i = 0; i < class_n_properties; i++)
1188 g_value_unset (value: &settings->property_values[i].value);
1189 g_free (mem: settings->property_values);
1190
1191 g_datalist_clear (datalist: &settings->queued_settings);
1192
1193 settings_update_provider (display: settings->display, old: &settings->theme_provider, NULL);
1194 g_slist_free_full (list: settings->style_cascades, free_func: g_object_unref);
1195
1196 if (settings->font_options)
1197 cairo_font_options_destroy (options: settings->font_options);
1198
1199 g_free (mem: settings->font_family);
1200
1201 g_object_unref (object: settings->theme_provider);
1202
1203 G_OBJECT_CLASS (gtk_settings_parent_class)->finalize (object);
1204}
1205
1206GtkStyleCascade *
1207_gtk_settings_get_style_cascade (GtkSettings *settings,
1208 int scale)
1209{
1210 GtkStyleCascade *new_cascade;
1211 GSList *list;
1212
1213 g_return_val_if_fail (GTK_IS_SETTINGS (settings), NULL);
1214
1215 for (list = settings->style_cascades; list; list = list->next)
1216 {
1217 if (_gtk_style_cascade_get_scale (cascade: list->data) == scale)
1218 return list->data;
1219 }
1220
1221 /* We are guaranteed to have the special cascade with scale == 1.
1222 * It's created in gtk_settings_init()
1223 */
1224 g_assert (scale != 1);
1225
1226 new_cascade = _gtk_style_cascade_new ();
1227 _gtk_style_cascade_set_parent (cascade: new_cascade, parent: _gtk_settings_get_style_cascade (settings, scale: 1));
1228 _gtk_style_cascade_set_scale (cascade: new_cascade, scale);
1229
1230 settings->style_cascades = g_slist_prepend (list: settings->style_cascades, data: new_cascade);
1231
1232 return new_cascade;
1233}
1234
1235static void
1236settings_init_style (GtkSettings *settings)
1237{
1238 static GtkCssProvider *css_provider = NULL;
1239 GtkStyleCascade *cascade;
1240
1241 /* Add provider for user file */
1242 if (G_UNLIKELY (!css_provider))
1243 {
1244 char *css_path;
1245
1246 css_provider = gtk_css_provider_new ();
1247 css_path = g_build_filename (first_element: g_get_user_config_dir (),
1248 "gtk-4.0",
1249 "gtk.css",
1250 NULL);
1251
1252 if (g_file_test (filename: css_path,
1253 test: G_FILE_TEST_IS_REGULAR))
1254 gtk_css_provider_load_from_path (css_provider, path: css_path);
1255
1256 g_free (mem: css_path);
1257 }
1258
1259 cascade = _gtk_settings_get_style_cascade (settings, scale: 1);
1260 _gtk_style_cascade_add_provider (cascade,
1261 GTK_STYLE_PROVIDER (css_provider),
1262 GTK_STYLE_PROVIDER_PRIORITY_USER);
1263
1264 _gtk_style_cascade_add_provider (cascade,
1265 GTK_STYLE_PROVIDER (settings),
1266 GTK_STYLE_PROVIDER_PRIORITY_SETTINGS);
1267
1268 _gtk_style_cascade_add_provider (cascade,
1269 GTK_STYLE_PROVIDER (settings->theme_provider),
1270 GTK_STYLE_PROVIDER_PRIORITY_SETTINGS);
1271
1272 settings_update_theme (settings);
1273}
1274
1275static void
1276setting_changed (GdkDisplay *display,
1277 const char *name,
1278 gpointer data)
1279{
1280 GtkSettings *settings = data;
1281 GParamSpec *pspec;
1282
1283 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (settings), property_name: name);
1284
1285 if (!pspec)
1286 return;
1287
1288 if (settings_update_xsetting (settings, pspec, TRUE))
1289 g_object_notify_by_pspec (G_OBJECT (settings), pspec);
1290}
1291
1292static GtkSettings *
1293gtk_settings_create_for_display (GdkDisplay *display)
1294{
1295 GtkSettings *settings;
1296
1297#ifdef GDK_WINDOWING_MACOS
1298 if (GDK_IS_MACOS_DISPLAY (display))
1299 settings = g_object_new (GTK_TYPE_SETTINGS,
1300 "gtk-shell-shows-app-menu", TRUE,
1301 "gtk-shell-shows-menubar", TRUE,
1302 NULL);
1303 else
1304#endif
1305 settings = g_object_new (GTK_TYPE_SETTINGS, NULL);
1306
1307 settings->display = display;
1308
1309 g_signal_connect_object (instance: display, detailed_signal: "setting-changed", G_CALLBACK (setting_changed), gobject: settings, connect_flags: 0);
1310
1311 g_ptr_array_add (array: display_settings, data: settings);
1312
1313 settings_init_style (settings);
1314 settings_update_xsettings (settings);
1315 settings_update_double_click (settings);
1316 settings_update_cursor_theme (settings);
1317 settings_update_font_options (settings);
1318 settings_update_font_values (settings);
1319
1320 return settings;
1321}
1322
1323/**
1324 * gtk_settings_get_for_display:
1325 * @display: a `GdkDisplay`
1326 *
1327 * Gets the `GtkSettings` object for @display, creating it if necessary.
1328 *
1329 * Returns: (transfer none): a `GtkSettings` object
1330 */
1331GtkSettings *
1332gtk_settings_get_for_display (GdkDisplay *display)
1333{
1334 int i;
1335
1336 g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
1337
1338 if G_UNLIKELY (display_settings == NULL)
1339 display_settings = g_ptr_array_new ();
1340
1341 for (i = 0; i < display_settings->len; i++)
1342 {
1343 GtkSettings *settings = g_ptr_array_index (display_settings, i);
1344 if (settings->display == display)
1345 return settings;
1346 }
1347
1348 return gtk_settings_create_for_display (display);
1349}
1350
1351/**
1352 * gtk_settings_get_default:
1353 *
1354 * Gets the `GtkSettings` object for the default display, creating
1355 * it if necessary.
1356 *
1357 * See [func@Gtk.Settings.get_for_display].
1358 *
1359 * Returns: (nullable) (transfer none): a `GtkSettings` object. If there is
1360 * no default display, then returns %NULL.
1361 */
1362GtkSettings*
1363gtk_settings_get_default (void)
1364{
1365 GdkDisplay *display = gdk_display_get_default ();
1366
1367 if (display)
1368 return gtk_settings_get_for_display (display);
1369
1370 g_debug ("%s() returning NULL GtkSettings object. Is a display available?",
1371 G_STRFUNC);
1372 return NULL;
1373}
1374
1375static void
1376gtk_settings_set_property (GObject *object,
1377 guint property_id,
1378 const GValue *value,
1379 GParamSpec *pspec)
1380{
1381 GtkSettings *settings = GTK_SETTINGS (object);
1382
1383 g_value_copy (src_value: value, dest_value: &settings->property_values[property_id - 1].value);
1384 settings->property_values[property_id - 1].source = GTK_SETTINGS_SOURCE_APPLICATION;
1385}
1386
1387static void
1388settings_invalidate_style (GtkSettings *settings)
1389{
1390 gtk_style_provider_changed (GTK_STYLE_PROVIDER (settings));
1391}
1392
1393static void
1394settings_update_font_values (GtkSettings *settings)
1395{
1396 PangoFontDescription *desc;
1397 const char *font_name;
1398
1399 font_name = g_value_get_string (value: &settings->property_values[PROP_FONT_NAME - 1].value);
1400 desc = pango_font_description_from_string (str: font_name);
1401
1402 if (desc != NULL &&
1403 (pango_font_description_get_set_fields (desc) & PANGO_FONT_MASK_SIZE) != 0)
1404 {
1405 settings->font_size = pango_font_description_get_size (desc);
1406 settings->font_size_absolute = pango_font_description_get_size_is_absolute (desc);
1407 }
1408 else
1409 {
1410 settings->font_size = 10 * PANGO_SCALE;
1411 settings->font_size_absolute = FALSE;
1412 }
1413
1414 g_free (mem: settings->font_family);
1415
1416 if (desc != NULL &&
1417 (pango_font_description_get_set_fields (desc) & PANGO_FONT_MASK_FAMILY) != 0)
1418 {
1419 settings->font_family = g_strdup (str: pango_font_description_get_family (desc));
1420 }
1421 else
1422 {
1423 settings->font_family = g_strdup (str: "Sans");
1424 }
1425
1426 if (desc)
1427 pango_font_description_free (desc);
1428}
1429
1430static void
1431gtk_settings_notify (GObject *object,
1432 GParamSpec *pspec)
1433{
1434 GtkSettings *settings = GTK_SETTINGS (object);
1435 guint property_id = pspec->param_id;
1436
1437 if (settings->display == NULL) /* initialization */
1438 return;
1439
1440 switch (property_id)
1441 {
1442 case PROP_DOUBLE_CLICK_TIME:
1443 case PROP_DOUBLE_CLICK_DISTANCE:
1444 settings_update_double_click (settings);
1445 break;
1446 case PROP_FONT_NAME:
1447 settings_update_font_values (settings);
1448 settings_invalidate_style (settings);
1449 gtk_system_setting_changed (display: settings->display, setting: GTK_SYSTEM_SETTING_FONT_NAME);
1450 break;
1451 case PROP_THEME_NAME:
1452 case PROP_APPLICATION_PREFER_DARK_THEME:
1453 settings_update_theme (settings);
1454 break;
1455 case PROP_XFT_DPI:
1456 settings_invalidate_style (settings);
1457 gtk_system_setting_changed (display: settings->display, setting: GTK_SYSTEM_SETTING_DPI);
1458 break;
1459 case PROP_XFT_ANTIALIAS:
1460 case PROP_XFT_HINTING:
1461 case PROP_XFT_HINTSTYLE:
1462 case PROP_XFT_RGBA:
1463 case PROP_HINT_FONT_METRICS:
1464 settings_update_font_options (settings);
1465 gtk_system_setting_changed (display: settings->display, setting: GTK_SYSTEM_SETTING_FONT_CONFIG);
1466 break;
1467 case PROP_FONTCONFIG_TIMESTAMP:
1468 if (settings_update_fontconfig (settings))
1469 gtk_system_setting_changed (display: settings->display, setting: GTK_SYSTEM_SETTING_FONT_CONFIG);
1470 break;
1471 case PROP_ENABLE_ANIMATIONS:
1472 settings_invalidate_style (settings);
1473 break;
1474 case PROP_CURSOR_THEME_NAME:
1475 case PROP_CURSOR_THEME_SIZE:
1476 settings_update_cursor_theme (settings);
1477 break;
1478 default:
1479 break;
1480 }
1481}
1482
1483static gboolean
1484_gtk_settings_parse_convert (const GValue *src_value,
1485 GParamSpec *pspec,
1486 GValue *dest_value)
1487{
1488 gboolean success = FALSE;
1489
1490 g_return_val_if_fail (G_VALUE_HOLDS (dest_value, G_PARAM_SPEC_VALUE_TYPE (pspec)), FALSE);
1491
1492 if (G_VALUE_HOLDS (src_value, G_TYPE_GSTRING))
1493 {
1494 if (G_VALUE_HOLDS (dest_value, G_TYPE_STRING))
1495 {
1496 GString *gstring = g_value_get_boxed (value: src_value);
1497
1498 g_value_set_string (value: dest_value, v_string: gstring ? gstring->str : NULL);
1499 success = !g_param_value_validate (pspec, value: dest_value);
1500 }
1501 }
1502 else if (g_value_type_transformable (G_VALUE_TYPE (src_value), G_VALUE_TYPE (dest_value)))
1503 success = g_param_value_convert (pspec, src_value, dest_value, TRUE);
1504
1505 return success;
1506}
1507
1508static void
1509apply_queued_setting (GtkSettings *settings,
1510 GParamSpec *pspec,
1511 GtkSettingsValue *qvalue)
1512{
1513 GValue tmp_value = G_VALUE_INIT;
1514
1515 g_value_init (value: &tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1516 if (_gtk_settings_parse_convert (src_value: &qvalue->value,
1517 pspec, dest_value: &tmp_value))
1518 {
1519 if (settings->property_values[pspec->param_id - 1].source <= qvalue->source)
1520 {
1521 g_value_copy (src_value: &tmp_value, dest_value: &settings->property_values[pspec->param_id - 1].value);
1522 settings->property_values[pspec->param_id - 1].source = qvalue->source;
1523 g_object_notify_by_pspec (G_OBJECT (settings), pspec);
1524 }
1525
1526 }
1527 else
1528 {
1529 char *debug = g_strdup_value_contents (value: &qvalue->value);
1530
1531 g_message ("%s: failed to retrieve property '%s' of type '%s' from rc file value \"%s\" of type '%s'",
1532 qvalue->origin ? qvalue->origin : "(for origin information, set GTK_DEBUG)",
1533 pspec->name,
1534 g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
1535 debug,
1536 G_VALUE_TYPE_NAME (&tmp_value));
1537 g_free (mem: debug);
1538 }
1539 g_value_unset (value: &tmp_value);
1540}
1541
1542static guint
1543settings_install_property_parser (GtkSettingsClass *class,
1544 GParamSpec *pspec)
1545{
1546 GSList *node, *next;
1547
1548 switch (G_TYPE_FUNDAMENTAL (G_PARAM_SPEC_VALUE_TYPE (pspec)))
1549 {
1550 case G_TYPE_BOOLEAN:
1551 case G_TYPE_UCHAR:
1552 case G_TYPE_CHAR:
1553 case G_TYPE_UINT:
1554 case G_TYPE_INT:
1555 case G_TYPE_ULONG:
1556 case G_TYPE_LONG:
1557 case G_TYPE_FLOAT:
1558 case G_TYPE_DOUBLE:
1559 case G_TYPE_STRING:
1560 case G_TYPE_ENUM:
1561 break;
1562 case G_TYPE_BOXED:
1563 default:
1564 g_warning (G_STRLOC ": no parser for property \"%s\" of type '%s'",
1565 pspec->name, g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
1566 return 0;
1567 }
1568 if (g_object_class_find_property (G_OBJECT_CLASS (class), property_name: pspec->name))
1569 {
1570 g_warning (G_STRLOC ": an rc-data property \"%s\" already exists",
1571 pspec->name);
1572 return 0;
1573 }
1574
1575 for (node = object_list; node; node = node->next)
1576 g_object_freeze_notify (object: node->data);
1577
1578 g_object_class_install_property (G_OBJECT_CLASS (class), property_id: ++class_n_properties, pspec);
1579
1580 for (node = object_list; node; node = node->next)
1581 {
1582 GtkSettings *settings = node->data;
1583 GtkSettingsValue *qvalue;
1584
1585 settings->property_values = g_renew (GtkSettingsPropertyValue, settings->property_values, class_n_properties);
1586 settings->property_values[class_n_properties - 1].value.g_type = 0;
1587 g_value_init (value: &settings->property_values[class_n_properties - 1].value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1588 g_param_value_set_default (pspec, value: &settings->property_values[class_n_properties - 1].value);
1589 settings->property_values[class_n_properties - 1].source = GTK_SETTINGS_SOURCE_DEFAULT;
1590 g_object_notify_by_pspec (G_OBJECT (settings), pspec);
1591
1592 qvalue = g_datalist_id_dup_data (datalist: &settings->queued_settings, key_id: g_param_spec_get_name_quark (pspec), NULL, NULL);
1593 if (qvalue)
1594 apply_queued_setting (settings, pspec, qvalue);
1595 }
1596
1597 for (node = object_list; node; node = next)
1598 {
1599 next = node->next;
1600 g_object_thaw_notify (object: node->data);
1601 }
1602
1603 return class_n_properties;
1604}
1605
1606static void
1607free_value (gpointer data)
1608{
1609 GtkSettingsValue *qvalue = data;
1610
1611 g_value_unset (value: &qvalue->value);
1612 g_free (mem: qvalue->origin);
1613 g_slice_free (GtkSettingsValue, qvalue);
1614}
1615
1616static void
1617gtk_settings_set_property_value_internal (GtkSettings *settings,
1618 const char *prop_name,
1619 const GtkSettingsValue *new_value,
1620 GtkSettingsSource source)
1621{
1622 GtkSettingsValue *qvalue;
1623 GParamSpec *pspec;
1624 char *name;
1625 GQuark name_quark;
1626
1627 if (!G_VALUE_HOLDS_LONG (&new_value->value) &&
1628 !G_VALUE_HOLDS_DOUBLE (&new_value->value) &&
1629 !G_VALUE_HOLDS_STRING (&new_value->value) &&
1630 !G_VALUE_HOLDS (&new_value->value, G_TYPE_GSTRING))
1631 {
1632 g_warning (G_STRLOC ": value type invalid (%s)", g_type_name (G_VALUE_TYPE (&new_value->value)));
1633 return;
1634 }
1635
1636 name = g_strdup (str: prop_name);
1637 g_strcanon (string: name, G_CSET_DIGITS "-" G_CSET_a_2_z G_CSET_A_2_Z, substitutor: '-');
1638 name_quark = g_quark_from_string (string: name);
1639 g_free (mem: name);
1640
1641 qvalue = g_datalist_id_dup_data (datalist: &settings->queued_settings, key_id: name_quark, NULL, NULL);
1642 if (!qvalue)
1643 {
1644 qvalue = g_slice_new0 (GtkSettingsValue);
1645 g_datalist_id_set_data_full (datalist: &settings->queued_settings, key_id: name_quark, data: qvalue, destroy_func: free_value);
1646 }
1647 else
1648 {
1649 g_free (mem: qvalue->origin);
1650 g_value_unset (value: &qvalue->value);
1651 }
1652 qvalue->origin = g_strdup (str: new_value->origin);
1653 g_value_init (value: &qvalue->value, G_VALUE_TYPE (&new_value->value));
1654 g_value_copy (src_value: &new_value->value, dest_value: &qvalue->value);
1655 qvalue->source = source;
1656 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (settings), property_name: g_quark_to_string (quark: name_quark));
1657 if (pspec)
1658 apply_queued_setting (settings, pspec, qvalue);
1659}
1660
1661static void
1662settings_update_double_click (GtkSettings *settings)
1663{
1664 int double_click_time;
1665 int double_click_distance;
1666
1667 g_object_get (object: settings,
1668 first_property_name: "gtk-double-click-time", &double_click_time,
1669 "gtk-double-click-distance", &double_click_distance,
1670 NULL);
1671
1672 gdk_display_set_double_click_time (display: settings->display, msec: double_click_time);
1673 gdk_display_set_double_click_distance (display: settings->display, distance: double_click_distance);
1674}
1675
1676static void
1677settings_update_cursor_theme (GtkSettings *settings)
1678{
1679 char *theme = NULL;
1680 int size = 0;
1681
1682 g_object_get (object: settings,
1683 first_property_name: "gtk-cursor-theme-name", &theme,
1684 "gtk-cursor-theme-size", &size,
1685 NULL);
1686 if (theme)
1687 {
1688 gdk_display_set_cursor_theme (display: settings->display, theme, size);
1689 g_free (mem: theme);
1690 }
1691}
1692
1693static void
1694settings_update_font_options (GtkSettings *settings)
1695{
1696 int hinting;
1697 char *hint_style_str;
1698 cairo_hint_style_t hint_style;
1699 int antialias;
1700 cairo_antialias_t antialias_mode;
1701 char *rgba_str;
1702 cairo_subpixel_order_t subpixel_order;
1703 gboolean hint_font_metrics;
1704
1705 if (settings->font_options)
1706 cairo_font_options_destroy (options: settings->font_options);
1707
1708 g_object_get (object: settings,
1709 first_property_name: "gtk-xft-antialias", &antialias,
1710 "gtk-xft-hinting", &hinting,
1711 "gtk-xft-hintstyle", &hint_style_str,
1712 "gtk-xft-rgba", &rgba_str,
1713 "gtk-hint-font-metrics", &hint_font_metrics,
1714 NULL);
1715
1716 settings->font_options = cairo_font_options_create ();
1717
1718 cairo_font_options_set_hint_metrics (options: settings->font_options,
1719 hint_metrics: hint_font_metrics ? CAIRO_HINT_METRICS_ON
1720 : CAIRO_HINT_METRICS_OFF);
1721
1722 hint_style = CAIRO_HINT_STYLE_DEFAULT;
1723 if (hinting == 0)
1724 {
1725 hint_style = CAIRO_HINT_STYLE_NONE;
1726 }
1727 else if (hinting == 1)
1728 {
1729 if (hint_style_str)
1730 {
1731 if (strcmp (s1: hint_style_str, s2: "hintnone") == 0)
1732 hint_style = CAIRO_HINT_STYLE_NONE;
1733 else if (strcmp (s1: hint_style_str, s2: "hintslight") == 0)
1734 hint_style = CAIRO_HINT_STYLE_SLIGHT;
1735 else if (strcmp (s1: hint_style_str, s2: "hintmedium") == 0)
1736 hint_style = CAIRO_HINT_STYLE_MEDIUM;
1737 else if (strcmp (s1: hint_style_str, s2: "hintfull") == 0)
1738 hint_style = CAIRO_HINT_STYLE_FULL;
1739 }
1740 }
1741
1742 g_free (mem: hint_style_str);
1743
1744 cairo_font_options_set_hint_style (options: settings->font_options, hint_style);
1745
1746 subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT;
1747 if (rgba_str)
1748 {
1749 if (strcmp (s1: rgba_str, s2: "rgb") == 0)
1750 subpixel_order = CAIRO_SUBPIXEL_ORDER_RGB;
1751 else if (strcmp (s1: rgba_str, s2: "bgr") == 0)
1752 subpixel_order = CAIRO_SUBPIXEL_ORDER_BGR;
1753 else if (strcmp (s1: rgba_str, s2: "vrgb") == 0)
1754 subpixel_order = CAIRO_SUBPIXEL_ORDER_VRGB;
1755 else if (strcmp (s1: rgba_str, s2: "vbgr") == 0)
1756 subpixel_order = CAIRO_SUBPIXEL_ORDER_VBGR;
1757 }
1758
1759 g_free (mem: rgba_str);
1760
1761 cairo_font_options_set_subpixel_order (options: settings->font_options, subpixel_order);
1762
1763 antialias_mode = CAIRO_ANTIALIAS_DEFAULT;
1764 if (antialias == 0)
1765 {
1766 antialias_mode = CAIRO_ANTIALIAS_NONE;
1767 }
1768 else if (antialias == 1)
1769 {
1770 if (subpixel_order != CAIRO_SUBPIXEL_ORDER_DEFAULT)
1771 antialias_mode = CAIRO_ANTIALIAS_SUBPIXEL;
1772 else
1773 antialias_mode = CAIRO_ANTIALIAS_GRAY;
1774 }
1775
1776 cairo_font_options_set_antialias (options: settings->font_options, antialias: antialias_mode);
1777}
1778
1779static gboolean
1780settings_update_fontconfig (GtkSettings *settings)
1781{
1782#if defined(GDK_WINDOWING_X11) || defined(GDK_WINDOWING_WAYLAND)
1783 static guint last_update_timestamp;
1784 static gboolean last_update_needed;
1785
1786 guint timestamp;
1787
1788 g_object_get (object: settings,
1789 first_property_name: "gtk-fontconfig-timestamp", &timestamp,
1790 NULL);
1791
1792 /* if timestamp is the same as last_update_timestamp, we already have
1793 * updated fontconig on this timestamp (another screen requested it perhaps?),
1794 * just return the cached result.*/
1795
1796 if (timestamp != last_update_timestamp)
1797 {
1798 PangoFontMap *fontmap = pango_cairo_font_map_get_default ();
1799 gboolean update_needed = FALSE;
1800
1801 /* bug 547680 */
1802 if (PANGO_IS_FC_FONT_MAP (fontmap) && !FcConfigUptoDate (NULL))
1803 {
1804 pango_fc_font_map_config_changed (PANGO_FC_FONT_MAP (fontmap));
1805 if (FcInitReinitialize ())
1806 update_needed = TRUE;
1807 }
1808
1809 last_update_timestamp = timestamp;
1810 last_update_needed = update_needed;
1811 }
1812
1813 return last_update_needed;
1814#else
1815 return FALSE;
1816#endif /* GDK_WINDOWING_X11 || GDK_WINDOWING_WAYLAND */
1817}
1818
1819static void
1820settings_update_provider (GdkDisplay *display,
1821 GtkCssProvider **old,
1822 GtkCssProvider *new)
1823{
1824 if (display != NULL && *old != new)
1825 {
1826 if (*old)
1827 {
1828 gtk_style_context_remove_provider_for_display (display,
1829 GTK_STYLE_PROVIDER (*old));
1830 g_object_unref (object: *old);
1831 *old = NULL;
1832 }
1833
1834 if (new)
1835 {
1836 gtk_style_context_add_provider_for_display (display,
1837 GTK_STYLE_PROVIDER (new),
1838 GTK_STYLE_PROVIDER_PRIORITY_THEME);
1839 *old = g_object_ref (new);
1840 }
1841 }
1842}
1843
1844static void
1845get_theme_name (GtkSettings *settings,
1846 char **theme_name,
1847 char **theme_variant)
1848{
1849 gboolean prefer_dark;
1850
1851 *theme_name = NULL;
1852 *theme_variant = NULL;
1853
1854 if (g_getenv (variable: "GTK_THEME"))
1855 *theme_name = g_strdup (str: g_getenv (variable: "GTK_THEME"));
1856
1857 if (*theme_name && **theme_name)
1858 {
1859 char *p;
1860 p = strrchr (s: *theme_name, c: ':');
1861 if (p) {
1862 *p = '\0';
1863 p++;
1864 *theme_variant = g_strdup (str: p);
1865 }
1866
1867 return;
1868 }
1869
1870 g_free (mem: *theme_name);
1871
1872 g_object_get (object: settings,
1873 first_property_name: "gtk-theme-name", theme_name,
1874 "gtk-application-prefer-dark-theme", &prefer_dark,
1875 NULL);
1876
1877 if (prefer_dark)
1878 *theme_variant = g_strdup (str: "dark");
1879
1880 if (*theme_name && **theme_name)
1881 return;
1882
1883 g_free (mem: *theme_name);
1884 *theme_name = g_strdup (DEFAULT_THEME_NAME);
1885}
1886
1887static void
1888settings_update_theme (GtkSettings *settings)
1889{
1890 char *theme_name;
1891 char *theme_variant;
1892 const char *theme_dir;
1893 char *path;
1894
1895 get_theme_name (settings, theme_name: &theme_name, theme_variant: &theme_variant);
1896
1897 gtk_css_provider_load_named (provider: settings->theme_provider,
1898 name: theme_name,
1899 variant: theme_variant);
1900
1901 /* reload per-theme settings */
1902 theme_dir = _gtk_css_provider_get_theme_dir (provider: settings->theme_provider);
1903 if (theme_dir)
1904 {
1905 path = g_build_filename (first_element: theme_dir, "settings.ini", NULL);
1906 gtk_settings_load_from_key_file (settings, path, source: GTK_SETTINGS_SOURCE_THEME);
1907 g_free (mem: path);
1908 }
1909
1910 g_free (mem: theme_name);
1911 g_free (mem: theme_variant);
1912}
1913
1914const cairo_font_options_t *
1915gtk_settings_get_font_options (GtkSettings *settings)
1916{
1917 return settings->font_options;
1918}
1919
1920GdkDisplay *
1921_gtk_settings_get_display (GtkSettings *settings)
1922{
1923 return settings->display;
1924}
1925
1926static void
1927gvalue_free (gpointer data)
1928{
1929 g_value_unset (value: data);
1930 g_free (mem: data);
1931}
1932
1933static void
1934gtk_settings_load_from_key_file (GtkSettings *settings,
1935 const char *path,
1936 GtkSettingsSource source)
1937{
1938 GError *error;
1939 GKeyFile *keyfile;
1940 char **keys;
1941 gsize n_keys;
1942 int i;
1943 char *contents;
1944 gsize contents_len;
1945
1946 if (!g_file_get_contents (filename: path, contents: &contents, length: &contents_len, NULL))
1947 return;
1948
1949 error = NULL;
1950 keys = NULL;
1951
1952 keyfile = g_key_file_new ();
1953
1954 if (!g_key_file_load_from_data (key_file: keyfile, data: contents, length: contents_len, flags: G_KEY_FILE_NONE, error: &error))
1955 {
1956 g_warning ("Failed to parse %s: %s", path, error->message);
1957
1958 g_error_free (error);
1959
1960 goto out;
1961 }
1962
1963 keys = g_key_file_get_keys (key_file: keyfile, group_name: "Settings", length: &n_keys, error: &error);
1964 if (error)
1965 {
1966 g_warning ("Failed to parse %s: %s", path, error->message);
1967 g_error_free (error);
1968 goto out;
1969 }
1970
1971 for (i = 0; i < n_keys; i++)
1972 {
1973 char *key;
1974 GParamSpec *pspec;
1975 GType value_type;
1976 GtkSettingsValue svalue = { NULL, G_VALUE_INIT, GTK_SETTINGS_SOURCE_DEFAULT };
1977
1978 key = keys[i];
1979 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (settings), property_name: key);
1980 if (!pspec)
1981 {
1982 g_warning ("Unknown key %s in %s", key, path);
1983 continue;
1984 }
1985
1986 if (pspec->owner_type != G_OBJECT_TYPE (settings))
1987 continue;
1988
1989 value_type = G_PARAM_SPEC_VALUE_TYPE (pspec);
1990 switch (value_type)
1991 {
1992 case G_TYPE_BOOLEAN:
1993 {
1994 gboolean b_val;
1995
1996 g_value_init (value: &svalue.value, G_TYPE_LONG);
1997 b_val = g_key_file_get_boolean (key_file: keyfile, group_name: "Settings", key, error: &error);
1998 if (!error)
1999 g_value_set_long (value: &svalue.value, v_long: b_val);
2000 break;
2001 }
2002
2003 case G_TYPE_INT:
2004 case G_TYPE_UINT:
2005 {
2006 int i_val;
2007
2008 g_value_init (value: &svalue.value, G_TYPE_LONG);
2009 i_val = g_key_file_get_integer (key_file: keyfile, group_name: "Settings", key, error: &error);
2010 if (!error)
2011 g_value_set_long (value: &svalue.value, v_long: i_val);
2012 break;
2013 }
2014
2015 case G_TYPE_DOUBLE:
2016 {
2017 double d_val;
2018
2019 g_value_init (value: &svalue.value, G_TYPE_DOUBLE);
2020 d_val = g_key_file_get_double (key_file: keyfile, group_name: "Settings", key, error: &error);
2021 if (!error)
2022 g_value_set_double (value: &svalue.value, v_double: d_val);
2023 break;
2024 }
2025
2026 default:
2027 {
2028 char *s_val;
2029
2030 g_value_init (value: &svalue.value, G_TYPE_GSTRING);
2031 s_val = g_key_file_get_string (key_file: keyfile, group_name: "Settings", key, error: &error);
2032 if (!error)
2033 g_value_take_boxed (value: &svalue.value, v_boxed: g_string_new (init: s_val));
2034 g_free (mem: s_val);
2035 break;
2036 }
2037 }
2038 if (error)
2039 {
2040 g_warning ("Error setting %s in %s: %s", key, path, error->message);
2041 g_error_free (error);
2042 error = NULL;
2043 }
2044 else
2045 {
2046 GValue *copy;
2047
2048 copy = g_new0 (GValue, 1);
2049
2050 g_value_init (value: copy, G_VALUE_TYPE (&svalue.value));
2051 g_value_copy (src_value: &svalue.value, dest_value: copy);
2052
2053 g_param_spec_set_qdata_full (pspec, quark: g_quark_from_string (string: key),
2054 data: copy, destroy: gvalue_free);
2055
2056 if (g_getenv (variable: "GTK_DEBUG"))
2057 svalue.origin = (char *)path;
2058
2059 gtk_settings_set_property_value_internal (settings, prop_name: key, new_value: &svalue, source);
2060 g_value_unset (value: &svalue.value);
2061 }
2062 }
2063
2064 out:
2065 g_free (mem: contents);
2066 g_strfreev (str_array: keys);
2067 g_key_file_free (key_file: keyfile);
2068}
2069
2070static gboolean
2071settings_update_xsetting (GtkSettings *settings,
2072 GParamSpec *pspec,
2073 gboolean force)
2074{
2075 GType value_type;
2076 GType fundamental_type;
2077 gboolean retval = FALSE;
2078
2079 if (settings->property_values[pspec->param_id - 1].source == GTK_SETTINGS_SOURCE_APPLICATION)
2080 return FALSE;
2081
2082 if (settings->property_values[pspec->param_id - 1].source == GTK_SETTINGS_SOURCE_XSETTING && !force)
2083 return FALSE;
2084
2085 value_type = G_PARAM_SPEC_VALUE_TYPE (pspec);
2086 fundamental_type = G_TYPE_FUNDAMENTAL (value_type);
2087
2088 if ((g_value_type_transformable (G_TYPE_INT, dest_type: value_type) &&
2089 !(fundamental_type == G_TYPE_ENUM || fundamental_type == G_TYPE_FLAGS)) ||
2090 g_value_type_transformable (G_TYPE_STRING, dest_type: value_type) ||
2091 g_value_type_transformable (GDK_TYPE_RGBA, dest_type: value_type))
2092 {
2093 GValue val = G_VALUE_INIT;
2094
2095 g_value_init (value: &val, g_type: value_type);
2096
2097 if (!gdk_display_get_setting (display: settings->display, name: pspec->name, value: &val))
2098 return FALSE;
2099
2100 g_param_value_validate (pspec, value: &val);
2101 g_value_copy (src_value: &val, dest_value: &settings->property_values[pspec->param_id - 1].value);
2102 settings->property_values[pspec->param_id - 1].source = GTK_SETTINGS_SOURCE_XSETTING;
2103
2104 g_value_unset (value: &val);
2105
2106 retval = TRUE;
2107 }
2108 else
2109 {
2110 return FALSE;
2111 }
2112
2113 return retval;
2114}
2115
2116static void
2117settings_update_xsettings (GtkSettings *settings)
2118{
2119 GParamSpec **pspecs;
2120 int i;
2121
2122 pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (settings), NULL);
2123 for (i = 0; pspecs[i]; i++)
2124 settings_update_xsetting (settings, pspec: pspecs[i], FALSE);
2125 g_free (mem: pspecs);
2126}
2127
2128static void
2129gtk_settings_get_property (GObject *object,
2130 guint property_id,
2131 GValue *value,
2132 GParamSpec *pspec)
2133{
2134 GtkSettings *settings = GTK_SETTINGS (object);
2135
2136 settings_update_xsetting (settings, pspec, FALSE);
2137
2138 g_value_copy (src_value: &settings->property_values[property_id - 1].value, dest_value: value);
2139}
2140
2141GtkSettingsSource
2142_gtk_settings_get_setting_source (GtkSettings *settings,
2143 const char *name)
2144{
2145 GParamSpec *pspec;
2146
2147 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (settings), property_name: name);
2148 if (!pspec)
2149 return GTK_SETTINGS_SOURCE_DEFAULT;
2150
2151 return settings->property_values[pspec->param_id - 1].source;
2152}
2153
2154/**
2155 * gtk_settings_reset_property:
2156 * @settings: a `GtkSettings` object
2157 * @name: the name of the setting to reset
2158 *
2159 * Undoes the effect of calling g_object_set() to install an
2160 * application-specific value for a setting.
2161 *
2162 * After this call, the setting will again follow the session-wide
2163 * value for this setting.
2164 */
2165void
2166gtk_settings_reset_property (GtkSettings *settings,
2167 const char *name)
2168{
2169 GParamSpec *pspec;
2170 GValue *value;
2171 GValue tmp_value = G_VALUE_INIT;
2172
2173 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (settings), property_name: name);
2174
2175 g_return_if_fail (pspec != NULL);
2176
2177 value = g_param_spec_get_qdata (pspec, quark: g_quark_from_string (string: name));
2178
2179 g_value_init (value: &tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
2180 if (value && _gtk_settings_parse_convert (src_value: value, pspec, dest_value: &tmp_value))
2181 g_value_copy (src_value: &tmp_value, dest_value: &settings->property_values[pspec->param_id - 1].value);
2182 else
2183 g_param_value_set_default (pspec, value: &settings->property_values[pspec->param_id - 1].value);
2184
2185 settings->property_values[pspec->param_id - 1].source = GTK_SETTINGS_SOURCE_DEFAULT;
2186 g_object_notify_by_pspec (G_OBJECT (settings), pspec);
2187}
2188
2189gboolean
2190gtk_settings_get_enable_animations (GtkSettings *settings)
2191{
2192 GtkSettingsPropertyValue *svalue = &settings->property_values[PROP_ENABLE_ANIMATIONS - 1];
2193
2194 if (svalue->source < GTK_SETTINGS_SOURCE_XSETTING)
2195 {
2196 GParamSpec *pspec;
2197
2198 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (settings), property_name: "gtk-enable-animations");
2199 if (settings_update_xsetting (settings, pspec, FALSE))
2200 g_object_notify_by_pspec (G_OBJECT (settings), pspec);
2201 }
2202
2203 return g_value_get_boolean (value: &svalue->value);
2204}
2205
2206int
2207gtk_settings_get_dnd_drag_threshold (GtkSettings *settings)
2208{
2209 GtkSettingsPropertyValue *svalue = &settings->property_values[PROP_DND_DRAG_THRESHOLD - 1];
2210
2211 if (svalue->source < GTK_SETTINGS_SOURCE_XSETTING)
2212 {
2213 GParamSpec *pspec;
2214
2215 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (settings), property_name: "gtk-dnd-drag-threshold");
2216 if (settings_update_xsetting (settings, pspec, FALSE))
2217 g_object_notify_by_pspec (G_OBJECT (settings), pspec);
2218 }
2219
2220 return g_value_get_int (value: &svalue->value);
2221}
2222
2223static void
2224settings_update_font_name (GtkSettings *settings)
2225{
2226 GtkSettingsPropertyValue *svalue = &settings->property_values[PROP_FONT_NAME - 1];
2227
2228 if (svalue->source < GTK_SETTINGS_SOURCE_XSETTING)
2229 {
2230 GParamSpec *pspec;
2231
2232 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (settings), property_name: "gtk-font-name");
2233 if (settings_update_xsetting (settings, pspec, FALSE))
2234 g_object_notify_by_pspec (G_OBJECT (settings), pspec);
2235 }
2236}
2237
2238const char *
2239gtk_settings_get_font_family (GtkSettings *settings)
2240{
2241 settings_update_font_name (settings);
2242
2243 return settings->font_family;
2244}
2245
2246int
2247gtk_settings_get_font_size (GtkSettings *settings)
2248{
2249 settings_update_font_name (settings);
2250
2251 return settings->font_size;
2252}
2253
2254gboolean
2255gtk_settings_get_font_size_is_absolute (GtkSettings *settings)
2256{
2257 settings_update_font_name (settings);
2258
2259 return settings->font_size_absolute;
2260}
2261

source code of gtk/gtk/gtksettings.c