1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3 /* Metacity preferences */
4
5 /*
6 * Copyright (C) 2001 Havoc Pennington, Copyright (C) 2002 Red Hat Inc.
7 * Copyright (C) 2006 Elijah Newren
8 * Copyright (C) 2008 Thomas Thurman
9 * Copyright (C) 2010 Milan Bouchet-Valat, Copyright (C) 2011 Red Hat Inc.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License as
13 * published by the Free Software Foundation; either version 2 of the
14 * License, or (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, see <http://www.gnu.org/licenses/>.
23 */
24
25 #include <config.h>
26 #include "prefs.h"
27 #include "ui.h"
28 #include "util.h"
29 #include <glib.h>
30 #include <gio/gio.h>
31 #include <string.h>
32 #include <stdlib.h>
33 #include "keybindings.h"
34
35 /* If you add a key, it needs updating in init() and in the gsettings
36 * notify listener and of course in the .schemas file.
37 *
38 * Keys which are handled by one of the unified handlers below are
39 * not given a name here, because the purpose of the unified handlers
40 * is that keys should be referred to exactly once.
41 */
42 #define KEY_TITLEBAR_FONT "titlebar-font"
43 #define KEY_NUM_WORKSPACES "num-workspaces"
44 #define KEY_WORKSPACE_NAMES "workspace-names"
45 #define KEY_COMPOSITING_MANAGER "compositing-manager"
46 #define KEY_PLACEMENT_MODE "placement-mode"
47
48 /* Keys from "foreign" schemas */
49 #define KEY_GNOME_ACCESSIBILITY "toolkit-accessibility"
50 #define KEY_GNOME_ANIMATIONS "enable-animations"
51 #define KEY_GNOME_CURSOR_THEME "cursor-theme"
52
53 /* These are the different schemas we are keeping
54 * a GSettings instance for */
55 #define SCHEMA_GENERAL "org.gnome.desktop.wm.preferences"
56 #define SCHEMA_METACITY "org.gnome.metacity"
57 #define SCHEMA_METACITY_THEME "org.gnome.metacity.theme"
58 #define SCHEMA_INTERFACE "org.gnome.desktop.interface"
59
60 #define SETTINGS(s) g_hash_table_lookup (settings_schemas, (s))
61
62 static GList *changes = NULL;
63 static guint changed_idle;
64 static GList *listeners = NULL;
65 static GHashTable *settings_schemas;
66
67 static gboolean use_system_font = FALSE;
68 static PangoFontDescription *titlebar_font = NULL;
69 static MetaVirtualModifier mouse_button_mods = Mod1Mask;
70 static GDesktopFocusMode focus_mode = G_DESKTOP_FOCUS_MODE_CLICK;
71 static GDesktopFocusNewWindows focus_new_windows = G_DESKTOP_FOCUS_NEW_WINDOWS_SMART;
72 static gboolean raise_on_click = TRUE;
73 static gboolean attach_modal_dialogs = FALSE;
74 static gchar *current_theme_name = NULL;
75 static MetaThemeType current_theme_type = META_THEME_TYPE_GTK;
76 static int num_workspaces = 4;
77 static GDesktopTitlebarAction action_double_click_titlebar = G_DESKTOP_TITLEBAR_ACTION_TOGGLE_MAXIMIZE;
78 static GDesktopTitlebarAction action_middle_click_titlebar = G_DESKTOP_TITLEBAR_ACTION_LOWER;
79 static GDesktopTitlebarAction action_right_click_titlebar = G_DESKTOP_TITLEBAR_ACTION_MENU;
80 static gboolean disable_workarounds = FALSE;
81 static gboolean auto_raise = FALSE;
82 static gboolean auto_raise_delay = 500;
83 static gboolean bell_is_visible = FALSE;
84 static gboolean bell_is_audible = TRUE;
85 static gboolean gnome_accessibility = FALSE;
86 static gboolean gnome_animations = TRUE;
87 static char *cursor_theme = NULL;
88 static int cursor_size = 24;
89 static MetaCompositorType compositor = META_COMPOSITOR_TYPE_XRENDER;
90 static gboolean resize_with_right_button = FALSE;
91 static gboolean edge_tiling = FALSE;
92 static gboolean force_fullscreen = TRUE;
93 static gboolean alt_tab_thumbnails = FALSE;
94
95 static GDesktopVisualBellType visual_bell_type = G_DESKTOP_VISUAL_BELL_FULLSCREEN_FLASH;
96 static gchar *button_layout;
97
98 static MetaPlacementMode placement_mode = META_PLACEMENT_MODE_SMART;
99
100 /* NULL-terminated array */
101 static char **workspace_names = NULL;
102
103 static void handle_preference_update_enum (GSettings *settings,
104 gchar *key);
105
106 static gboolean update_binding (MetaKeyPref *binding,
107 gchar **strokes);
108 static gboolean update_key_binding (const char *key,
109 gchar **strokes);
110 static gboolean update_workspace_names (void);
111
112 static void settings_changed (GSettings *settings,
113 gchar *key,
114 gpointer data);
115 static void bindings_changed (GSettings *settings,
116 gchar *key,
117 gpointer data);
118
119
120 static void queue_changed (MetaPreference pref);
121
122 static void maybe_give_disable_workarounds_warning (void);
123
124 static gboolean titlebar_handler (GVariant*, gpointer*, gpointer);
125 static gboolean theme_name_handler (GVariant*, gpointer*, gpointer);
126 static gboolean mouse_button_mods_handler (GVariant*, gpointer*, gpointer);
127 static gboolean button_layout_handler (GVariant*, gpointer*, gpointer);
128
129 static void init_bindings (void);
130 static void init_workspace_names (void);
131
132 static void update_button_layout (const gchar *string_value);
133
134 typedef struct
135 {
136 MetaPrefsChangedFunc func;
137 gpointer data;
138 } MetaPrefsListener;
139
140 typedef struct
141 {
142 const gchar *key;
143 const gchar *schema;
144 MetaPreference pref;
145 } MetaBasePreference;
146
147 typedef struct
148 {
149 MetaBasePreference base;
150 gpointer target;
151 } MetaEnumPreference;
152
153 typedef struct
154 {
155 MetaBasePreference base;
156 gboolean *target;
157 gboolean becomes_true_on_destruction;
158 } MetaBoolPreference;
159
160 typedef struct
161 {
162 MetaBasePreference base;
163
164 /**
165 * A handler. Many of the string preferences aren't stored as
166 * strings and need parsing; others of them have default values
167 * which can't be solved in the general case. If you include a
168 * function pointer here, it will be called instead of writing
169 * the string value out to the target variable.
170 *
171 * The function will be passed to g_settings_get_mapped() and should
172 * return %TRUE if the mapping was successful and %FALSE otherwise.
173 * In the former case the function is expected to handle the result
174 * of the conversion itself and call queue_changed() appropriately;
175 * in particular the @result (out) parameter as returned by
176 * g_settings_get_mapped() will be ignored in all cases.
177 *
178 * This may be NULL. If it is, see "target", below.
179 */
180 GSettingsGetMapping handler;
181
182 /**
183 * Where to write the incoming string.
184 *
185 * This must be NULL if the handler is non-NULL.
186 * If the incoming string is NULL, no change will be made.
187 */
188 gchar **target;
189
190 } MetaStringPreference;
191
192 typedef struct
193 {
194 MetaBasePreference base;
195 gint *target;
196 } MetaIntPreference;
197
198
199 /* All preferences that are not keybindings must be listed here,
200 * plus in the GSettings schemas and the MetaPreference enum.
201 */
202
203 /* FIXMEs: */
204 /* @@@ Don't use NULL lines at the end; glib can tell you how big it is */
205 static MetaEnumPreference preferences_enum[] =
206 {
207 {
208 { "focus-new-windows",
209 SCHEMA_GENERAL,
210 META_PREF_FOCUS_NEW_WINDOWS,
211 },
212 &focus_new_windows,
213 },
214 {
215 { "focus-mode",
216 SCHEMA_GENERAL,
217 META_PREF_FOCUS_MODE,
218 },
219 &focus_mode,
220 },
221 {
222 { "visual-bell-type",
223 SCHEMA_GENERAL,
224 META_PREF_VISUAL_BELL_TYPE,
225 },
226 &visual_bell_type,
227 },
228 {
229 { "action-double-click-titlebar",
230 SCHEMA_GENERAL,
231 META_PREF_ACTION_DOUBLE_CLICK_TITLEBAR,
232 },
233 &action_double_click_titlebar,
234 },
235 {
236 { "action-middle-click-titlebar",
237 SCHEMA_GENERAL,
238 META_PREF_ACTION_MIDDLE_CLICK_TITLEBAR,
239 },
240 &action_middle_click_titlebar,
241 },
242 {
243 { "action-right-click-titlebar",
244 SCHEMA_GENERAL,
245 META_PREF_ACTION_RIGHT_CLICK_TITLEBAR,
246 },
247 &action_right_click_titlebar,
248 },
249 {
250 { "placement-mode",
251 SCHEMA_METACITY,
252 META_PREF_PLACEMENT_MODE,
253 },
254 &placement_mode,
255 },
256 {
257 { "type",
258 SCHEMA_METACITY_THEME,
259 META_PREF_THEME_TYPE,
260 },
261 ¤t_theme_type,
262 },
263 {
264 { "compositor",
265 SCHEMA_METACITY,
266 META_PREF_COMPOSITOR,
267 },
268 &compositor,
269 },
270 { { NULL, 0, 0 }, NULL },
271 };
272
273 static MetaBoolPreference preferences_bool[] =
274 {
275 {
276 { "raise-on-click",
277 SCHEMA_GENERAL,
278 META_PREF_RAISE_ON_CLICK,
279 },
280 &raise_on_click,
281 TRUE,
282 },
283 {
284 { "titlebar-uses-system-font",
285 SCHEMA_GENERAL,
286 META_PREF_TITLEBAR_FONT, /* note! shares a pref */
287 },
288 &use_system_font,
289 TRUE,
290 },
291 {
292 { "disable-workarounds",
293 SCHEMA_GENERAL,
294 META_PREF_DISABLE_WORKAROUNDS,
295 },
296 &disable_workarounds,
297 FALSE,
298 },
299 {
300 { "auto-raise",
301 SCHEMA_GENERAL,
302 META_PREF_AUTO_RAISE,
303 },
304 &auto_raise,
305 FALSE,
306 },
307 {
308 { "visual-bell",
309 SCHEMA_GENERAL,
310 META_PREF_VISUAL_BELL,
311 },
312 &bell_is_visible, /* FIXME: change the name: it's confusing */
313 FALSE,
314 },
315 {
316 { "audible-bell",
317 SCHEMA_GENERAL,
318 META_PREF_AUDIBLE_BELL,
319 },
320 &bell_is_audible, /* FIXME: change the name: it's confusing */
321 FALSE,
322 },
323 {
324 { KEY_GNOME_ACCESSIBILITY,
325 SCHEMA_INTERFACE,
326 META_PREF_GNOME_ACCESSIBILITY,
327 },
328 &gnome_accessibility,
329 FALSE,
330 },
331 {
332 { KEY_GNOME_ANIMATIONS,
333 SCHEMA_INTERFACE,
334 META_PREF_GNOME_ANIMATIONS,
335 },
336 &gnome_animations,
337 TRUE,
338 },
339 {
340 { "resize-with-right-button",
341 SCHEMA_GENERAL,
342 META_PREF_RESIZE_WITH_RIGHT_BUTTON,
343 },
344 &resize_with_right_button,
345 FALSE,
346 },
347 {
348 { "edge-tiling",
349 SCHEMA_METACITY,
350 META_PREF_EDGE_TILING,
351 },
352 &edge_tiling,
353 FALSE,
354 },
355 {
356 { "alt-tab-thumbnails",
357 SCHEMA_METACITY,
358 META_PREF_ALT_TAB_THUMBNAILS,
359 },
360 &alt_tab_thumbnails,
361 FALSE,
362 },
363 { { NULL, 0, 0 }, NULL, FALSE },
364 };
365
366 static MetaStringPreference preferences_string[] =
367 {
368 {
369 { "mouse-button-modifier",
370 SCHEMA_GENERAL,
371 META_PREF_MOUSE_BUTTON_MODS,
372 },
373 mouse_button_mods_handler,
374 NULL,
375 },
376 {
377 { KEY_TITLEBAR_FONT,
378 SCHEMA_GENERAL,
379 META_PREF_TITLEBAR_FONT,
380 },
381 titlebar_handler,
382 NULL,
383 },
384 {
385 { "button-layout",
386 SCHEMA_GENERAL,
387 META_PREF_BUTTON_LAYOUT,
388 },
389 button_layout_handler,
390 NULL,
391 },
392 {
393 { KEY_GNOME_CURSOR_THEME,
394 SCHEMA_INTERFACE,
395 META_PREF_CURSOR_THEME,
396 },
397 NULL,
398 &cursor_theme,
399 },
400 {
401 { "name",
402 SCHEMA_METACITY_THEME,
403 META_PREF_THEME_NAME,
404 },
405 theme_name_handler,
406 NULL,
407 },
408 { { NULL, 0, 0 }, NULL },
409 };
410
411 static MetaIntPreference preferences_int[] =
412 {
413 {
414 { "num-workspaces",
415 SCHEMA_GENERAL,
416 META_PREF_NUM_WORKSPACES,
417 },
418 &num_workspaces
419 },
420 {
421 { "auto-raise-delay",
422 SCHEMA_GENERAL,
423 META_PREF_AUTO_RAISE_DELAY,
424 },
425 &auto_raise_delay
426 },
427 { { NULL, 0, 0 }, NULL },
428 };
429
430 static void
handle_preference_init_enum(void)431 handle_preference_init_enum (void)
432 {
433 MetaEnumPreference *cursor = preferences_enum;
434
435 while (cursor->base.key != NULL)
436 {
437 if (cursor->target==NULL)
438 continue;
439
440 *((gint *) cursor->target) =
441 g_settings_get_enum (SETTINGS (cursor->base.schema), cursor->base.key);
442
443 ++cursor;
444 }
445 }
446
447 static void
handle_preference_init_bool(void)448 handle_preference_init_bool (void)
449 {
450 MetaBoolPreference *cursor = preferences_bool;
451
452 while (cursor->base.key != NULL)
453 {
454 if (cursor->target!=NULL)
455 *cursor->target =
456 g_settings_get_boolean (SETTINGS (cursor->base.schema),
457 cursor->base.key);
458
459 ++cursor;
460 }
461
462 maybe_give_disable_workarounds_warning ();
463 }
464
465 static void
handle_preference_init_string(void)466 handle_preference_init_string (void)
467 {
468 MetaStringPreference *cursor = preferences_string;
469
470 while (cursor->base.key != NULL)
471 {
472 char *value;
473
474 /* Complex keys have a mapping function to check validity */
475 if (cursor->handler)
476 {
477 if (cursor->target)
478 g_error ("%s has both a target and a handler", cursor->base.key);
479
480 g_settings_get_mapped (SETTINGS (cursor->base.schema),
481 cursor->base.key, cursor->handler, NULL);
482 }
483 else
484 {
485 if (!cursor->target)
486 g_error ("%s must have handler or target", cursor->base.key);
487
488 if (*(cursor->target))
489 g_free (*(cursor->target));
490
491 value = g_settings_get_string (SETTINGS (cursor->base.schema),
492 cursor->base.key);
493
494 *(cursor->target) = value;
495 }
496
497 ++cursor;
498 }
499 }
500
501 static void
handle_preference_init_int(void)502 handle_preference_init_int (void)
503 {
504 MetaIntPreference *cursor = preferences_int;
505
506
507 while (cursor->base.key != NULL)
508 {
509 if (cursor->target)
510 *cursor->target = g_settings_get_int (SETTINGS (cursor->base.schema),
511 cursor->base.key);
512
513 ++cursor;
514 }
515 }
516
517 static void
handle_preference_update_enum(GSettings * settings,gchar * key)518 handle_preference_update_enum (GSettings *settings,
519 gchar *key)
520 {
521 MetaEnumPreference *cursor = preferences_enum;
522 gint old_value;
523
524 while (cursor->base.key != NULL && strcmp (key, cursor->base.key) != 0)
525 ++cursor;
526
527 if (cursor->base.key==NULL)
528 /* Didn't recognise that key. */
529 return;
530
531 /* We need to know whether the value changes, so
532 * store the current value away. */
533 old_value = * ((gint *) cursor->target);
534
535 *((gint *) cursor->target) =
536 g_settings_get_enum (SETTINGS (cursor->base.schema), key);
537
538 /* Did it change? If so, tell the listeners about it. */
539 if (old_value != *((gint *) cursor->target))
540 queue_changed (cursor->base.pref);
541 }
542
543 static void
handle_preference_update_bool(GSettings * settings,gchar * key)544 handle_preference_update_bool (GSettings *settings,
545 gchar *key)
546 {
547 MetaBoolPreference *cursor = preferences_bool;
548 gboolean old_value;
549
550 while (cursor->base.key != NULL && strcmp (key, cursor->base.key) != 0)
551 ++cursor;
552
553 if (cursor->base.key==NULL || cursor->target==NULL)
554 /* Unknown key or no work for us to do. */
555 return;
556
557 /* We need to know whether the value changes, so
558 * store the current value away. */
559 old_value = *((gboolean *) cursor->target);
560
561 *((gboolean *) cursor->target) =
562 g_settings_get_boolean (SETTINGS (cursor->base.schema), key);
563
564 /* Did it change? If so, tell the listeners about it. */
565 if (old_value != *((gboolean *) cursor->target))
566 queue_changed (cursor->base.pref);
567
568 if (cursor->base.pref==META_PREF_DISABLE_WORKAROUNDS)
569 maybe_give_disable_workarounds_warning ();
570 }
571
572 static void
handle_preference_update_string(GSettings * settings,gchar * key)573 handle_preference_update_string (GSettings *settings,
574 gchar *key)
575 {
576 MetaStringPreference *cursor = preferences_string;
577 char *value;
578 gboolean inform_listeners = FALSE;
579
580 while (cursor->base.key != NULL && strcmp (key, cursor->base.key) != 0)
581 ++cursor;
582
583 if (cursor->base.key==NULL)
584 /* Didn't recognise that key. */
585 return;
586
587 /* Complex keys have a mapping function to check validity */
588 if (cursor->handler)
589 {
590 if (cursor->target)
591 g_error ("%s has both a target and a handler", cursor->base.key);
592
593 g_settings_get_mapped (SETTINGS (cursor->base.schema),
594 cursor->base.key, cursor->handler, NULL);
595 }
596 else
597 {
598 if (!cursor->target)
599 g_error ("%s must have handler or target", cursor->base.key);
600
601 value = g_settings_get_string (SETTINGS (cursor->base.schema),
602 cursor->base.key);
603 inform_listeners = (g_strcmp0 (value, *(cursor->target)) != 0);
604
605 if (*(cursor->target))
606 g_free (*(cursor->target));
607
608 *(cursor->target) = value;
609 }
610
611 if (inform_listeners)
612 queue_changed (cursor->base.pref);
613 }
614
615 static void
handle_preference_update_int(GSettings * settings,gchar * key)616 handle_preference_update_int (GSettings *settings,
617 gchar *key)
618 {
619 MetaIntPreference *cursor = preferences_int;
620 gint new_value;
621
622 while (cursor->base.key != NULL && strcmp (key, cursor->base.key) != 0)
623 ++cursor;
624
625 if (cursor->base.key==NULL || cursor->target==NULL)
626 /* Unknown key or no work for us to do. */
627 return;
628
629 new_value = g_settings_get_int (SETTINGS (cursor->base.schema), key);
630
631 /* Did it change? If so, tell the listeners about it. */
632 if (*cursor->target != new_value)
633 {
634 *cursor->target = new_value;
635 queue_changed (cursor->base.pref);
636 }
637 }
638
639 /****************************************************************************/
640 /* Listeners. */
641 /****************************************************************************/
642
643 void
meta_prefs_add_listener(MetaPrefsChangedFunc func,gpointer data)644 meta_prefs_add_listener (MetaPrefsChangedFunc func,
645 gpointer data)
646 {
647 MetaPrefsListener *l;
648
649 l = g_new (MetaPrefsListener, 1);
650 l->func = func;
651 l->data = data;
652
653 listeners = g_list_prepend (listeners, l);
654 }
655
656 void
meta_prefs_remove_listener(MetaPrefsChangedFunc func,gpointer data)657 meta_prefs_remove_listener (MetaPrefsChangedFunc func,
658 gpointer data)
659 {
660 GList *tmp;
661
662 tmp = listeners;
663 while (tmp != NULL)
664 {
665 MetaPrefsListener *l = tmp->data;
666
667 if (l->func == func &&
668 l->data == data)
669 {
670 g_free (l);
671 listeners = g_list_delete_link (listeners, tmp);
672
673 return;
674 }
675
676 tmp = tmp->next;
677 }
678
679 g_error ("Did not find listener to remove");
680 }
681
682 static void
emit_changed(MetaPreference pref)683 emit_changed (MetaPreference pref)
684 {
685 GList *tmp;
686 GList *copy;
687
688 meta_topic (META_DEBUG_PREFS, "Notifying listeners that pref %s changed\n",
689 meta_preference_to_string (pref));
690
691 copy = g_list_copy (listeners);
692
693 tmp = copy;
694
695 while (tmp != NULL)
696 {
697 MetaPrefsListener *l = tmp->data;
698
699 (* l->func) (pref, l->data);
700
701 tmp = tmp->next;
702 }
703
704 g_list_free (copy);
705 }
706
707 static gboolean
changed_idle_handler(gpointer data)708 changed_idle_handler (gpointer data)
709 {
710 GList *tmp;
711 GList *copy;
712
713 changed_idle = 0;
714
715 copy = g_list_copy (changes); /* reentrancy paranoia */
716
717 g_list_free (changes);
718 changes = NULL;
719
720 tmp = copy;
721 while (tmp != NULL)
722 {
723 MetaPreference pref = GPOINTER_TO_INT (tmp->data);
724
725 emit_changed (pref);
726
727 tmp = tmp->next;
728 }
729
730 g_list_free (copy);
731
732 return FALSE;
733 }
734
735 static void
queue_changed(MetaPreference pref)736 queue_changed (MetaPreference pref)
737 {
738 meta_topic (META_DEBUG_PREFS, "Queueing change of pref %s\n",
739 meta_preference_to_string (pref));
740
741 if (g_list_find (changes, GINT_TO_POINTER (pref)) == NULL)
742 changes = g_list_prepend (changes, GINT_TO_POINTER (pref));
743 else
744 meta_topic (META_DEBUG_PREFS, "Change of pref %s was already pending\n",
745 meta_preference_to_string (pref));
746
747 if (changed_idle == 0)
748 changed_idle = g_idle_add_full (META_PRIORITY_PREFS_NOTIFY,
749 changed_idle_handler, NULL, NULL);
750 }
751
752 static void
gtk_cursor_theme_size_changed(GtkSettings * settings,GParamSpec * pspec,gpointer user_data)753 gtk_cursor_theme_size_changed (GtkSettings *settings,
754 GParamSpec *pspec,
755 gpointer user_data)
756 {
757 gint size;
758
759 g_object_get (settings, "gtk-cursor-theme-size", &size, NULL);
760
761 if (size == 0)
762 size = 24;
763
764 if (size != cursor_size)
765 {
766 cursor_size = size;
767 queue_changed (META_PREF_CURSOR_SIZE);
768 }
769 }
770
771 static void
init_gtk_cursor_theme_size(void)772 init_gtk_cursor_theme_size (void)
773 {
774 GtkSettings *settings;
775
776 settings = gtk_settings_get_default ();
777
778 g_signal_connect (settings, "notify::gtk-cursor-theme-size",
779 G_CALLBACK (gtk_cursor_theme_size_changed), NULL);
780
781 gtk_cursor_theme_size_changed (settings, NULL, NULL);
782 }
783
784 static void
gtk_theme_name_changed(GtkSettings * settings,GParamSpec * pspec,gpointer user_data)785 gtk_theme_name_changed (GtkSettings *settings,
786 GParamSpec *pspec,
787 gpointer user_data)
788 {
789 if (current_theme_type == META_THEME_TYPE_GTK)
790 queue_changed (META_PREF_THEME_NAME);
791 }
792
793 static void
init_gtk_theme_name(void)794 init_gtk_theme_name (void)
795 {
796 GtkSettings *settings;
797
798 settings = gtk_settings_get_default ();
799
800 g_signal_connect (settings, "notify::gtk-theme-name",
801 G_CALLBACK (gtk_theme_name_changed), NULL);
802 }
803
804 static void
update_compositing_manager(void)805 update_compositing_manager (void)
806 {
807 GVariant *user_value;
808 gboolean compositing_manager;
809
810 user_value = g_settings_get_user_value (SETTINGS (SCHEMA_METACITY),
811 KEY_COMPOSITING_MANAGER);
812
813 if (user_value == NULL)
814 return;
815
816 compositing_manager = g_variant_get_boolean (user_value);
817 g_variant_unref (user_value);
818
819 if (compositing_manager)
820 meta_prefs_set_compositor (META_COMPOSITOR_TYPE_XRENDER);
821 else
822 meta_prefs_set_compositor (META_COMPOSITOR_TYPE_NONE);
823
824 g_settings_reset (SETTINGS (SCHEMA_METACITY), KEY_COMPOSITING_MANAGER);
825 }
826
827 static void
init_compositing_manager(void)828 init_compositing_manager (void)
829 {
830 update_compositing_manager ();
831 }
832
833 /****************************************************************************/
834 /* Initialisation. */
835 /****************************************************************************/
836
837 void
meta_prefs_init(void)838 meta_prefs_init (void)
839 {
840 GSettings *settings;
841
842 settings_schemas = g_hash_table_new_full (g_str_hash, g_str_equal,
843 g_free, g_object_unref);
844
845 settings = g_settings_new (SCHEMA_GENERAL);
846 g_signal_connect (settings, "changed", G_CALLBACK (settings_changed), NULL);
847 g_hash_table_insert (settings_schemas, g_strdup (SCHEMA_GENERAL), settings);
848
849 settings = g_settings_new (SCHEMA_METACITY);
850 g_signal_connect (settings, "changed", G_CALLBACK (settings_changed), NULL);
851 g_hash_table_insert (settings_schemas, g_strdup (SCHEMA_METACITY), settings);
852
853 settings = g_settings_new (SCHEMA_METACITY_THEME);
854 g_signal_connect (settings, "changed", G_CALLBACK (settings_changed), NULL);
855 g_hash_table_insert (settings_schemas, g_strdup (SCHEMA_METACITY_THEME), settings);
856
857 /* Individual keys we watch outside of our schemas */
858 settings = g_settings_new (SCHEMA_INTERFACE);
859 g_signal_connect (settings, "changed::" KEY_GNOME_ACCESSIBILITY,
860 G_CALLBACK (settings_changed), NULL);
861 g_signal_connect (settings, "changed::" KEY_GNOME_ANIMATIONS,
862 G_CALLBACK (settings_changed), NULL);
863 g_signal_connect (settings, "changed::" KEY_GNOME_CURSOR_THEME,
864 G_CALLBACK (settings_changed), NULL);
865 g_hash_table_insert (settings_schemas, g_strdup (SCHEMA_INTERFACE), settings);
866
867 /* Pick up initial values. */
868 handle_preference_init_enum ();
869 handle_preference_init_bool ();
870 handle_preference_init_string ();
871 handle_preference_init_int ();
872
873 init_bindings ();
874 init_workspace_names ();
875 init_compositing_manager ();
876
877 init_gtk_cursor_theme_size ();
878 init_gtk_theme_name ();
879 }
880
881 /****************************************************************************/
882 /* Updates. */
883 /****************************************************************************/
884
885 static void
settings_changed(GSettings * settings,gchar * key,gpointer data)886 settings_changed (GSettings *settings,
887 gchar *key,
888 gpointer data)
889 {
890 GVariant *value;
891 const GVariantType *type;
892 MetaEnumPreference *cursor;
893 gboolean found_enum;
894
895 /* String array, handled separately */
896 if (strcmp (key, KEY_WORKSPACE_NAMES) == 0)
897 {
898 if (update_workspace_names ())
899 queue_changed (META_PREF_WORKSPACE_NAMES);
900
901 return;
902 }
903 else if (strcmp (key, KEY_COMPOSITING_MANAGER) == 0)
904 {
905 g_warning (_("Setting “compositing-manager” is deprecated, "
906 "use the “compositor” instead."));
907
908 update_compositing_manager ();
909 return;
910 }
911
912 value = g_settings_get_value (settings, key);
913 type = g_variant_get_type (value);
914
915 if (g_variant_type_equal (type, G_VARIANT_TYPE_BOOLEAN))
916 handle_preference_update_bool (settings, key);
917 else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT32))
918 handle_preference_update_int (settings, key);
919 else if (g_variant_type_equal (type, G_VARIANT_TYPE_STRING))
920 {
921 cursor = preferences_enum;
922 found_enum = FALSE;
923
924 while (cursor->base.key != NULL)
925 {
926 if (strcmp (key, cursor->base.key) == 0)
927 found_enum = TRUE;
928
929 cursor++;
930 }
931
932 if (found_enum)
933 handle_preference_update_enum (settings, key);
934 else
935 handle_preference_update_string (settings, key);
936 }
937 else
938 /* Someone added a preference of an unhandled type */
939 g_assert_not_reached ();
940
941 g_variant_unref (value);
942 }
943
944 static void
bindings_changed(GSettings * settings,gchar * key,gpointer data)945 bindings_changed (GSettings *settings,
946 gchar *key,
947 gpointer data)
948 {
949 gchar **strokes;
950
951 strokes = g_settings_get_strv (settings, key);
952
953 if (update_key_binding (key, strokes))
954 queue_changed (META_PREF_KEYBINDINGS);
955
956 g_strfreev (strokes);
957 }
958
959 /**
960 * Special case: give a warning the first time disable_workarounds
961 * is turned on.
962 */
963 static void
maybe_give_disable_workarounds_warning(void)964 maybe_give_disable_workarounds_warning (void)
965 {
966 static gboolean first_disable = TRUE;
967
968 if (first_disable && disable_workarounds)
969 {
970 first_disable = FALSE;
971
972 g_warning ("Workarounds for broken applications disabled. "
973 "Some applications may not behave properly.");
974 }
975 }
976
977 MetaVirtualModifier
meta_prefs_get_mouse_button_mods(void)978 meta_prefs_get_mouse_button_mods (void)
979 {
980 return mouse_button_mods;
981 }
982
983 GDesktopFocusMode
meta_prefs_get_focus_mode(void)984 meta_prefs_get_focus_mode (void)
985 {
986 return focus_mode;
987 }
988
989 GDesktopFocusNewWindows
meta_prefs_get_focus_new_windows(void)990 meta_prefs_get_focus_new_windows (void)
991 {
992 return focus_new_windows;
993 }
994
995 gboolean
meta_prefs_get_attach_modal_dialogs(void)996 meta_prefs_get_attach_modal_dialogs (void)
997 {
998 return attach_modal_dialogs;
999 }
1000
1001 gboolean
meta_prefs_get_raise_on_click(void)1002 meta_prefs_get_raise_on_click (void)
1003 {
1004 return raise_on_click;
1005 }
1006
1007 const gchar *
meta_prefs_get_theme_name(void)1008 meta_prefs_get_theme_name (void)
1009 {
1010 return current_theme_name;
1011 }
1012
1013 MetaThemeType
meta_prefs_get_theme_type(void)1014 meta_prefs_get_theme_type (void)
1015 {
1016 return current_theme_type;
1017 }
1018
1019 const char*
meta_prefs_get_cursor_theme(void)1020 meta_prefs_get_cursor_theme (void)
1021 {
1022 return cursor_theme;
1023 }
1024
1025 int
meta_prefs_get_cursor_size(void)1026 meta_prefs_get_cursor_size (void)
1027 {
1028 return cursor_size;
1029 }
1030
1031 /****************************************************************************/
1032 /* Handlers for string preferences. */
1033 /****************************************************************************/
1034
1035 static gboolean
titlebar_handler(GVariant * value,gpointer * result,gpointer data)1036 titlebar_handler (GVariant *value,
1037 gpointer *result,
1038 gpointer data)
1039 {
1040 PangoFontDescription *desc;
1041 const gchar *string_value;
1042
1043 *result = NULL; /* ignored */
1044 string_value = g_variant_get_string (value, NULL);
1045 desc = pango_font_description_from_string (string_value);
1046
1047 if (desc == NULL)
1048 {
1049 g_warning ("Could not parse font description \"%s\" from GSettings key %s",
1050 string_value ? string_value : "(null)", KEY_TITLEBAR_FONT);
1051
1052 return FALSE;
1053 }
1054
1055 /* Is the new description the same as the old? */
1056 if (titlebar_font &&
1057 pango_font_description_equal (desc, titlebar_font))
1058 {
1059 pango_font_description_free (desc);
1060 }
1061 else
1062 {
1063 if (titlebar_font)
1064 pango_font_description_free (titlebar_font);
1065
1066 titlebar_font = desc;
1067 queue_changed (META_PREF_TITLEBAR_FONT);
1068 }
1069
1070 return TRUE;
1071 }
1072
1073 static gboolean
theme_name_handler(GVariant * value,gpointer * result,gpointer data)1074 theme_name_handler (GVariant *value,
1075 gpointer *result,
1076 gpointer data)
1077 {
1078 const gchar *string_value;
1079
1080 *result = NULL; /* ignored */
1081 string_value = g_variant_get_string (value, NULL);
1082
1083 if (g_strcmp0 (current_theme_name, string_value) != 0)
1084 {
1085 g_free (current_theme_name);
1086 current_theme_name = g_strdup (string_value);
1087
1088 queue_changed (META_PREF_THEME_NAME);
1089 }
1090
1091 return TRUE;
1092 }
1093
1094 static gboolean
mouse_button_mods_handler(GVariant * value,gpointer * result,gpointer data)1095 mouse_button_mods_handler (GVariant *value,
1096 gpointer *result,
1097 gpointer data)
1098 {
1099 MetaVirtualModifier mods;
1100 const gchar *string_value;
1101
1102 string_value = g_variant_get_string (value, NULL);
1103
1104 if (!string_value || !meta_ui_parse_modifier (string_value, &mods))
1105 {
1106 g_warning ("\"%s\" found in configuration database is not a valid value "
1107 "for mouse button modifier", string_value);
1108
1109 return FALSE;
1110 }
1111
1112 meta_topic (META_DEBUG_KEYBINDINGS,
1113 "Mouse button modifier has new GSettings value \"%s\"\n",
1114 string_value);
1115
1116 if (mods != mouse_button_mods)
1117 {
1118 mouse_button_mods = mods;
1119 queue_changed (META_PREF_MOUSE_BUTTON_MODS);
1120 }
1121
1122 return TRUE;
1123 }
1124
1125 static void
update_button_layout(const gchar * string_value)1126 update_button_layout (const gchar *string_value)
1127 {
1128 if (g_strcmp0 (button_layout, string_value) == 0)
1129 return;
1130
1131 g_free (button_layout);
1132 button_layout = g_strdup (string_value);
1133
1134 emit_changed (META_PREF_BUTTON_LAYOUT);
1135 }
1136
1137 static gboolean
button_layout_handler(GVariant * value,gpointer * result,gpointer data)1138 button_layout_handler (GVariant *value,
1139 gpointer *result,
1140 gpointer data)
1141 {
1142 const gchar *string_value;
1143
1144 *result = NULL; /* ignored */
1145
1146 string_value = g_variant_get_string (value, NULL);
1147
1148 if (string_value)
1149 update_button_layout (string_value);
1150
1151 return TRUE;
1152 }
1153
1154 const PangoFontDescription*
meta_prefs_get_titlebar_font(void)1155 meta_prefs_get_titlebar_font (void)
1156 {
1157 if (use_system_font)
1158 return NULL;
1159 else
1160 return titlebar_font;
1161 }
1162
1163 int
meta_prefs_get_num_workspaces(void)1164 meta_prefs_get_num_workspaces (void)
1165 {
1166 return num_workspaces;
1167 }
1168
1169 gboolean
meta_prefs_get_disable_workarounds(void)1170 meta_prefs_get_disable_workarounds (void)
1171 {
1172 return disable_workarounds;
1173 }
1174
1175 const char*
meta_preference_to_string(MetaPreference pref)1176 meta_preference_to_string (MetaPreference pref)
1177 {
1178 /* TODO: better handled via GLib enum nicknames */
1179 switch (pref)
1180 {
1181 case META_PREF_MOUSE_BUTTON_MODS:
1182 return "MOUSE_BUTTON_MODS";
1183
1184 case META_PREF_FOCUS_MODE:
1185 return "FOCUS_MODE";
1186
1187 case META_PREF_FOCUS_NEW_WINDOWS:
1188 return "FOCUS_NEW_WINDOWS";
1189
1190 case META_PREF_ATTACH_MODAL_DIALOGS:
1191 return "ATTACH_MODAL_DIALOGS";
1192
1193 case META_PREF_RAISE_ON_CLICK:
1194 return "RAISE_ON_CLICK";
1195
1196 case META_PREF_THEME_NAME:
1197 return "THEME_NAME";
1198
1199 case META_PREF_THEME_TYPE:
1200 return "THEME_TYPE";
1201
1202 case META_PREF_TITLEBAR_FONT:
1203 return "TITLEBAR_FONT";
1204
1205 case META_PREF_NUM_WORKSPACES:
1206 return "NUM_WORKSPACES";
1207
1208 case META_PREF_KEYBINDINGS:
1209 return "KEYBINDINGS";
1210
1211 case META_PREF_DISABLE_WORKAROUNDS:
1212 return "DISABLE_WORKAROUNDS";
1213
1214 case META_PREF_ACTION_DOUBLE_CLICK_TITLEBAR:
1215 return "ACTION_DOUBLE_CLICK_TITLEBAR";
1216
1217 case META_PREF_ACTION_MIDDLE_CLICK_TITLEBAR:
1218 return "ACTION_MIDDLE_CLICK_TITLEBAR";
1219
1220 case META_PREF_ACTION_RIGHT_CLICK_TITLEBAR:
1221 return "ACTION_RIGHT_CLICK_TITLEBAR";
1222
1223 case META_PREF_AUTO_RAISE:
1224 return "AUTO_RAISE";
1225
1226 case META_PREF_AUTO_RAISE_DELAY:
1227 return "AUTO_RAISE_DELAY";
1228
1229 case META_PREF_BUTTON_LAYOUT:
1230 return "BUTTON_LAYOUT";
1231
1232 case META_PREF_WORKSPACE_NAMES:
1233 return "WORKSPACE_NAMES";
1234
1235 case META_PREF_VISUAL_BELL:
1236 return "VISUAL_BELL";
1237
1238 case META_PREF_AUDIBLE_BELL:
1239 return "AUDIBLE_BELL";
1240
1241 case META_PREF_VISUAL_BELL_TYPE:
1242 return "VISUAL_BELL_TYPE";
1243
1244 case META_PREF_GNOME_ACCESSIBILITY:
1245 return "GNOME_ACCESSIBILTY";
1246
1247 case META_PREF_GNOME_ANIMATIONS:
1248 return "GNOME_ANIMATIONS";
1249
1250 case META_PREF_CURSOR_THEME:
1251 return "CURSOR_THEME";
1252
1253 case META_PREF_CURSOR_SIZE:
1254 return "CURSOR_SIZE";
1255
1256 case META_PREF_COMPOSITOR:
1257 return "META_PREF_COMPOSITOR";
1258
1259 case META_PREF_RESIZE_WITH_RIGHT_BUTTON:
1260 return "RESIZE_WITH_RIGHT_BUTTON";
1261
1262 case META_PREF_EDGE_TILING:
1263 return "EDGE_TILING";
1264
1265 case META_PREF_FORCE_FULLSCREEN:
1266 return "FORCE_FULLSCREEN";
1267
1268 case META_PREF_PLACEMENT_MODE:
1269 return "PLACEMENT_MODE";
1270
1271 case META_PREF_ALT_TAB_THUMBNAILS:
1272 return "ALT_TAB_THUMBNAILS";
1273
1274 default:
1275 break;
1276 }
1277
1278 return "(unknown)";
1279 }
1280
1281 void
meta_prefs_set_num_workspaces(int n_workspaces)1282 meta_prefs_set_num_workspaces (int n_workspaces)
1283 {
1284 g_settings_set_int (SETTINGS (SCHEMA_GENERAL),
1285 KEY_NUM_WORKSPACES,
1286 n_workspaces);
1287 }
1288
1289 static GHashTable *key_bindings;
1290
1291 static void
meta_key_pref_free(MetaKeyPref * pref)1292 meta_key_pref_free (MetaKeyPref *pref)
1293 {
1294 update_binding (pref, NULL);
1295
1296 g_free (pref->name);
1297 g_free (pref->schema);
1298
1299 g_free (pref);
1300 }
1301
1302 static void
init_bindings(void)1303 init_bindings (void)
1304 {
1305 key_bindings = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
1306 (GDestroyNotify) meta_key_pref_free);
1307 }
1308
1309 static void
init_workspace_names(void)1310 init_workspace_names (void)
1311 {
1312 update_workspace_names ();
1313 }
1314
1315 static gboolean
update_binding(MetaKeyPref * binding,gchar ** strokes)1316 update_binding (MetaKeyPref *binding,
1317 gchar **strokes)
1318 {
1319 unsigned int keysym;
1320 unsigned int keycode;
1321 MetaVirtualModifier mods;
1322 gboolean changed = FALSE;
1323 MetaKeyCombo *combo;
1324 int i;
1325
1326 meta_topic (META_DEBUG_KEYBINDINGS,
1327 "Binding \"%s\" has new GSettings value\n",
1328 binding->name);
1329
1330 /* Okay, so, we're about to provide a new list of key combos for this
1331 * action. Delete any pre-existing list.
1332 */
1333 g_slist_free_full (binding->bindings, g_free);
1334 binding->bindings = NULL;
1335
1336 for (i = 0; strokes && strokes[i]; i++)
1337 {
1338 keysym = 0;
1339 keycode = 0;
1340 mods = 0;
1341
1342 if (!meta_ui_parse_accelerator (strokes[i], &keysym, &keycode, &mods))
1343 {
1344 meta_topic (META_DEBUG_KEYBINDINGS,
1345 "Failed to parse new GSettings value\n");
1346 g_warning ("\"%s\" found in configuration database is not a valid "
1347 "value for keybinding \"%s\"", strokes[i], binding->name);
1348
1349 /* Value is kept and will thus be removed next time we save the key.
1350 * Changing the key in response to a modification could lead to cyclic calls. */
1351 continue;
1352 }
1353
1354 /* Bug 329676: Bindings which can be shifted must not have no modifiers,
1355 * nor only SHIFT as a modifier.
1356 */
1357
1358 if (binding->add_shift &&
1359 0 != keysym &&
1360 (META_VIRTUAL_SHIFT_MASK == mods || 0 == mods))
1361 {
1362 g_warning ("Cannot bind \"%s\" to %s: it needs a modifier "
1363 "such as Ctrl or Alt.", binding->name, strokes[i]);
1364
1365 /* Value is kept and will thus be removed next time we save the key.
1366 * Changing the key in response to a modification could lead to cyclic calls. */
1367 continue;
1368 }
1369
1370 changed = TRUE;
1371
1372 combo = g_malloc0 (sizeof (MetaKeyCombo));
1373 combo->keysym = keysym;
1374 combo->keycode = keycode;
1375 combo->modifiers = mods;
1376 binding->bindings = g_slist_prepend (binding->bindings, combo);
1377
1378 meta_topic (META_DEBUG_KEYBINDINGS,
1379 "New keybinding for \"%s\" is keysym = 0x%x keycode = 0x%x mods = 0x%x\n",
1380 binding->name, keysym, keycode, mods);
1381 }
1382
1383 return changed;
1384 }
1385
1386 static gboolean
update_key_binding(const char * key,gchar ** strokes)1387 update_key_binding (const char *key,
1388 gchar **strokes)
1389 {
1390 MetaKeyPref *pref = g_hash_table_lookup (key_bindings, key);
1391
1392 if (pref)
1393 return update_binding (pref, strokes);
1394 else
1395 return FALSE;
1396 }
1397
1398 static gboolean
update_workspace_names(void)1399 update_workspace_names (void)
1400 {
1401 int i;
1402 char **names;
1403 int n_workspace_names, n_names;
1404 gboolean changed = FALSE;
1405
1406 names = g_settings_get_strv (SETTINGS (SCHEMA_GENERAL), KEY_WORKSPACE_NAMES);
1407 n_names = g_strv_length (names);
1408 n_workspace_names = workspace_names ? g_strv_length (workspace_names) : 0;
1409
1410 for (i = 0; i < n_names; i++)
1411 if (n_workspace_names < i + 1 || !workspace_names[i] ||
1412 g_strcmp0 (names[i], workspace_names[i]) != 0)
1413 {
1414 changed = TRUE;
1415 break;
1416 }
1417
1418 if (n_workspace_names != n_names)
1419 changed = TRUE;
1420
1421 if (changed)
1422 {
1423 if (workspace_names)
1424 g_strfreev (workspace_names);
1425 workspace_names = names;
1426 }
1427 else
1428 {
1429 g_strfreev (names);
1430 }
1431
1432 return changed;
1433 }
1434
1435 const char*
meta_prefs_get_workspace_name(int i)1436 meta_prefs_get_workspace_name (int i)
1437 {
1438 const char *name;
1439
1440 g_return_val_if_fail (i >= 0, NULL);
1441
1442 if (!workspace_names ||
1443 g_strv_length (workspace_names) < (guint)i + 1 ||
1444 !*workspace_names[i])
1445 {
1446 char *generated_name = g_strdup_printf (_("Workspace %d"), i + 1);
1447 name = g_intern_string (generated_name);
1448 g_free (generated_name);
1449 }
1450 else
1451 name = workspace_names[i];
1452
1453 meta_topic (META_DEBUG_PREFS,
1454 "Getting name of workspace %d: \"%s\"\n", i, name);
1455
1456 return name;
1457 }
1458
1459 void
meta_prefs_change_workspace_name(int num,const char * name)1460 meta_prefs_change_workspace_name (int num,
1461 const char *name)
1462 {
1463 GVariantBuilder builder;
1464 int n_workspace_names, i;
1465
1466 g_return_if_fail (num >= 0);
1467
1468 meta_topic (META_DEBUG_PREFS,
1469 "Changing name of workspace %d to %s\n",
1470 num, name ? name : "none");
1471
1472 /* NULL and empty string both mean "default" here,
1473 * and we also need to match the name against its default value
1474 * to avoid saving it literally. */
1475 if (g_strcmp0 (name, meta_prefs_get_workspace_name (num)) == 0)
1476 {
1477 if (!name || !*name)
1478 meta_topic (META_DEBUG_PREFS,
1479 "Workspace %d already uses default name\n", num);
1480 else
1481 meta_topic (META_DEBUG_PREFS,
1482 "Workspace %d already has name %s\n", num, name);
1483 return;
1484 }
1485
1486 g_variant_builder_init (&builder, G_VARIANT_TYPE_STRING_ARRAY);
1487 n_workspace_names = workspace_names ? g_strv_length (workspace_names) : 0;
1488
1489 for (i = 0; i < MAX (num + 1, n_workspace_names); i++)
1490 {
1491 const char *value;
1492
1493 if (i == num)
1494 value = name ? name : "";
1495 else if (i < n_workspace_names)
1496 value = workspace_names[i] ? workspace_names[i] : "";
1497 else
1498 value = "";
1499
1500 g_variant_builder_add (&builder, "s", value);
1501 }
1502 g_settings_set_value (SETTINGS (SCHEMA_GENERAL), KEY_WORKSPACE_NAMES,
1503 g_variant_builder_end (&builder));
1504 }
1505
1506 const gchar *
meta_prefs_get_button_layout(void)1507 meta_prefs_get_button_layout (void)
1508 {
1509 return button_layout;
1510 }
1511
1512 gboolean
meta_prefs_get_visual_bell(void)1513 meta_prefs_get_visual_bell (void)
1514 {
1515 return bell_is_visible;
1516 }
1517
1518 gboolean
meta_prefs_bell_is_audible(void)1519 meta_prefs_bell_is_audible (void)
1520 {
1521 return bell_is_audible;
1522 }
1523
1524 GDesktopVisualBellType
meta_prefs_get_visual_bell_type(void)1525 meta_prefs_get_visual_bell_type (void)
1526 {
1527 return visual_bell_type;
1528 }
1529
1530 gboolean
meta_prefs_add_keybinding(const char * name,const char * schema,MetaKeyBindingAction action,MetaKeyBindingFlags flags)1531 meta_prefs_add_keybinding (const char *name,
1532 const char *schema,
1533 MetaKeyBindingAction action,
1534 MetaKeyBindingFlags flags)
1535 {
1536 MetaKeyPref *pref;
1537 GSettings *settings;
1538 char **strokes;
1539
1540 if (g_hash_table_lookup (key_bindings, name))
1541 {
1542 g_warning ("Trying to re-add keybinding \"%s\".", name);
1543 return FALSE;
1544 }
1545
1546 settings = SETTINGS (schema);
1547 if (settings == NULL)
1548 {
1549 settings = g_settings_new (schema);
1550 g_signal_connect (settings, "changed",
1551 G_CALLBACK (bindings_changed), NULL);
1552 g_hash_table_insert (settings_schemas, g_strdup (schema), settings);
1553 }
1554
1555 pref = g_new0 (MetaKeyPref, 1);
1556 pref->name = g_strdup (name);
1557 pref->schema = g_strdup (schema);
1558 pref->action = action;
1559 pref->bindings = NULL;
1560 pref->add_shift = (flags & META_KEY_BINDING_REVERSES) != 0;
1561 pref->per_window = (flags & META_KEY_BINDING_PER_WINDOW) != 0;
1562
1563 strokes = g_settings_get_strv (settings, name);
1564 update_binding (pref, strokes);
1565 g_strfreev (strokes);
1566
1567 g_hash_table_insert (key_bindings, g_strdup (name), pref);
1568
1569 return TRUE;
1570 }
1571
1572 /**
1573 * meta_prefs_get_keybindings: (skip)
1574 * Return: (element-type MetaKeyPref) (transfer container):
1575 */
1576 GList *
meta_prefs_get_keybindings(void)1577 meta_prefs_get_keybindings (void)
1578 {
1579 return g_hash_table_get_values (key_bindings);
1580 }
1581
1582 GDesktopTitlebarAction
meta_prefs_get_action_double_click_titlebar(void)1583 meta_prefs_get_action_double_click_titlebar (void)
1584 {
1585 return action_double_click_titlebar;
1586 }
1587
1588 GDesktopTitlebarAction
meta_prefs_get_action_middle_click_titlebar(void)1589 meta_prefs_get_action_middle_click_titlebar (void)
1590 {
1591 return action_middle_click_titlebar;
1592 }
1593
1594 GDesktopTitlebarAction
meta_prefs_get_action_right_click_titlebar(void)1595 meta_prefs_get_action_right_click_titlebar (void)
1596 {
1597 return action_right_click_titlebar;
1598 }
1599
1600 gboolean
meta_prefs_get_auto_raise(void)1601 meta_prefs_get_auto_raise (void)
1602 {
1603 return auto_raise;
1604 }
1605
1606 int
meta_prefs_get_auto_raise_delay(void)1607 meta_prefs_get_auto_raise_delay (void)
1608 {
1609 return auto_raise_delay;
1610 }
1611
1612 gboolean
meta_prefs_get_gnome_accessibility(void)1613 meta_prefs_get_gnome_accessibility (void)
1614 {
1615 return gnome_accessibility;
1616 }
1617
1618 gboolean
meta_prefs_get_gnome_animations(void)1619 meta_prefs_get_gnome_animations (void)
1620 {
1621 return gnome_animations;
1622 }
1623
1624 gboolean
meta_prefs_get_edge_tiling(void)1625 meta_prefs_get_edge_tiling (void)
1626 {
1627 return edge_tiling;
1628 }
1629
1630 MetaKeyBindingAction
meta_prefs_get_keybinding_action(const char * name)1631 meta_prefs_get_keybinding_action (const char *name)
1632 {
1633 MetaKeyPref *pref = g_hash_table_lookup (key_bindings, name);
1634
1635 return pref ? pref->action : META_KEYBINDING_ACTION_NONE;
1636 }
1637
1638 /* This is used by the menu system to decide what key binding
1639 * to display next to an option. We return the first non-disabled
1640 * binding, if any.
1641 */
1642 void
meta_prefs_get_window_binding(const char * name,unsigned int * keysym,MetaVirtualModifier * modifiers)1643 meta_prefs_get_window_binding (const char *name,
1644 unsigned int *keysym,
1645 MetaVirtualModifier *modifiers)
1646 {
1647 MetaKeyPref *pref = g_hash_table_lookup (key_bindings, name);
1648
1649 if (pref->per_window)
1650 {
1651 GSList *s = pref->bindings;
1652
1653 while (s)
1654 {
1655 MetaKeyCombo *c = s->data;
1656
1657 if (c->keysym != 0 || c->modifiers != 0)
1658 {
1659 *keysym = c->keysym;
1660 *modifiers = c->modifiers;
1661 return;
1662 }
1663
1664 s = s->next;
1665 }
1666
1667 /* Not found; return the disabled value */
1668 *keysym = *modifiers = 0;
1669 return;
1670 }
1671
1672 g_assert_not_reached ();
1673 }
1674
1675 guint
meta_prefs_get_mouse_button_resize(void)1676 meta_prefs_get_mouse_button_resize (void)
1677 {
1678 return resize_with_right_button ? 3: 2;
1679 }
1680
1681 guint
meta_prefs_get_mouse_button_menu(void)1682 meta_prefs_get_mouse_button_menu (void)
1683 {
1684 return resize_with_right_button ? 2: 3;
1685 }
1686
1687 gboolean
meta_prefs_get_force_fullscreen(void)1688 meta_prefs_get_force_fullscreen (void)
1689 {
1690 return force_fullscreen;
1691 }
1692
1693 MetaPlacementMode
meta_prefs_get_placement_mode(void)1694 meta_prefs_get_placement_mode (void)
1695 {
1696 return placement_mode;
1697 }
1698
1699 gboolean
meta_prefs_get_alt_tab_thumbnails(void)1700 meta_prefs_get_alt_tab_thumbnails (void)
1701 {
1702 return alt_tab_thumbnails;
1703 }
1704
1705 MetaCompositorType
meta_prefs_get_compositor(void)1706 meta_prefs_get_compositor (void)
1707 {
1708 return compositor;
1709 }
1710
1711 void
meta_prefs_set_compositor(MetaCompositorType type)1712 meta_prefs_set_compositor (MetaCompositorType type)
1713 {
1714 g_settings_set_enum (SETTINGS (SCHEMA_METACITY), "compositor", type);
1715 }
1716
1717 void
meta_prefs_set_force_fullscreen(gboolean whether)1718 meta_prefs_set_force_fullscreen (gboolean whether)
1719 {
1720 force_fullscreen = whether;
1721 }
1722