1
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
3
/* Metacity preferences */
6
* Copyright (C) 2001 Havoc Pennington, Copyright (C) 2002 Red Hat Inc.
7
* Copyright (C) 2006 Elijah Newren
8
* Copyright (C) 2008 Thomas Thurman
10
* This program is free software; you can redistribute it and/or
11
* modify it under the terms of the GNU General Public License as
12
* published by the Free Software Foundation; either version 2 of the
13
* License, or (at your option) any later version.
15
* This program is distributed in the hope that it will be useful, but
16
* WITHOUT ANY WARRANTY; without even the implied warranty of
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18
* General Public License for more details.
20
* You should have received a copy of the GNU General Public License
21
* along with this program; if not, write to the Free Software
22
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
31
#include <gconf/gconf-client.h>
36
#define MAX_REASONABLE_WORKSPACES 36
38
#define MAX_COMMANDS (32 + NUM_EXTRA_COMMANDS)
39
#define NUM_EXTRA_COMMANDS 2
40
#define SCREENSHOT_COMMAND_IDX (MAX_COMMANDS - 2)
41
#define WIN_SCREENSHOT_COMMAND_IDX (MAX_COMMANDS - 1)
43
/* If you add a key, it needs updating in init() and in the gconf
44
* notify listener and of course in the .schemas file.
46
* Keys which are handled by one of the unified handlers below are
47
* not given a name here, because the purpose of the unified handlers
48
* is that keys should be referred to exactly once.
50
#define KEY_TITLEBAR_FONT "/apps/metacity/general/titlebar_font"
51
#define KEY_NUM_WORKSPACES "/apps/metacity/general/num_workspaces"
52
#define KEY_COMPOSITOR "/apps/metacity/general/compositing_manager"
53
#define KEY_GNOME_ACCESSIBILITY "/desktop/gnome/interface/accessibility"
55
#define KEY_COMMAND_DIRECTORY "/apps/metacity/keybinding_commands"
56
#define KEY_COMMAND_PREFIX "/apps/metacity/keybinding_commands/command_"
58
#define KEY_TERMINAL_DIR "/desktop/gnome/applications/terminal"
59
#define KEY_TERMINAL_COMMAND KEY_TERMINAL_DIR "/exec"
61
#define KEY_SCREEN_BINDINGS_PREFIX "/apps/metacity/global_keybindings"
62
#define KEY_WINDOW_BINDINGS_PREFIX "/apps/metacity/window_keybindings"
63
#define KEY_LIST_BINDINGS_SUFFIX "_list"
65
#define KEY_WORKSPACE_NAME_DIRECTORY "/apps/metacity/workspace_names"
66
#define KEY_WORKSPACE_NAME_PREFIX "/apps/metacity/workspace_names/name_"
70
static GConfClient *default_client = NULL;
71
static GList *changes = NULL;
72
static guint changed_idle;
73
static GList *listeners = NULL;
76
static gboolean use_system_font = FALSE;
77
static PangoFontDescription *titlebar_font = NULL;
78
static MetaVirtualModifier mouse_button_mods = Mod1Mask;
79
static MetaFocusMode focus_mode = META_FOCUS_MODE_CLICK;
80
static MetaFocusNewWindows focus_new_windows = META_FOCUS_NEW_WINDOWS_SMART;
81
static gboolean raise_on_click = TRUE;
82
static char* current_theme = NULL;
83
static int num_workspaces = 4;
84
static MetaActionTitlebar action_double_click_titlebar = META_ACTION_TITLEBAR_TOGGLE_MAXIMIZE;
85
static MetaActionTitlebar action_middle_click_titlebar = META_ACTION_TITLEBAR_LOWER;
86
static MetaActionTitlebar action_right_click_titlebar = META_ACTION_TITLEBAR_MENU;
87
static gboolean application_based = FALSE;
88
static gboolean disable_workarounds = FALSE;
89
static gboolean auto_raise = FALSE;
90
static gboolean auto_raise_delay = 500;
91
static gboolean provide_visual_bell = FALSE;
92
static gboolean bell_is_audible = TRUE;
93
static gboolean reduced_resources = FALSE;
94
static gboolean gnome_accessibility = FALSE;
95
static gboolean gnome_animations = TRUE;
96
static char *cursor_theme = NULL;
97
static int cursor_size = 24;
98
static gboolean compositing_manager = FALSE;
99
static gboolean compositor_effects = TRUE;
100
static gboolean capture_before_unmap = FALSE;
101
static gboolean resize_with_right_button = FALSE;
102
static gboolean force_fullscreen = TRUE;
103
static gboolean hide_decorator_tooltip = FALSE;
104
static gboolean show_maximized_titlebars = TRUE;
106
static MetaVisualBellType visual_bell_type = META_VISUAL_BELL_FULLSCREEN_FLASH;
107
static MetaButtonLayout button_layout;
109
/* The screenshot commands are at the end */
110
static char *commands[MAX_COMMANDS] = { NULL, };
112
static char *terminal_command = NULL;
114
static char *workspace_names[MAX_REASONABLE_WORKSPACES] = { NULL, };
117
static gboolean handle_preference_update_enum (const gchar *key, GConfValue *value);
119
static gboolean update_key_binding (const char *name,
121
static gboolean find_and_update_list_binding (MetaKeyPref *bindings,
124
static gboolean update_key_list_binding (const char *name,
126
static gboolean update_command (const char *name,
128
static gboolean update_workspace_name (const char *name,
131
static void change_notify (GConfClient *client,
136
static char* gconf_key_for_workspace_name (int i);
138
static void queue_changed (MetaPreference pref);
142
META_LIST_OF_STRINGS,
143
META_LIST_OF_GCONFVALUE_STRINGS
144
} MetaStringListType;
146
static gboolean update_list_binding (MetaKeyPref *binding,
148
MetaStringListType type_of_value);
150
static void cleanup_error (GError **error);
151
static gboolean get_bool (const char *key, gboolean *val);
152
static void maybe_give_disable_workarounds_warning (void);
154
static void titlebar_handler (MetaPreference, const gchar*, gboolean*);
155
static void theme_name_handler (MetaPreference, const gchar*, gboolean*);
156
static void mouse_button_mods_handler (MetaPreference, const gchar*, gboolean*);
157
static void button_layout_handler (MetaPreference, const gchar*, gboolean*);
159
#endif /* HAVE_GCONF */
161
static gboolean update_binding (MetaKeyPref *binding,
164
static void init_bindings (void);
165
static void init_commands (void);
166
static void init_workspace_names (void);
169
static void init_button_layout (void);
170
#endif /* !HAVE_GCONF */
176
MetaPrefsChangedFunc func;
180
static GConfEnumStringPair symtab_focus_mode[] =
182
{ META_FOCUS_MODE_CLICK, "click" },
183
{ META_FOCUS_MODE_SLOPPY, "sloppy" },
184
{ META_FOCUS_MODE_MOUSE, "mouse" },
185
{ META_FOCUS_MODE_STRICT, "strict" },
189
static GConfEnumStringPair symtab_focus_new_windows[] =
191
{ META_FOCUS_NEW_WINDOWS_SMART, "smart" },
192
{ META_FOCUS_NEW_WINDOWS_STRICT, "strict" },
196
static GConfEnumStringPair symtab_visual_bell_type[] =
198
/* Note to the reader: 0 is an invalid value; these start at 1. */
199
{ META_VISUAL_BELL_FULLSCREEN_FLASH, "fullscreen" },
200
{ META_VISUAL_BELL_FRAME_FLASH, "frame_flash" },
204
static GConfEnumStringPair symtab_titlebar_action[] =
206
{ META_ACTION_TITLEBAR_TOGGLE_SHADE, "toggle_shade" },
207
{ META_ACTION_TITLEBAR_TOGGLE_MAXIMIZE, "toggle_maximize" },
208
{ META_ACTION_TITLEBAR_TOGGLE_MAXIMIZE_HORIZONTALLY,
209
"toggle_maximize_horizontally" },
210
{ META_ACTION_TITLEBAR_TOGGLE_MAXIMIZE_VERTICALLY,
211
"toggle_maximize_vertically" },
212
{ META_ACTION_TITLEBAR_MINIMIZE, "minimize" },
213
{ META_ACTION_TITLEBAR_NONE, "none" },
214
{ META_ACTION_TITLEBAR_LOWER, "lower" },
215
{ META_ACTION_TITLEBAR_MENU, "menu" },
216
{ META_ACTION_TITLEBAR_TOGGLE_SHADE, "toggle_shade" },
221
* The details of one preference which is constrained to be
222
* one of a small number of string values-- in other words,
225
* We could have done this other ways. One particularly attractive
226
* possibility would have been to represent the entire symbol table
227
* as a space-separated string literal in the list of symtabs, so
228
* the focus mode enums could have been represented simply by
229
* "click sloppy mouse". However, the simplicity gained would have
230
* been outweighed by the bugs caused when the ordering of the enum
231
* strings got out of sync with the actual enum statement. Also,
232
* there is existing library code to use this kind of symbol tables.
234
* Other things we might consider doing to clean this up in the
237
* - most of the keys begin with the same prefix, and perhaps we
238
* could assume it if they don't start with a slash
240
* - there are several cases where a single identifier could be used
241
* to generate an entire entry, and perhaps this could be done
242
* with a macro. (This would reduce clarity, however, and is
243
* probably a bad thing.)
245
* - these types all begin with a gchar* (and contain a MetaPreference)
246
* and we can factor out the repeated code in the handlers by taking
247
* advantage of this using some kind of union arrangement.
253
GConfEnumStringPair *symtab;
255
} MetaEnumPreference;
262
gboolean becomes_true_on_destruction;
263
} MetaBoolPreference;
271
* A handler. Many of the string preferences aren't stored as
272
* strings and need parsing; others of them have default values
273
* which can't be solved in the general case. If you include a
274
* function pointer here, it will be called before the string
275
* value is written out to the target variable.
277
* The function is passed two arguments: the preference, and
278
* the new string as a gchar*. It returns a gboolean;
279
* only if this is true, the listeners will be informed that
280
* the preference has changed.
282
* This may be NULL. If it is, see "target", below.
284
void (*handler) (MetaPreference pref,
285
const gchar *string_value,
286
gboolean *inform_listeners);
289
* Where to write the incoming string.
291
* This must be NULL if the handler is non-NULL.
292
* If the incoming string is NULL, no change will be made.
296
} MetaStringPreference;
298
#define METAINTPREFERENCE_NO_CHANGE_ON_DESTROY G_MININT
306
* Minimum and maximum values of the integer.
307
* If the new value is out of bounds, it will be discarded with a warning.
309
gint minimum, maximum;
311
* Value to use if the key is destroyed.
312
* If this is METAINTPREFERENCE_NO_CHANGE_ON_DESTROY, it will
313
* not be changed when the key is destroyed.
315
gint value_if_destroyed;
319
/* @@@ Don't use NULL lines at the end; glib can tell you how big it is */
320
/* @@@ /apps/metacity/general should be assumed if first char is not / */
321
/* @@@ Will it ever be possible to merge init and update? If not, why not? */
323
static MetaEnumPreference preferences_enum[] =
325
{ "/apps/metacity/general/focus_new_windows",
326
META_PREF_FOCUS_NEW_WINDOWS,
327
symtab_focus_new_windows,
330
{ "/apps/metacity/general/focus_mode",
331
META_PREF_FOCUS_MODE,
335
{ "/apps/metacity/general/visual_bell_type",
336
META_PREF_VISUAL_BELL_TYPE,
337
symtab_visual_bell_type,
340
{ "/apps/metacity/general/action_double_click_titlebar",
341
META_PREF_ACTION_DOUBLE_CLICK_TITLEBAR,
342
symtab_titlebar_action,
343
&action_double_click_titlebar,
345
{ "/apps/metacity/general/action_middle_click_titlebar",
346
META_PREF_ACTION_MIDDLE_CLICK_TITLEBAR,
347
symtab_titlebar_action,
348
&action_middle_click_titlebar,
350
{ "/apps/metacity/general/action_right_click_titlebar",
351
META_PREF_ACTION_RIGHT_CLICK_TITLEBAR,
352
symtab_titlebar_action,
353
&action_right_click_titlebar,
355
{ NULL, 0, NULL, NULL },
358
static MetaBoolPreference preferences_bool[] =
360
{ "/apps/metacity/general/raise_on_click",
361
META_PREF_RAISE_ON_CLICK,
365
{ "/apps/metacity/general/titlebar_uses_system_font",
366
META_PREF_TITLEBAR_FONT, /* note! shares a pref */
370
{ "/apps/metacity/general/application_based",
371
META_PREF_APPLICATION_BASED,
372
NULL, /* feature is known but disabled */
375
{ "/apps/metacity/general/disable_workarounds",
376
META_PREF_DISABLE_WORKAROUNDS,
377
&disable_workarounds,
380
{ "/apps/metacity/general/auto_raise",
381
META_PREF_AUTO_RAISE,
385
{ "/apps/metacity/general/visual_bell",
386
META_PREF_VISUAL_BELL,
387
&provide_visual_bell, /* FIXME: change the name: it's confusing */
390
{ "/apps/metacity/general/audible_bell",
391
META_PREF_AUDIBLE_BELL,
392
&bell_is_audible, /* FIXME: change the name: it's confusing */
395
{ "/apps/metacity/general/reduced_resources",
396
META_PREF_REDUCED_RESOURCES,
400
{ "/desktop/gnome/interface/accessibility",
401
META_PREF_GNOME_ACCESSIBILITY,
402
&gnome_accessibility,
405
{ "/desktop/gnome/interface/enable_animations",
406
META_PREF_GNOME_ANIMATIONS,
410
{ "/apps/metacity/general/compositing_manager",
411
META_PREF_COMPOSITING_MANAGER,
412
&compositing_manager,
415
{ "/apps/metacity/general/resize_with_right_button",
416
META_PREF_RESIZE_WITH_RIGHT_BUTTON,
417
&resize_with_right_button,
420
{ "/desktop/gnome/interface/hide_decorator_tooltip",
421
META_PREF_HIDE_DECORATOR_TOOLTIP,
422
&hide_decorator_tooltip,
425
{ "/apps/metacity/general/show_maximized_titlebars",
426
META_PREF_SHOW_MAXIMIZED_TITLEBARS,
427
&show_maximized_titlebars,
430
{ "/apps/metacity/general/compositor_effects",
431
META_PREF_COMPOSITOR_EFFECTS,
435
{ "/apps/metacity/general/capture_before_unmap",
436
META_PREF_CAPTURE_BEFORE_UNMAP,
437
&capture_before_unmap,
440
{ NULL, 0, NULL, FALSE },
443
static MetaStringPreference preferences_string[] =
445
{ "/apps/metacity/general/mouse_button_modifier",
446
META_PREF_MOUSE_BUTTON_MODS,
447
mouse_button_mods_handler,
450
{ "/apps/metacity/general/theme",
456
META_PREF_TITLEBAR_FONT,
460
{ KEY_TERMINAL_COMMAND,
461
META_PREF_TERMINAL_COMMAND,
465
{ "/apps/metacity/general/button_layout",
466
META_PREF_BUTTON_LAYOUT,
467
button_layout_handler,
470
{ "/desktop/gnome/peripherals/mouse/cursor_theme",
471
META_PREF_CURSOR_THEME,
475
{ NULL, 0, NULL, NULL },
478
static MetaIntPreference preferences_int[] =
480
{ "/apps/metacity/general/num_workspaces",
481
META_PREF_NUM_WORKSPACES,
483
/* I would actually recommend we change the destroy value to 4
484
* and get rid of METAINTPREFERENCE_NO_CHANGE_ON_DESTROY entirely.
487
1, MAX_REASONABLE_WORKSPACES, METAINTPREFERENCE_NO_CHANGE_ON_DESTROY,
489
{ "/apps/metacity/general/auto_raise_delay",
490
META_PREF_AUTO_RAISE_DELAY,
493
/* @@@ Get rid of MAX_REASONABLE_AUTO_RAISE_DELAY */
495
{ "/desktop/gnome/peripherals/mouse/cursor_size",
496
META_PREF_CURSOR_SIZE,
500
{ NULL, 0, NULL, 0, 0, 0, },
504
handle_preference_init_enum (void)
506
MetaEnumPreference *cursor = preferences_enum;
508
while (cursor->key!=NULL)
511
GError *error = NULL;
513
if (cursor->target==NULL)
519
value = gconf_client_get_string (default_client,
522
cleanup_error (&error);
530
if (!gconf_string_to_enum (cursor->symtab,
532
(gint *) cursor->target))
533
meta_warning (_("GConf key '%s' is set to an invalid value\n"),
543
handle_preference_init_bool (void)
545
MetaBoolPreference *cursor = preferences_bool;
547
while (cursor->key!=NULL)
549
if (cursor->target!=NULL)
550
get_bool (cursor->key, cursor->target);
555
maybe_give_disable_workarounds_warning ();
559
handle_preference_init_string (void)
561
MetaStringPreference *cursor = preferences_string;
563
while (cursor->key!=NULL)
566
GError *error = NULL;
567
gboolean dummy = TRUE;
569
/* the string "value" will be newly allocated */
570
value = gconf_client_get_string (default_client,
573
cleanup_error (&error);
578
meta_bug ("%s has both a target and a handler\n", cursor->key);
580
cursor->handler (cursor->pref, value, &dummy);
584
else if (cursor->target)
586
if (*(cursor->target))
587
g_free (*(cursor->target));
589
*(cursor->target) = value;
597
handle_preference_init_int (void)
599
MetaIntPreference *cursor = preferences_int;
602
while (cursor->key!=NULL)
605
GError *error = NULL;
607
value = gconf_client_get_int (default_client,
610
cleanup_error (&error);
612
if (value < cursor->minimum || value > cursor->maximum)
614
meta_warning (_("%d stored in GConf key %s is out of range %d to %d\n"),
615
value, cursor->key, cursor->minimum, cursor->maximum);
616
/* Former behaviour for out-of-range values was:
617
* - number of workspaces was clamped;
618
* - auto raise delay was always reset to zero even if too high!;
619
* - cursor size was ignored.
621
* These seem to be meaningless variations. If they did
622
* have meaning we could have put them into MetaIntPreference.
623
* The last of these is the closest to how we behave for
624
* other types, so I think we should standardise on that.
627
else if (cursor->target)
628
*cursor->target = value;
635
handle_preference_update_enum (const gchar *key, GConfValue *value)
637
MetaEnumPreference *cursor = preferences_enum;
640
while (cursor->key!=NULL && strcmp (key, cursor->key)!=0)
643
if (cursor->key==NULL)
644
/* Didn't recognise that key. */
647
/* Setting it to null (that is, removing it) always means
654
/* Check the type. Enums are always strings. */
656
if (value->type != GCONF_VALUE_STRING)
658
meta_warning (_("GConf key \"%s\" is set to an invalid type\n"),
660
/* But we did recognise it. */
664
/* We need to know whether the value changes, so
665
* store the current value away.
668
old_value = * ((gint *) cursor->target);
670
/* Now look it up... */
672
if (!gconf_string_to_enum (cursor->symtab,
673
gconf_value_get_string (value),
674
(gint *) cursor->target))
677
* We found it, but it was invalid. Complain.
679
* FIXME: This replicates the original behaviour, but in the future
680
* we might consider reverting invalid keys to their original values.
681
* (We know the old value, so we can look up a suitable string in
684
* (Empty comment follows so the translators don't see this.)
688
meta_warning (_("GConf key '%s' is set to an invalid value\n"),
693
/* Did it change? If so, tell the listeners about it. */
695
if (old_value != *((gint *) cursor->target))
696
queue_changed (cursor->pref);
702
handle_preference_update_bool (const gchar *key, GConfValue *value)
704
MetaBoolPreference *cursor = preferences_bool;
707
while (cursor->key!=NULL && strcmp (key, cursor->key)!=0)
710
if (cursor->key==NULL)
711
/* Didn't recognise that key. */
714
if (cursor->target==NULL)
715
/* No work for us to do. */
720
/* Value was destroyed; let's get out of here. */
722
if (cursor->becomes_true_on_destruction)
723
/* This preserves the behaviour of the old system, but
724
* for all I know that might have been an oversight.
726
*((gboolean *)cursor->target) = TRUE;
731
/* Check the type. */
733
if (value->type != GCONF_VALUE_BOOL)
735
meta_warning (_("GConf key \"%s\" is set to an invalid type\n"),
737
/* But we did recognise it. */
741
/* We need to know whether the value changes, so
742
* store the current value away.
745
old_value = * ((gboolean *) cursor->target);
747
/* Now look it up... */
749
*((gboolean *) cursor->target) = gconf_value_get_bool (value);
751
/* Did it change? If so, tell the listeners about it. */
753
if (old_value != *((gboolean *) cursor->target))
754
queue_changed (cursor->pref);
756
if (cursor->pref==META_PREF_DISABLE_WORKAROUNDS)
757
maybe_give_disable_workarounds_warning ();
763
handle_preference_update_string (const gchar *key, GConfValue *value)
765
MetaStringPreference *cursor = preferences_string;
766
const gchar *value_as_string;
767
gboolean inform_listeners = TRUE;
769
while (cursor->key!=NULL && strcmp (key, cursor->key)!=0)
772
if (cursor->key==NULL)
773
/* Didn't recognise that key. */
779
/* Check the type. */
781
if (value->type != GCONF_VALUE_STRING)
783
meta_warning (_("GConf key \"%s\" is set to an invalid type\n"),
785
/* But we did recognise it. */
789
/* Docs: "The returned string is not a copy, don't try to free it." */
790
value_as_string = gconf_value_get_string (value);
793
cursor->handler (cursor->pref, value_as_string, &inform_listeners);
794
else if (cursor->target)
796
if (*(cursor->target))
797
g_free(*(cursor->target));
799
if (value_as_string!=NULL)
800
*(cursor->target) = g_strdup (value_as_string);
802
*(cursor->target) = NULL;
805
(value_as_string==NULL && *(cursor->target)==NULL) ||
806
(value_as_string!=NULL && *(cursor->target)!=NULL &&
807
strcmp (value_as_string, *(cursor->target))==0);
810
if (inform_listeners)
811
queue_changed (cursor->pref);
817
handle_preference_update_int (const gchar *key, GConfValue *value)
819
MetaIntPreference *cursor = preferences_int;
822
while (cursor->key!=NULL && strcmp (key, cursor->key)!=0)
825
if (cursor->key==NULL)
826
/* Didn't recognise that key. */
829
if (cursor->target==NULL)
830
/* No work for us to do. */
835
/* Value was destroyed. */
837
if (cursor->value_if_destroyed != METAINTPREFERENCE_NO_CHANGE_ON_DESTROY)
838
*((gint *)cursor->target) = cursor->value_if_destroyed;
843
/* Check the type. */
845
if (value->type != GCONF_VALUE_INT)
847
meta_warning (_("GConf key \"%s\" is set to an invalid type\n"),
849
/* But we did recognise it. */
853
new_value = gconf_value_get_int (value);
855
if (new_value < cursor->minimum || new_value > cursor->maximum)
857
meta_warning (_("%d stored in GConf key %s is out of range %d to %d\n"),
858
new_value, cursor->key,
859
cursor->minimum, cursor->maximum);
863
/* Did it change? If so, tell the listeners about it. */
865
if (*cursor->target != new_value)
867
*cursor->target = new_value;
868
queue_changed (cursor->pref);
876
/****************************************************************************/
878
/****************************************************************************/
881
meta_prefs_add_listener (MetaPrefsChangedFunc func,
884
MetaPrefsListener *l;
886
l = g_new (MetaPrefsListener, 1);
890
listeners = g_list_prepend (listeners, l);
894
meta_prefs_remove_listener (MetaPrefsChangedFunc func,
902
MetaPrefsListener *l = tmp->data;
904
if (l->func == func &&
908
listeners = g_list_delete_link (listeners, tmp);
916
meta_bug ("Did not find listener to remove\n");
920
emit_changed (MetaPreference pref)
925
meta_topic (META_DEBUG_PREFS, "Notifying listeners that pref %s changed\n",
926
meta_preference_to_string (pref));
928
copy = g_list_copy (listeners);
934
MetaPrefsListener *l = tmp->data;
936
(* l->func) (pref, l->data);
945
changed_idle_handler (gpointer data)
952
copy = g_list_copy (changes); /* reentrancy paranoia */
954
g_list_free (changes);
960
MetaPreference pref = GPOINTER_TO_INT (tmp->data);
973
queue_changed (MetaPreference pref)
975
meta_topic (META_DEBUG_PREFS, "Queueing change of pref %s\n",
976
meta_preference_to_string (pref));
978
if (g_list_find (changes, GINT_TO_POINTER (pref)) == NULL)
979
changes = g_list_prepend (changes, GINT_TO_POINTER (pref));
981
meta_topic (META_DEBUG_PREFS, "Change of pref %s was already pending\n",
982
meta_preference_to_string (pref));
984
/* add idle at priority below the gconf notify idle */
985
if (changed_idle == 0)
986
changed_idle = g_idle_add_full (META_PRIORITY_PREFS_NOTIFY,
987
changed_idle_handler, NULL, NULL);
990
#else /* HAVE_GCONF */
993
meta_prefs_add_listener (MetaPrefsChangedFunc func,
996
/* Nothing, because they have gconf turned off */
1000
meta_prefs_remove_listener (MetaPrefsChangedFunc func,
1003
/* Nothing, because they have gconf turned off */
1006
#endif /* HAVE_GCONF */
1009
/****************************************************************************/
1010
/* Initialisation. */
1011
/****************************************************************************/
1014
/* @@@ again, use glib's ability to tell you the size of the array */
1015
static gchar *gconf_dirs_we_are_interested_in[] = {
1018
KEY_GNOME_ACCESSIBILITY,
1019
"/desktop/gnome/peripherals/mouse",
1020
"/desktop/gnome/interface",
1026
meta_prefs_init (void)
1030
gchar **gconf_dir_cursor;
1032
if (default_client != NULL)
1035
/* returns a reference which we hold forever */
1036
default_client = gconf_client_get_default ();
1038
for (gconf_dir_cursor=gconf_dirs_we_are_interested_in;
1039
*gconf_dir_cursor!=NULL;
1042
gconf_client_add_dir (default_client,
1044
GCONF_CLIENT_PRELOAD_RECURSIVE,
1046
cleanup_error (&err);
1049
/* Pick up initial values. */
1051
handle_preference_init_enum ();
1052
handle_preference_init_bool ();
1053
handle_preference_init_string ();
1054
handle_preference_init_int ();
1056
/* @@@ Is there any reason we don't do the add_dir here? */
1057
for (gconf_dir_cursor=gconf_dirs_we_are_interested_in;
1058
*gconf_dir_cursor!=NULL;
1061
gconf_client_notify_add (default_client,
1067
cleanup_error (&err);
1070
#else /* HAVE_GCONF */
1072
/* Set defaults for some values that can't be set at initialization time of
1073
* the static globals. In the case of the theme, note that there is code
1074
* elsewhere that will do everything possible to fallback to an existing theme
1075
* if the one here does not exist.
1077
titlebar_font = pango_font_description_from_string ("Sans Bold 10");
1078
current_theme = g_strdup ("Atlanta");
1080
init_button_layout();
1081
#endif /* HAVE_GCONF */
1085
init_workspace_names ();
1089
/****************************************************************************/
1091
/****************************************************************************/
1095
gboolean (*preference_update_handler[]) (const gchar*, GConfValue*) = {
1096
handle_preference_update_enum,
1097
handle_preference_update_bool,
1098
handle_preference_update_string,
1099
handle_preference_update_int,
1104
change_notify (GConfClient *client,
1113
key = gconf_entry_get_key (entry);
1114
value = gconf_entry_get_value (entry);
1116
/* First, search for a handler that might know what to do. */
1118
/* FIXME: When this is all working, since the first item in every
1119
* array is the gchar* of the key, there's no reason we can't
1120
* find the correct record for that key here and save code duplication.
1123
while (preference_update_handler[i]!=NULL)
1125
if (preference_update_handler[i] (key, value))
1126
goto out; /* Get rid of this eventually */
1131
if (g_str_has_prefix (key, KEY_WINDOW_BINDINGS_PREFIX) ||
1132
g_str_has_prefix (key, KEY_SCREEN_BINDINGS_PREFIX))
1134
if (g_str_has_suffix (key, KEY_LIST_BINDINGS_SUFFIX))
1138
if (value && value->type != GCONF_VALUE_LIST)
1140
meta_warning (_("GConf key \"%s\" is set to an invalid type\n"),
1145
list = value ? gconf_value_get_list (value) : NULL;
1147
if (update_key_list_binding (key, list))
1148
queue_changed (META_PREF_KEYBINDINGS);
1154
if (value && value->type != GCONF_VALUE_STRING)
1156
meta_warning (_("GConf key \"%s\" is set to an invalid type\n"),
1161
str = value ? gconf_value_get_string (value) : NULL;
1163
if (update_key_binding (key, str))
1164
queue_changed (META_PREF_KEYBINDINGS);
1167
else if (g_str_has_prefix (key, KEY_COMMAND_PREFIX))
1171
if (value && value->type != GCONF_VALUE_STRING)
1173
meta_warning (_("GConf key \"%s\" is set to an invalid type\n"),
1178
str = value ? gconf_value_get_string (value) : NULL;
1180
if (update_command (key, str))
1181
queue_changed (META_PREF_COMMANDS);
1183
else if (g_str_has_prefix (key, KEY_WORKSPACE_NAME_PREFIX))
1187
if (value && value->type != GCONF_VALUE_STRING)
1189
meta_warning (_("GConf key \"%s\" is set to an invalid type\n"),
1194
str = value ? gconf_value_get_string (value) : NULL;
1196
if (update_workspace_name (key, str))
1197
queue_changed (META_PREF_WORKSPACE_NAMES);
1201
meta_topic (META_DEBUG_PREFS, "Key %s doesn't mean anything to Metacity\n",
1207
return; /* AIX compiler wants something after a label like out: */
1211
cleanup_error (GError **error)
1215
meta_warning ("%s\n", (*error)->message);
1217
g_error_free (*error);
1222
/* get_bool returns TRUE if *val is filled in, FALSE otherwise */
1223
/* @@@ probably worth moving this inline; only used once */
1225
get_bool (const char *key, gboolean *val)
1229
gboolean filled_in = FALSE;
1231
value = gconf_client_get (default_client, key, &err);
1232
cleanup_error (&err);
1235
if (value->type == GCONF_VALUE_BOOL)
1237
*val = gconf_value_get_bool (value);
1240
gconf_value_free (value);
1247
* Special case: give a warning the first time disable_workarounds
1251
maybe_give_disable_workarounds_warning (void)
1253
static gboolean first_disable = TRUE;
1255
if (first_disable && disable_workarounds)
1257
first_disable = FALSE;
1259
meta_warning (_("Workarounds for broken applications disabled. "
1260
"Some applications may not behave properly.\n"));
1264
#endif /* HAVE_GCONF */
1267
meta_prefs_get_mouse_button_mods (void)
1269
return mouse_button_mods;
1273
meta_prefs_get_focus_mode (void)
1279
meta_prefs_get_focus_new_windows (void)
1281
return focus_new_windows;
1285
meta_prefs_get_raise_on_click (void)
1287
return raise_on_click;
1291
meta_prefs_get_hide_decorator_tooltip (void)
1293
return hide_decorator_tooltip;
1297
meta_prefs_get_show_maximized_titlebars (void)
1299
return show_maximized_titlebars;
1303
meta_prefs_get_theme (void)
1305
return current_theme;
1309
meta_prefs_get_cursor_theme (void)
1311
return cursor_theme;
1315
meta_prefs_get_cursor_size (void)
1321
/****************************************************************************/
1322
/* Handlers for string preferences. */
1323
/****************************************************************************/
1328
titlebar_handler (MetaPreference pref,
1329
const gchar *string_value,
1330
gboolean *inform_listeners)
1332
PangoFontDescription *new_desc = NULL;
1335
new_desc = pango_font_description_from_string (string_value);
1337
if (new_desc == NULL)
1339
meta_warning (_("Could not parse font description "
1340
"\"%s\" from GConf key %s\n"),
1341
string_value ? string_value : "(null)",
1344
*inform_listeners = FALSE;
1349
/* Is the new description the same as the old? */
1351
if (titlebar_font &&
1352
pango_font_description_equal (new_desc, titlebar_font))
1354
pango_font_description_free (new_desc);
1355
*inform_listeners = FALSE;
1359
/* No, so free the old one and put ours in instead. */
1362
pango_font_description_free (titlebar_font);
1364
titlebar_font = new_desc;
1369
theme_name_handler (MetaPreference pref,
1370
const gchar *string_value,
1371
gboolean *inform_listeners)
1373
g_free (current_theme);
1375
/* Fallback crackrock */
1376
if (string_value == NULL)
1377
current_theme = g_strdup ("Atlanta");
1379
current_theme = g_strdup (string_value);
1383
mouse_button_mods_handler (MetaPreference pref,
1384
const gchar *string_value,
1385
gboolean *inform_listeners)
1387
MetaVirtualModifier mods;
1389
meta_topic (META_DEBUG_KEYBINDINGS,
1390
"Mouse button modifier has new gconf value \"%s\"\n",
1392
if (string_value && meta_ui_parse_modifier (string_value, &mods))
1394
mouse_button_mods = mods;
1398
meta_topic (META_DEBUG_KEYBINDINGS,
1399
"Failed to parse new gconf value\n");
1401
meta_warning (_("\"%s\" found in configuration database is "
1402
"not a valid value for mouse button modifier\n"),
1405
*inform_listeners = FALSE;
1410
button_layout_equal (const MetaButtonLayout *a,
1411
const MetaButtonLayout *b)
1416
while (i < MAX_BUTTONS_PER_CORNER)
1418
if (a->left_buttons[i] != b->left_buttons[i])
1420
if (a->right_buttons[i] != b->right_buttons[i])
1422
if (a->left_buttons_has_spacer[i] != b->left_buttons_has_spacer[i])
1424
if (a->right_buttons_has_spacer[i] != b->right_buttons_has_spacer[i])
1432
static MetaButtonFunction
1433
button_function_from_string (const char *str)
1435
/* FIXME: gconf_string_to_enum is the obvious way to do this */
1437
if (strcmp (str, "menu") == 0)
1438
return META_BUTTON_FUNCTION_MENU;
1439
else if (strcmp (str, "minimize") == 0)
1440
return META_BUTTON_FUNCTION_MINIMIZE;
1441
else if (strcmp (str, "maximize") == 0)
1442
return META_BUTTON_FUNCTION_MAXIMIZE;
1443
else if (strcmp (str, "close") == 0)
1444
return META_BUTTON_FUNCTION_CLOSE;
1445
else if (strcmp (str, "shade") == 0)
1446
return META_BUTTON_FUNCTION_SHADE;
1447
else if (strcmp (str, "above") == 0)
1448
return META_BUTTON_FUNCTION_ABOVE;
1449
else if (strcmp (str, "stick") == 0)
1450
return META_BUTTON_FUNCTION_STICK;
1452
/* don't know; give up */
1453
return META_BUTTON_FUNCTION_LAST;
1456
static MetaButtonFunction
1457
button_opposite_function (MetaButtonFunction ofwhat)
1461
case META_BUTTON_FUNCTION_SHADE:
1462
return META_BUTTON_FUNCTION_UNSHADE;
1463
case META_BUTTON_FUNCTION_UNSHADE:
1464
return META_BUTTON_FUNCTION_SHADE;
1466
case META_BUTTON_FUNCTION_ABOVE:
1467
return META_BUTTON_FUNCTION_UNABOVE;
1468
case META_BUTTON_FUNCTION_UNABOVE:
1469
return META_BUTTON_FUNCTION_ABOVE;
1471
case META_BUTTON_FUNCTION_STICK:
1472
return META_BUTTON_FUNCTION_UNSTICK;
1473
case META_BUTTON_FUNCTION_UNSTICK:
1474
return META_BUTTON_FUNCTION_STICK;
1477
return META_BUTTON_FUNCTION_LAST;
1482
button_layout_handler (MetaPreference pref,
1483
const gchar *string_value,
1484
gboolean *inform_listeners)
1486
MetaButtonLayout new_layout;
1487
char **sides = NULL;
1490
/* We need to ignore unknown button functions, for
1491
* compat with future versions
1495
sides = g_strsplit (string_value, ":", 2);
1497
if (sides != NULL && sides[0] != NULL)
1501
gboolean used[META_BUTTON_FUNCTION_LAST];
1504
while (i < META_BUTTON_FUNCTION_LAST)
1507
new_layout.left_buttons_has_spacer[i] = FALSE;
1511
buttons = g_strsplit (sides[0], ",", -1);
1514
while (buttons[b] != NULL)
1516
MetaButtonFunction f = button_function_from_string (buttons[b]);
1517
if (i > 0 && strcmp("spacer", buttons[b]) == 0)
1519
new_layout.left_buttons_has_spacer[i-1] = TRUE;
1520
f = button_opposite_function (f);
1522
if (f != META_BUTTON_FUNCTION_LAST)
1524
new_layout.left_buttons_has_spacer[i-2] = TRUE;
1529
if (f != META_BUTTON_FUNCTION_LAST && !used[f])
1531
new_layout.left_buttons[i] = f;
1535
f = button_opposite_function (f);
1537
if (f != META_BUTTON_FUNCTION_LAST)
1538
new_layout.left_buttons[i++] = f;
1543
meta_topic (META_DEBUG_PREFS, "Ignoring unknown or already-used button name \"%s\"\n",
1551
new_layout.left_buttons[i] = META_BUTTON_FUNCTION_LAST;
1552
new_layout.left_buttons_has_spacer[i] = FALSE;
1554
g_strfreev (buttons);
1557
if (sides != NULL && sides[0] != NULL && sides[1] != NULL)
1561
gboolean used[META_BUTTON_FUNCTION_LAST];
1564
while (i < META_BUTTON_FUNCTION_LAST)
1567
new_layout.right_buttons_has_spacer[i] = FALSE;
1571
buttons = g_strsplit (sides[1], ",", -1);
1574
while (buttons[b] != NULL)
1576
MetaButtonFunction f = button_function_from_string (buttons[b]);
1577
if (i > 0 && strcmp("spacer", buttons[b]) == 0)
1579
new_layout.right_buttons_has_spacer[i-1] = TRUE;
1580
f = button_opposite_function (f);
1581
if (f != META_BUTTON_FUNCTION_LAST)
1583
new_layout.right_buttons_has_spacer[i-2] = TRUE;
1588
if (f != META_BUTTON_FUNCTION_LAST && !used[f])
1590
new_layout.right_buttons[i] = f;
1594
f = button_opposite_function (f);
1596
if (f != META_BUTTON_FUNCTION_LAST)
1597
new_layout.right_buttons[i++] = f;
1602
meta_topic (META_DEBUG_PREFS, "Ignoring unknown or already-used button name \"%s\"\n",
1610
new_layout.right_buttons[i] = META_BUTTON_FUNCTION_LAST;
1611
new_layout.right_buttons_has_spacer[i] = FALSE;
1613
g_strfreev (buttons);
1618
/* Invert the button layout for RTL languages */
1619
if (meta_ui_get_direction() == META_UI_DIRECTION_RTL)
1621
MetaButtonLayout rtl_layout;
1624
for (i = 0; new_layout.left_buttons[i] != META_BUTTON_FUNCTION_LAST; i++);
1625
for (j = 0; j < i; j++)
1627
rtl_layout.right_buttons[j] = new_layout.left_buttons[i - j - 1];
1629
rtl_layout.right_buttons_has_spacer[i - 1] = new_layout.left_buttons_has_spacer[i - j - 1];
1631
rtl_layout.right_buttons_has_spacer[j - 1] = new_layout.left_buttons_has_spacer[i - j - 1];
1633
rtl_layout.right_buttons[j] = META_BUTTON_FUNCTION_LAST;
1634
rtl_layout.right_buttons_has_spacer[j] = FALSE;
1636
for (i = 0; new_layout.right_buttons[i] != META_BUTTON_FUNCTION_LAST; i++);
1637
for (j = 0; j < i; j++)
1639
rtl_layout.left_buttons[j] = new_layout.right_buttons[i - j - 1];
1641
rtl_layout.left_buttons_has_spacer[i - 1] = new_layout.right_buttons_has_spacer[i - j - 1];
1643
rtl_layout.left_buttons_has_spacer[j - 1] = new_layout.right_buttons_has_spacer[i - j - 1];
1645
rtl_layout.left_buttons[j] = META_BUTTON_FUNCTION_LAST;
1646
rtl_layout.left_buttons_has_spacer[j] = FALSE;
1648
new_layout = rtl_layout;
1651
if (button_layout_equal (&button_layout, &new_layout))
1653
/* Same as before, so duck out */
1654
*inform_listeners = FALSE;
1658
button_layout = new_layout;
1662
#endif /* HAVE_GCONF */
1664
const PangoFontDescription*
1665
meta_prefs_get_titlebar_font (void)
1667
if (use_system_font)
1670
return titlebar_font;
1674
meta_prefs_get_num_workspaces (void)
1676
return num_workspaces;
1680
meta_prefs_get_application_based (void)
1682
return FALSE; /* For now, we never want this to do anything */
1684
return application_based;
1688
meta_prefs_get_disable_workarounds (void)
1690
return disable_workarounds;
1694
#define MAX_REASONABLE_AUTO_RAISE_DELAY 10000
1696
#endif /* HAVE_GCONF */
1698
#ifdef WITH_VERBOSE_MODE
1700
meta_preference_to_string (MetaPreference pref)
1702
/* FIXME: another case for gconf_string_to_enum */
1705
case META_PREF_MOUSE_BUTTON_MODS:
1706
return "MOUSE_BUTTON_MODS";
1708
case META_PREF_FOCUS_MODE:
1709
return "FOCUS_MODE";
1711
case META_PREF_FOCUS_NEW_WINDOWS:
1712
return "FOCUS_NEW_WINDOWS";
1714
case META_PREF_RAISE_ON_CLICK:
1715
return "RAISE_ON_CLICK";
1717
case META_PREF_THEME:
1720
case META_PREF_TITLEBAR_FONT:
1721
return "TITLEBAR_FONT";
1723
case META_PREF_NUM_WORKSPACES:
1724
return "NUM_WORKSPACES";
1726
case META_PREF_APPLICATION_BASED:
1727
return "APPLICATION_BASED";
1729
case META_PREF_KEYBINDINGS:
1730
return "KEYBINDINGS";
1732
case META_PREF_DISABLE_WORKAROUNDS:
1733
return "DISABLE_WORKAROUNDS";
1735
case META_PREF_ACTION_DOUBLE_CLICK_TITLEBAR:
1736
return "ACTION_DOUBLE_CLICK_TITLEBAR";
1738
case META_PREF_ACTION_MIDDLE_CLICK_TITLEBAR:
1739
return "ACTION_MIDDLE_CLICK_TITLEBAR";
1741
case META_PREF_ACTION_RIGHT_CLICK_TITLEBAR:
1742
return "ACTION_RIGHT_CLICK_TITLEBAR";
1744
case META_PREF_AUTO_RAISE:
1745
return "AUTO_RAISE";
1747
case META_PREF_AUTO_RAISE_DELAY:
1748
return "AUTO_RAISE_DELAY";
1750
case META_PREF_COMMANDS:
1753
case META_PREF_TERMINAL_COMMAND:
1754
return "TERMINAL_COMMAND";
1756
case META_PREF_BUTTON_LAYOUT:
1757
return "BUTTON_LAYOUT";
1759
case META_PREF_WORKSPACE_NAMES:
1760
return "WORKSPACE_NAMES";
1762
case META_PREF_VISUAL_BELL:
1763
return "VISUAL_BELL";
1765
case META_PREF_AUDIBLE_BELL:
1766
return "AUDIBLE_BELL";
1768
case META_PREF_VISUAL_BELL_TYPE:
1769
return "VISUAL_BELL_TYPE";
1771
case META_PREF_REDUCED_RESOURCES:
1772
return "REDUCED_RESOURCES";
1774
case META_PREF_GNOME_ACCESSIBILITY:
1775
return "GNOME_ACCESSIBILTY";
1777
case META_PREF_GNOME_ANIMATIONS:
1778
return "GNOME_ANIMATIONS";
1780
case META_PREF_CURSOR_THEME:
1781
return "CURSOR_THEME";
1783
case META_PREF_CURSOR_SIZE:
1784
return "CURSOR_SIZE";
1786
case META_PREF_COMPOSITING_MANAGER:
1787
return "COMPOSITING_MANAGER";
1789
case META_PREF_COMPOSITOR_EFFECTS:
1790
return "COMPOSITOR_EFFECTS";
1792
case META_PREF_CAPTURE_BEFORE_UNMAP:
1793
return "CAPTURE_BEFORE_UNMAP";
1795
case META_PREF_RESIZE_WITH_RIGHT_BUTTON:
1796
return "RESIZE_WITH_RIGHT_BUTTON";
1798
case META_PREF_FORCE_FULLSCREEN:
1799
return "FORCE_FULLSCREEN";
1801
case META_PREF_HIDE_DECORATOR_TOOLTIP:
1802
return "HIDE_DECORATOR_TOOLTIP";
1804
case META_PREF_SHOW_MAXIMIZED_TITLEBARS:
1805
return "META_PREF_SHOW_MAXIMIZED_TITLEBARS";
1810
#endif /* WITH_VERBOSE_MODE */
1813
meta_prefs_set_num_workspaces (int n_workspaces)
1818
if (default_client == NULL)
1821
if (n_workspaces < 1)
1823
if (n_workspaces > MAX_REASONABLE_WORKSPACES)
1824
n_workspaces = MAX_REASONABLE_WORKSPACES;
1827
gconf_client_set_int (default_client,
1834
meta_warning (_("Error setting number of workspaces to %d: %s\n"),
1839
#endif /* HAVE_GCONF */
1842
#define keybind(name, handler, param, flags, stroke, description) \
1843
{ #name, NULL, !!(flags & BINDING_REVERSES), !!(flags & BINDING_PER_WINDOW) },
1844
static MetaKeyPref key_bindings[] = {
1845
#include "all-keybindings.h"
1846
{ NULL, NULL, FALSE }
1853
* A type to map names of keybindings (such as "switch_windows")
1854
* to the binding strings themselves (such as "<Alt>Tab").
1855
* It exists only when GConf is turned off in ./configure and
1856
* functions as a sort of ersatz GConf.
1861
const char *keybinding;
1862
} MetaSimpleKeyMapping;
1864
/* FIXME: This would be neater if the array only contained entries whose
1865
* default keystroke was non-null. You COULD do this by defining
1866
* ONLY_BOUND_BY_DEFAULT around various blocks at the cost of making
1867
* the bindings file way more complicated. However, we could stop this being
1868
* data and move it into code. Then the compiler would optimise away
1869
* the problem lines.
1872
#define keybind(name, handler, param, flags, stroke, description) \
1875
static MetaSimpleKeyMapping key_string_bindings[] = {
1876
#include "all-keybindings.h"
1881
#endif /* NOT HAVE_GCONF */
1884
init_bindings (void)
1887
const char *prefix[] = {
1888
KEY_WINDOW_BINDINGS_PREFIX,
1889
KEY_SCREEN_BINDINGS_PREFIX,
1893
GSList *list, *l, *list_val;
1894
const char *str_val;
1899
for (i = 0; prefix[i]; i++)
1901
list = gconf_client_all_entries (default_client, prefix[i], NULL);
1902
for (l = list; l; l = l->next)
1905
key = gconf_entry_get_key (entry);
1906
value = gconf_entry_get_value (entry);
1907
if (g_str_has_suffix (key, KEY_LIST_BINDINGS_SUFFIX))
1909
list_val = gconf_client_get_list (default_client, key, GCONF_VALUE_STRING, NULL);
1911
update_key_list_binding (key, list_val);
1912
g_slist_foreach (list_val, (GFunc)g_free, NULL);
1913
g_slist_free (list_val);
1917
str_val = gconf_value_get_string (value);
1918
update_key_binding (key, str_val);
1920
gconf_entry_free (entry);
1922
g_slist_free (list);
1924
#else /* HAVE_GCONF */
1927
while (key_string_bindings[i].name)
1929
if (key_string_bindings[i].keybinding == NULL) {
1934
while (strcmp(key_bindings[which].name,
1935
key_string_bindings[i].name) != 0)
1938
/* Set the binding */
1939
update_binding (&key_bindings[which],
1940
key_string_bindings[i].keybinding);
1944
#endif /* HAVE_GCONF */
1948
init_commands (void)
1952
const char *str_val;
1957
list = gconf_client_all_entries (default_client, KEY_COMMAND_DIRECTORY, NULL);
1958
for (l = list; l; l = l->next)
1961
key = gconf_entry_get_key (entry);
1962
value = gconf_entry_get_value (entry);
1963
str_val = gconf_value_get_string (value);
1964
update_command (key, str_val);
1965
gconf_entry_free (entry);
1967
g_slist_free (list);
1970
for (i = 0; i < MAX_COMMANDS; i++)
1972
#endif /* HAVE_GCONF */
1976
init_workspace_names (void)
1979
for (i = 0; i < MAX_REASONABLE_WORKSPACES; i++)
1980
workspace_names[i] = NULL;
1984
const char *str_val;
1989
list = gconf_client_all_entries (default_client, KEY_WORKSPACE_NAME_DIRECTORY, NULL);
1990
for (l = list; l; l = l->next)
1993
key = gconf_entry_get_key (entry);
1994
value = gconf_entry_get_value (entry);
1995
str_val = gconf_value_get_string (value);
1996
update_workspace_name (key, str_val);
1997
gconf_entry_free (entry);
1999
g_slist_free (list);
2000
#endif /* HAVE_GCONF */
2002
/* initialise any we didn't see */
2003
for (i = 0; i < MAX_REASONABLE_WORKSPACES; i++)
2004
if (workspace_names[i]==NULL)
2005
workspace_names[i] = g_strdup_printf (_("Workspace %d"), i + 1);
2007
meta_topic (META_DEBUG_PREFS,
2008
"Initialized workspace names\n");
2012
update_binding (MetaKeyPref *binding,
2015
unsigned int keysym;
2016
unsigned int keycode;
2017
MetaVirtualModifier mods;
2018
MetaKeyCombo *combo;
2021
meta_topic (META_DEBUG_KEYBINDINGS,
2022
"Binding \"%s\" has new gconf value \"%s\"\n",
2023
binding->name, value ? value : "none");
2030
if (!meta_ui_parse_accelerator (value, &keysym, &keycode, &mods))
2032
meta_topic (META_DEBUG_KEYBINDINGS,
2033
"Failed to parse new gconf value\n");
2034
meta_warning (_("\"%s\" found in configuration database is not a valid value for keybinding \"%s\"\n"),
2035
value, binding->name);
2041
/* If there isn't already a first element, make one. */
2042
if (!binding->bindings)
2044
MetaKeyCombo *blank = g_malloc0 (sizeof (MetaKeyCombo));
2045
binding->bindings = g_slist_alloc();
2046
binding->bindings->data = blank;
2049
combo = binding->bindings->data;
2052
/* Bug 329676: Bindings which can be shifted must not have no modifiers,
2053
* nor only SHIFT as a modifier.
2056
if (binding->add_shift &&
2058
(META_VIRTUAL_SHIFT_MASK == mods || 0 == mods))
2064
meta_warning ("Cannot bind \"%s\" to %s: it needs a modifier "
2065
"such as Ctrl or Alt.\n",
2069
old_setting = meta_ui_accelerator_name (combo->keysym,
2072
if (!strcmp(old_setting, value))
2074
/* We were about to set it to the same value
2075
* that it had originally! This must be caused
2076
* by getting an invalid string back from
2077
* meta_ui_accelerator_name. Bail out now
2078
* so we don't get into an infinite loop.
2080
g_free (old_setting);
2084
meta_warning ("Reverting \"%s\" to %s.\n",
2088
/* FIXME: add_shift is currently screen_bindings only, but
2089
* there's no really good reason it should always be.
2090
* So we shouldn't blindly add KEY_SCREEN_BINDINGS_PREFIX
2093
key = g_strconcat (KEY_SCREEN_BINDINGS_PREFIX, "/",
2094
binding->name, NULL);
2096
gconf_client_set_string (gconf_client_get_default (),
2097
key, old_setting, &err);
2101
meta_warning ("Error while reverting keybinding: %s\n",
2107
g_free (old_setting);
2110
/* The call to gconf_client_set_string() will cause this function
2111
* to be called again with the new value, so there's no need to
2119
if (keysym != combo->keysym ||
2120
keycode != combo->keycode ||
2121
mods != combo->modifiers)
2125
combo->keysym = keysym;
2126
combo->keycode = keycode;
2127
combo->modifiers = mods;
2129
meta_topic (META_DEBUG_KEYBINDINGS,
2130
"New keybinding for \"%s\" is keysym = 0x%x keycode = 0x%x mods = 0x%x\n",
2131
binding->name, combo->keysym, combo->keycode,
2136
meta_topic (META_DEBUG_KEYBINDINGS,
2137
"Keybinding for \"%s\" is unchanged\n", binding->name);
2145
update_list_binding (MetaKeyPref *binding,
2147
MetaStringListType type_of_value)
2149
unsigned int keysym;
2150
unsigned int keycode;
2151
MetaVirtualModifier mods;
2152
gboolean changed = FALSE;
2153
const gchar *pref_string;
2154
GSList *pref_iterator = value, *tmp;
2155
MetaKeyCombo *combo;
2157
meta_topic (META_DEBUG_KEYBINDINGS,
2158
"Binding \"%s\" has new gconf value\n",
2161
if (binding->bindings == NULL)
2163
/* We need to insert a dummy element into the list, because the first
2164
* element is the one governed by update_binding. We only handle the
2165
* subsequent elements.
2167
MetaKeyCombo *blank = g_malloc0 (sizeof (MetaKeyCombo));
2168
binding->bindings = g_slist_alloc();
2169
binding->bindings->data = blank;
2172
/* Okay, so, we're about to provide a new list of key combos for this
2173
* action. Delete any pre-existing list.
2175
tmp = binding->bindings->next;
2181
g_slist_free (binding->bindings->next);
2182
binding->bindings->next = NULL;
2184
while (pref_iterator)
2190
if (!pref_iterator->data)
2192
pref_iterator = pref_iterator->next;
2196
switch (type_of_value)
2198
case META_LIST_OF_STRINGS:
2199
pref_string = pref_iterator->data;
2201
case META_LIST_OF_GCONFVALUE_STRINGS:
2202
pref_string = gconf_value_get_string (pref_iterator->data);
2205
g_assert_not_reached ();
2208
if (!meta_ui_parse_accelerator (pref_string, &keysym, &keycode, &mods))
2210
meta_topic (META_DEBUG_KEYBINDINGS,
2211
"Failed to parse new gconf value\n");
2212
meta_warning (_("\"%s\" found in configuration database is not a valid value for keybinding \"%s\"\n"),
2213
pref_string, binding->name);
2215
/* Should we remove this value from the list in gconf? */
2216
pref_iterator = pref_iterator->next;
2220
/* Bug 329676: Bindings which can be shifted must not have no modifiers,
2221
* nor only SHIFT as a modifier.
2224
if (binding->add_shift &&
2226
(META_VIRTUAL_SHIFT_MASK == mods || 0 == mods))
2228
meta_warning ("Cannot bind \"%s\" to %s: it needs a modifier "
2229
"such as Ctrl or Alt.\n",
2233
/* Should we remove this value from the list in gconf? */
2235
pref_iterator = pref_iterator->next;
2241
combo = g_malloc0 (sizeof (MetaKeyCombo));
2242
combo->keysym = keysym;
2243
combo->keycode = keycode;
2244
combo->modifiers = mods;
2245
binding->bindings->next = g_slist_prepend (binding->bindings->next, combo);
2247
meta_topic (META_DEBUG_KEYBINDINGS,
2248
"New keybinding for \"%s\" is keysym = 0x%x keycode = 0x%x mods = 0x%x\n",
2249
binding->name, keysym, keycode, mods);
2251
pref_iterator = pref_iterator->next;
2257
relative_key (const gchar* key)
2261
end = strrchr (key, '/');
2268
/* Return value is TRUE if a preference changed and we need to
2272
find_and_update_binding (MetaKeyPref *bindings,
2280
key = relative_key (name);
2285
while (bindings[i].name &&
2286
strcmp (key, bindings[i].name) != 0)
2289
if (bindings[i].name)
2290
return update_binding (&bindings[i], value);
2296
update_key_binding (const char *name,
2299
return find_and_update_binding (key_bindings, name, value);
2303
find_and_update_list_binding (MetaKeyPref *bindings,
2309
gchar *name_without_suffix = g_strdup(name);
2311
name_without_suffix[strlen(name_without_suffix) - strlen(KEY_LIST_BINDINGS_SUFFIX)] = 0;
2313
if (*name_without_suffix == '/')
2314
key = relative_key (name_without_suffix);
2316
key = name_without_suffix;
2319
while (bindings[i].name &&
2320
strcmp (key, bindings[i].name) != 0)
2323
g_free (name_without_suffix);
2325
if (bindings[i].name)
2326
return update_list_binding (&bindings[i], value, META_LIST_OF_GCONFVALUE_STRINGS);
2332
update_key_list_binding (const char *name,
2335
return find_and_update_list_binding (key_bindings, name, value);
2339
update_command (const char *name,
2345
p = strrchr (name, '_');
2348
meta_topic (META_DEBUG_KEYBINDINGS,
2349
"Command %s has no underscore?\n", name);
2355
if (g_ascii_isdigit (*p))
2358
i -= 1; /* count from 0 not 1 */
2362
p = strrchr (name, '/');
2365
if (strcmp (p, "command_screenshot") == 0)
2367
i = SCREENSHOT_COMMAND_IDX;
2369
else if (strcmp (p, "command_window_screenshot") == 0)
2371
i = WIN_SCREENSHOT_COMMAND_IDX;
2375
meta_topic (META_DEBUG_KEYBINDINGS,
2376
"Command %s doesn't end in number?\n", name);
2381
if (i >= MAX_COMMANDS)
2383
meta_topic (META_DEBUG_KEYBINDINGS,
2384
"Command %d is too highly numbered, ignoring\n", i);
2388
if ((commands[i] == NULL && value == NULL) ||
2389
(commands[i] && value && strcmp (commands[i], value) == 0))
2391
meta_topic (META_DEBUG_KEYBINDINGS,
2392
"Command %d is unchanged\n", i);
2396
g_free (commands[i]);
2397
commands[i] = g_strdup (value);
2399
meta_topic (META_DEBUG_KEYBINDINGS,
2400
"Updated command %d to \"%s\"\n",
2401
i, commands[i] ? commands[i] : "none");
2406
#endif /* HAVE_GCONF */
2409
meta_prefs_get_command (int i)
2411
g_return_val_if_fail (i >= 0 && i < MAX_COMMANDS, NULL);
2417
meta_prefs_get_gconf_key_for_command (int i)
2423
case SCREENSHOT_COMMAND_IDX:
2424
key = g_strdup (KEY_COMMAND_PREFIX "screenshot");
2426
case WIN_SCREENSHOT_COMMAND_IDX:
2427
key = g_strdup (KEY_COMMAND_PREFIX "window_screenshot");
2430
key = g_strdup_printf (KEY_COMMAND_PREFIX"%d", i + 1);
2438
meta_prefs_get_terminal_command (void)
2440
return terminal_command;
2444
meta_prefs_get_gconf_key_for_terminal_command (void)
2446
return KEY_TERMINAL_COMMAND;
2451
update_workspace_name (const char *name,
2457
p = strrchr (name, '_');
2460
meta_topic (META_DEBUG_PREFS,
2461
"Workspace name %s has no underscore?\n", name);
2467
if (!g_ascii_isdigit (*p))
2469
meta_topic (META_DEBUG_PREFS,
2470
"Workspace name %s doesn't end in number?\n", name);
2475
i -= 1; /* count from 0 not 1 */
2477
if (i >= MAX_REASONABLE_WORKSPACES)
2479
meta_topic (META_DEBUG_PREFS,
2480
"Workspace name %d is too highly numbered, ignoring\n", i);
2484
if (workspace_names[i] && value && strcmp (workspace_names[i], value) == 0)
2486
meta_topic (META_DEBUG_PREFS,
2487
"Workspace name %d is unchanged\n", i);
2491
/* This is a bad hack. We have to treat empty string as
2492
* "unset" because the root window property can't contain
2493
* null. So it gets empty string instead and we don't want
2494
* that to result in setting the empty string as a value that
2495
* overrides "unset".
2497
if (value != NULL && *value != '\0')
2499
g_free (workspace_names[i]);
2500
workspace_names[i] = g_strdup (value);
2504
/* use a default name */
2507
d = g_strdup_printf (_("Workspace %d"), i + 1);
2508
if (workspace_names[i] && strcmp (workspace_names[i], d) == 0)
2515
g_free (workspace_names[i]);
2516
workspace_names[i] = d;
2520
meta_topic (META_DEBUG_PREFS,
2521
"Updated workspace name %d to \"%s\"\n",
2522
i, workspace_names[i] ? workspace_names[i] : "none");
2526
#endif /* HAVE_GCONF */
2529
meta_prefs_get_workspace_name (int i)
2531
g_return_val_if_fail (i >= 0 && i < MAX_REASONABLE_WORKSPACES, NULL);
2533
g_assert (workspace_names[i] != NULL);
2535
meta_topic (META_DEBUG_PREFS,
2536
"Getting workspace name for %d: \"%s\"\n",
2537
i, workspace_names[i]);
2539
return workspace_names[i];
2543
meta_prefs_change_workspace_name (int i,
2550
g_return_if_fail (i >= 0 && i < MAX_REASONABLE_WORKSPACES);
2552
meta_topic (META_DEBUG_PREFS,
2553
"Changing name of workspace %d to %s\n",
2554
i, name ? name : "none");
2556
/* This is a bad hack. We have to treat empty string as
2557
* "unset" because the root window property can't contain
2558
* null. So it gets empty string instead and we don't want
2559
* that to result in setting the empty string as a value that
2560
* overrides "unset".
2562
if (name && *name == '\0')
2565
if ((name == NULL && workspace_names[i] == NULL) ||
2566
(name && workspace_names[i] && strcmp (name, workspace_names[i]) == 0))
2568
meta_topic (META_DEBUG_PREFS,
2569
"Workspace %d already has name %s\n",
2570
i, name ? name : "none");
2574
key = gconf_key_for_workspace_name (i);
2578
gconf_client_set_string (default_client,
2582
gconf_client_unset (default_client,
2588
meta_warning (_("Error setting name for workspace %d to \"%s\": %s\n"),
2589
i, name ? name : "none",
2596
g_free (workspace_names[i]);
2597
workspace_names[i] = g_strdup (name);
2598
#endif /* HAVE_GCONF */
2603
gconf_key_for_workspace_name (int i)
2607
key = g_strdup_printf (KEY_WORKSPACE_NAME_PREFIX"%d", i + 1);
2611
#endif /* HAVE_GCONF */
2614
meta_prefs_get_button_layout (MetaButtonLayout *button_layout_p)
2616
*button_layout_p = button_layout;
2620
meta_prefs_get_visual_bell (void)
2622
return provide_visual_bell;
2626
meta_prefs_bell_is_audible (void)
2628
return bell_is_audible;
2632
meta_prefs_get_visual_bell_type (void)
2634
return visual_bell_type;
2638
meta_prefs_get_key_bindings (const MetaKeyPref **bindings,
2642
*bindings = key_bindings;
2643
*n_bindings = (int) G_N_ELEMENTS (key_bindings) - 1;
2647
meta_prefs_get_action_double_click_titlebar (void)
2649
return action_double_click_titlebar;
2653
meta_prefs_get_action_middle_click_titlebar (void)
2655
return action_middle_click_titlebar;
2659
meta_prefs_get_action_right_click_titlebar (void)
2661
return action_right_click_titlebar;
2665
meta_prefs_get_auto_raise (void)
2671
meta_prefs_get_auto_raise_delay (void)
2673
return auto_raise_delay;
2677
meta_prefs_get_reduced_resources (void)
2679
return reduced_resources;
2683
meta_prefs_get_gnome_accessibility ()
2685
return gnome_accessibility;
2689
meta_prefs_get_gnome_animations ()
2691
return gnome_animations;
2694
MetaKeyBindingAction
2695
meta_prefs_get_keybinding_action (const char *name)
2699
i = G_N_ELEMENTS (key_bindings) - 2; /* -2 for dummy entry at end */
2702
if (strcmp (key_bindings[i].name, name) == 0)
2703
return (MetaKeyBindingAction) i;
2708
return META_KEYBINDING_ACTION_NONE;
2711
/* This is used by the menu system to decide what key binding
2712
* to display next to an option. We return the first non-disabled
2716
meta_prefs_get_window_binding (const char *name,
2717
unsigned int *keysym,
2718
MetaVirtualModifier *modifiers)
2722
i = G_N_ELEMENTS (key_bindings) - 2; /* -2 for dummy entry at end */
2725
if (key_bindings[i].per_window &&
2726
strcmp (key_bindings[i].name, name) == 0)
2728
GSList *s = key_bindings[i].bindings;
2732
MetaKeyCombo *c = s->data;
2734
if (c->keysym!=0 || c->modifiers!=0)
2736
*keysym = c->keysym;
2737
*modifiers = c->modifiers;
2744
/* Not found; return the disabled value */
2745
*keysym = *modifiers = 0;
2752
g_assert_not_reached ();
2756
meta_prefs_get_compositing_manager (void)
2758
return compositing_manager;
2762
meta_prefs_get_mouse_button_resize (void)
2764
return resize_with_right_button ? 3: 2;
2768
meta_prefs_get_mouse_button_menu (void)
2770
return resize_with_right_button ? 2: 3;
2774
meta_prefs_get_force_fullscreen (void)
2776
return force_fullscreen;
2780
meta_prefs_set_compositing_manager (gboolean whether)
2785
gconf_client_set_bool (default_client,
2792
meta_warning (_("Error setting compositor status: %s\n"),
2797
compositing_manager = whether;
2802
meta_prefs_get_compositor_effects (void)
2804
return compositor_effects;
2808
meta_prefs_get_capture_before_unmap (void)
2810
return capture_before_unmap;
2815
init_button_layout(void)
2817
MetaButtonLayout button_layout_ltr = {
2819
/* buttons in the group on the left side */
2820
META_BUTTON_FUNCTION_MENU,
2821
META_BUTTON_FUNCTION_LAST
2824
/* buttons in the group on the right side */
2825
META_BUTTON_FUNCTION_MINIMIZE,
2826
META_BUTTON_FUNCTION_MAXIMIZE,
2827
META_BUTTON_FUNCTION_CLOSE,
2828
META_BUTTON_FUNCTION_LAST
2831
MetaButtonLayout button_layout_rtl = {
2833
/* buttons in the group on the left side */
2834
META_BUTTON_FUNCTION_CLOSE,
2835
META_BUTTON_FUNCTION_MAXIMIZE,
2836
META_BUTTON_FUNCTION_MINIMIZE,
2837
META_BUTTON_FUNCTION_LAST
2840
/* buttons in the group on the right side */
2841
META_BUTTON_FUNCTION_MENU,
2842
META_BUTTON_FUNCTION_LAST
2846
button_layout = meta_ui_get_direction() == META_UI_DIRECTION_LTR ?
2847
button_layout_ltr : button_layout_rtl;
2853
meta_prefs_set_force_fullscreen (gboolean whether)
2855
force_fullscreen = whether;