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       &current_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