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 resize_with_right_button = FALSE;
100
static gboolean force_fullscreen = TRUE;
102
static MetaVisualBellType visual_bell_type = META_VISUAL_BELL_FULLSCREEN_FLASH;
103
static MetaButtonLayout button_layout;
105
/* The screenshot commands are at the end */
106
static char *commands[MAX_COMMANDS] = { NULL, };
108
static char *terminal_command = NULL;
110
static char *workspace_names[MAX_REASONABLE_WORKSPACES] = { NULL, };
113
static gboolean handle_preference_update_enum (const gchar *key, GConfValue *value);
115
static gboolean update_key_binding (const char *name,
117
static gboolean find_and_update_list_binding (MetaKeyPref *bindings,
120
static gboolean update_key_list_binding (const char *name,
122
static gboolean update_command (const char *name,
124
static gboolean update_workspace_name (const char *name,
127
static void change_notify (GConfClient *client,
132
static char* gconf_key_for_workspace_name (int i);
134
static void queue_changed (MetaPreference pref);
138
META_LIST_OF_STRINGS,
139
META_LIST_OF_GCONFVALUE_STRINGS
140
} MetaStringListType;
142
static gboolean update_list_binding (MetaKeyPref *binding,
144
MetaStringListType type_of_value);
146
static void cleanup_error (GError **error);
147
static gboolean get_bool (const char *key, gboolean *val);
148
static void maybe_give_disable_workarounds_warning (void);
150
static void titlebar_handler (MetaPreference, const gchar*, gboolean*);
151
static void theme_name_handler (MetaPreference, const gchar*, gboolean*);
152
static void mouse_button_mods_handler (MetaPreference, const gchar*, gboolean*);
153
static void button_layout_handler (MetaPreference, const gchar*, gboolean*);
155
#endif /* HAVE_GCONF */
157
static gboolean update_binding (MetaKeyPref *binding,
160
static void init_bindings (void);
161
static void init_commands (void);
162
static void init_workspace_names (void);
165
static void init_button_layout (void);
166
#endif /* !HAVE_GCONF */
172
MetaPrefsChangedFunc func;
176
static GConfEnumStringPair symtab_focus_mode[] =
178
{ META_FOCUS_MODE_CLICK, "click" },
179
{ META_FOCUS_MODE_SLOPPY, "sloppy" },
180
{ META_FOCUS_MODE_MOUSE, "mouse" },
181
{ META_FOCUS_MODE_STRICT, "strict" },
185
static GConfEnumStringPair symtab_focus_new_windows[] =
187
{ META_FOCUS_NEW_WINDOWS_SMART, "smart" },
188
{ META_FOCUS_NEW_WINDOWS_STRICT, "strict" },
192
static GConfEnumStringPair symtab_visual_bell_type[] =
194
/* Note to the reader: 0 is an invalid value; these start at 1. */
195
{ META_VISUAL_BELL_FULLSCREEN_FLASH, "fullscreen" },
196
{ META_VISUAL_BELL_FRAME_FLASH, "frame_flash" },
200
static GConfEnumStringPair symtab_titlebar_action[] =
202
{ META_ACTION_TITLEBAR_TOGGLE_SHADE, "toggle_shade" },
203
{ META_ACTION_TITLEBAR_TOGGLE_MAXIMIZE, "toggle_maximize" },
204
{ META_ACTION_TITLEBAR_TOGGLE_MAXIMIZE_HORIZONTALLY,
205
"toggle_maximize_horizontally" },
206
{ META_ACTION_TITLEBAR_TOGGLE_MAXIMIZE_VERTICALLY,
207
"toggle_maximize_vertically" },
208
{ META_ACTION_TITLEBAR_MINIMIZE, "minimize" },
209
{ META_ACTION_TITLEBAR_NONE, "none" },
210
{ META_ACTION_TITLEBAR_LOWER, "lower" },
211
{ META_ACTION_TITLEBAR_MENU, "menu" },
212
{ META_ACTION_TITLEBAR_TOGGLE_SHADE, "toggle_shade" },
217
* The details of one preference which is constrained to be
218
* one of a small number of string values-- in other words,
221
* We could have done this other ways. One particularly attractive
222
* possibility would have been to represent the entire symbol table
223
* as a space-separated string literal in the list of symtabs, so
224
* the focus mode enums could have been represented simply by
225
* "click sloppy mouse". However, the simplicity gained would have
226
* been outweighed by the bugs caused when the ordering of the enum
227
* strings got out of sync with the actual enum statement. Also,
228
* there is existing library code to use this kind of symbol tables.
230
* Other things we might consider doing to clean this up in the
233
* - most of the keys begin with the same prefix, and perhaps we
234
* could assume it if they don't start with a slash
236
* - there are several cases where a single identifier could be used
237
* to generate an entire entry, and perhaps this could be done
238
* with a macro. (This would reduce clarity, however, and is
239
* probably a bad thing.)
241
* - these types all begin with a gchar* (and contain a MetaPreference)
242
* and we can factor out the repeated code in the handlers by taking
243
* advantage of this using some kind of union arrangement.
249
GConfEnumStringPair *symtab;
251
} MetaEnumPreference;
258
gboolean becomes_true_on_destruction;
259
} MetaBoolPreference;
267
* A handler. Many of the string preferences aren't stored as
268
* strings and need parsing; others of them have default values
269
* which can't be solved in the general case. If you include a
270
* function pointer here, it will be called before the string
271
* value is written out to the target variable.
273
* The function is passed two arguments: the preference, and
274
* the new string as a gchar*. It returns a gboolean;
275
* only if this is true, the listeners will be informed that
276
* the preference has changed.
278
* This may be NULL. If it is, see "target", below.
280
void (*handler) (MetaPreference pref,
281
const gchar *string_value,
282
gboolean *inform_listeners);
285
* Where to write the incoming string.
287
* This must be NULL if the handler is non-NULL.
288
* If the incoming string is NULL, no change will be made.
292
} MetaStringPreference;
294
#define METAINTPREFERENCE_NO_CHANGE_ON_DESTROY G_MININT
302
* Minimum and maximum values of the integer.
303
* If the new value is out of bounds, it will be discarded with a warning.
305
gint minimum, maximum;
307
* Value to use if the key is destroyed.
308
* If this is METAINTPREFERENCE_NO_CHANGE_ON_DESTROY, it will
309
* not be changed when the key is destroyed.
311
gint value_if_destroyed;
315
/* @@@ Don't use NULL lines at the end; glib can tell you how big it is */
316
/* @@@ /apps/metacity/general should be assumed if first char is not / */
317
/* @@@ Will it ever be possible to merge init and update? If not, why not? */
319
static MetaEnumPreference preferences_enum[] =
321
{ "/apps/metacity/general/focus_new_windows",
322
META_PREF_FOCUS_NEW_WINDOWS,
323
symtab_focus_new_windows,
326
{ "/apps/metacity/general/focus_mode",
327
META_PREF_FOCUS_MODE,
331
{ "/apps/metacity/general/visual_bell_type",
332
META_PREF_VISUAL_BELL_TYPE,
333
symtab_visual_bell_type,
336
{ "/apps/metacity/general/action_double_click_titlebar",
337
META_PREF_ACTION_DOUBLE_CLICK_TITLEBAR,
338
symtab_titlebar_action,
339
&action_double_click_titlebar,
341
{ "/apps/metacity/general/action_middle_click_titlebar",
342
META_PREF_ACTION_MIDDLE_CLICK_TITLEBAR,
343
symtab_titlebar_action,
344
&action_middle_click_titlebar,
346
{ "/apps/metacity/general/action_right_click_titlebar",
347
META_PREF_ACTION_RIGHT_CLICK_TITLEBAR,
348
symtab_titlebar_action,
349
&action_right_click_titlebar,
351
{ NULL, 0, NULL, NULL },
354
static MetaBoolPreference preferences_bool[] =
356
{ "/apps/metacity/general/raise_on_click",
357
META_PREF_RAISE_ON_CLICK,
361
{ "/apps/metacity/general/titlebar_uses_system_font",
362
META_PREF_TITLEBAR_FONT, /* note! shares a pref */
366
{ "/apps/metacity/general/application_based",
367
META_PREF_APPLICATION_BASED,
368
NULL, /* feature is known but disabled */
371
{ "/apps/metacity/general/disable_workarounds",
372
META_PREF_DISABLE_WORKAROUNDS,
373
&disable_workarounds,
376
{ "/apps/metacity/general/auto_raise",
377
META_PREF_AUTO_RAISE,
381
{ "/apps/metacity/general/visual_bell",
382
META_PREF_VISUAL_BELL,
383
&provide_visual_bell, /* FIXME: change the name: it's confusing */
386
{ "/apps/metacity/general/audible_bell",
387
META_PREF_AUDIBLE_BELL,
388
&bell_is_audible, /* FIXME: change the name: it's confusing */
391
{ "/apps/metacity/general/reduced_resources",
392
META_PREF_REDUCED_RESOURCES,
396
{ "/desktop/gnome/interface/accessibility",
397
META_PREF_GNOME_ACCESSIBILITY,
398
&gnome_accessibility,
401
{ "/desktop/gnome/interface/enable_animations",
402
META_PREF_GNOME_ANIMATIONS,
406
{ "/apps/metacity/general/compositing_manager",
407
META_PREF_COMPOSITING_MANAGER,
408
&compositing_manager,
411
{ "/apps/metacity/general/resize_with_right_button",
412
META_PREF_RESIZE_WITH_RIGHT_BUTTON,
413
&resize_with_right_button,
416
{ NULL, 0, NULL, FALSE },
419
static MetaStringPreference preferences_string[] =
421
{ "/apps/metacity/general/mouse_button_modifier",
422
META_PREF_MOUSE_BUTTON_MODS,
423
mouse_button_mods_handler,
426
{ "/apps/metacity/general/theme",
432
META_PREF_TITLEBAR_FONT,
436
{ KEY_TERMINAL_COMMAND,
437
META_PREF_TERMINAL_COMMAND,
441
{ "/apps/metacity/general/button_layout",
442
META_PREF_BUTTON_LAYOUT,
443
button_layout_handler,
446
{ "/desktop/gnome/peripherals/mouse/cursor_theme",
447
META_PREF_CURSOR_THEME,
451
{ NULL, 0, NULL, NULL },
454
static MetaIntPreference preferences_int[] =
456
{ "/apps/metacity/general/num_workspaces",
457
META_PREF_NUM_WORKSPACES,
459
/* I would actually recommend we change the destroy value to 4
460
* and get rid of METAINTPREFERENCE_NO_CHANGE_ON_DESTROY entirely.
463
1, MAX_REASONABLE_WORKSPACES, METAINTPREFERENCE_NO_CHANGE_ON_DESTROY,
465
{ "/apps/metacity/general/auto_raise_delay",
466
META_PREF_AUTO_RAISE_DELAY,
469
/* @@@ Get rid of MAX_REASONABLE_AUTO_RAISE_DELAY */
471
{ "/desktop/gnome/peripherals/mouse/cursor_size",
472
META_PREF_CURSOR_SIZE,
476
{ NULL, 0, NULL, 0, 0, 0, },
480
handle_preference_init_enum (void)
482
MetaEnumPreference *cursor = preferences_enum;
484
while (cursor->key!=NULL)
487
GError *error = NULL;
489
if (cursor->target==NULL)
495
value = gconf_client_get_string (default_client,
498
cleanup_error (&error);
506
if (!gconf_string_to_enum (cursor->symtab,
508
(gint *) cursor->target))
509
meta_warning (_("GConf key '%s' is set to an invalid value\n"),
519
handle_preference_init_bool (void)
521
MetaBoolPreference *cursor = preferences_bool;
523
while (cursor->key!=NULL)
525
if (cursor->target!=NULL)
526
get_bool (cursor->key, cursor->target);
531
maybe_give_disable_workarounds_warning ();
535
handle_preference_init_string (void)
537
MetaStringPreference *cursor = preferences_string;
539
while (cursor->key!=NULL)
542
GError *error = NULL;
543
gboolean dummy = TRUE;
545
/* the string "value" will be newly allocated */
546
value = gconf_client_get_string (default_client,
549
cleanup_error (&error);
554
meta_bug ("%s has both a target and a handler\n", cursor->key);
556
cursor->handler (cursor->pref, value, &dummy);
560
else if (cursor->target)
562
if (*(cursor->target))
563
g_free (*(cursor->target));
565
*(cursor->target) = value;
573
handle_preference_init_int (void)
575
MetaIntPreference *cursor = preferences_int;
578
while (cursor->key!=NULL)
581
GError *error = NULL;
583
value = gconf_client_get_int (default_client,
586
cleanup_error (&error);
588
if (value < cursor->minimum || value > cursor->maximum)
590
meta_warning (_("%d stored in GConf key %s is out of range %d to %d\n"),
591
value, cursor->key, cursor->minimum, cursor->maximum);
592
/* Former behaviour for out-of-range values was:
593
* - number of workspaces was clamped;
594
* - auto raise delay was always reset to zero even if too high!;
595
* - cursor size was ignored.
597
* These seem to be meaningless variations. If they did
598
* have meaning we could have put them into MetaIntPreference.
599
* The last of these is the closest to how we behave for
600
* other types, so I think we should standardise on that.
603
else if (cursor->target)
604
*cursor->target = value;
611
handle_preference_update_enum (const gchar *key, GConfValue *value)
613
MetaEnumPreference *cursor = preferences_enum;
616
while (cursor->key!=NULL && strcmp (key, cursor->key)!=0)
619
if (cursor->key==NULL)
620
/* Didn't recognise that key. */
623
/* Setting it to null (that is, removing it) always means
630
/* Check the type. Enums are always strings. */
632
if (value->type != GCONF_VALUE_STRING)
634
meta_warning (_("GConf key \"%s\" is set to an invalid type\n"),
636
/* But we did recognise it. */
640
/* We need to know whether the value changes, so
641
* store the current value away.
644
old_value = * ((gint *) cursor->target);
646
/* Now look it up... */
648
if (!gconf_string_to_enum (cursor->symtab,
649
gconf_value_get_string (value),
650
(gint *) cursor->target))
653
* We found it, but it was invalid. Complain.
655
* FIXME: This replicates the original behaviour, but in the future
656
* we might consider reverting invalid keys to their original values.
657
* (We know the old value, so we can look up a suitable string in
660
* (Empty comment follows so the translators don't see this.)
664
meta_warning (_("GConf key '%s' is set to an invalid value\n"),
669
/* Did it change? If so, tell the listeners about it. */
671
if (old_value != *((gint *) cursor->target))
672
queue_changed (cursor->pref);
678
handle_preference_update_bool (const gchar *key, GConfValue *value)
680
MetaBoolPreference *cursor = preferences_bool;
683
while (cursor->key!=NULL && strcmp (key, cursor->key)!=0)
686
if (cursor->key==NULL)
687
/* Didn't recognise that key. */
690
if (cursor->target==NULL)
691
/* No work for us to do. */
696
/* Value was destroyed; let's get out of here. */
698
if (cursor->becomes_true_on_destruction)
699
/* This preserves the behaviour of the old system, but
700
* for all I know that might have been an oversight.
702
*((gboolean *)cursor->target) = TRUE;
707
/* Check the type. */
709
if (value->type != GCONF_VALUE_BOOL)
711
meta_warning (_("GConf key \"%s\" is set to an invalid type\n"),
713
/* But we did recognise it. */
717
/* We need to know whether the value changes, so
718
* store the current value away.
721
old_value = * ((gboolean *) cursor->target);
723
/* Now look it up... */
725
*((gboolean *) cursor->target) = gconf_value_get_bool (value);
727
/* Did it change? If so, tell the listeners about it. */
729
if (old_value != *((gboolean *) cursor->target))
730
queue_changed (cursor->pref);
732
if (cursor->pref==META_PREF_DISABLE_WORKAROUNDS)
733
maybe_give_disable_workarounds_warning ();
739
handle_preference_update_string (const gchar *key, GConfValue *value)
741
MetaStringPreference *cursor = preferences_string;
742
const gchar *value_as_string;
743
gboolean inform_listeners = TRUE;
745
while (cursor->key!=NULL && strcmp (key, cursor->key)!=0)
748
if (cursor->key==NULL)
749
/* Didn't recognise that key. */
755
/* Check the type. */
757
if (value->type != GCONF_VALUE_STRING)
759
meta_warning (_("GConf key \"%s\" is set to an invalid type\n"),
761
/* But we did recognise it. */
765
/* Docs: "The returned string is not a copy, don't try to free it." */
766
value_as_string = gconf_value_get_string (value);
769
cursor->handler (cursor->pref, value_as_string, &inform_listeners);
770
else if (cursor->target)
772
if (*(cursor->target))
773
g_free(*(cursor->target));
775
if (value_as_string!=NULL)
776
*(cursor->target) = g_strdup (value_as_string);
778
*(cursor->target) = NULL;
781
(value_as_string==NULL && *(cursor->target)==NULL) ||
782
(value_as_string!=NULL && *(cursor->target)!=NULL &&
783
strcmp (value_as_string, *(cursor->target))==0);
786
if (inform_listeners)
787
queue_changed (cursor->pref);
793
handle_preference_update_int (const gchar *key, GConfValue *value)
795
MetaIntPreference *cursor = preferences_int;
798
while (cursor->key!=NULL && strcmp (key, cursor->key)!=0)
801
if (cursor->key==NULL)
802
/* Didn't recognise that key. */
805
if (cursor->target==NULL)
806
/* No work for us to do. */
811
/* Value was destroyed. */
813
if (cursor->value_if_destroyed != METAINTPREFERENCE_NO_CHANGE_ON_DESTROY)
814
*((gint *)cursor->target) = cursor->value_if_destroyed;
819
/* Check the type. */
821
if (value->type != GCONF_VALUE_INT)
823
meta_warning (_("GConf key \"%s\" is set to an invalid type\n"),
825
/* But we did recognise it. */
829
new_value = gconf_value_get_int (value);
831
if (new_value < cursor->minimum || new_value > cursor->maximum)
833
meta_warning (_("%d stored in GConf key %s is out of range %d to %d\n"),
834
new_value, cursor->key,
835
cursor->minimum, cursor->maximum);
839
/* Did it change? If so, tell the listeners about it. */
841
if (*cursor->target != new_value)
843
*cursor->target = new_value;
844
queue_changed (cursor->pref);
852
/****************************************************************************/
854
/****************************************************************************/
857
meta_prefs_add_listener (MetaPrefsChangedFunc func,
860
MetaPrefsListener *l;
862
l = g_new (MetaPrefsListener, 1);
866
listeners = g_list_prepend (listeners, l);
870
meta_prefs_remove_listener (MetaPrefsChangedFunc func,
878
MetaPrefsListener *l = tmp->data;
880
if (l->func == func &&
884
listeners = g_list_delete_link (listeners, tmp);
892
meta_bug ("Did not find listener to remove\n");
896
emit_changed (MetaPreference pref)
901
meta_topic (META_DEBUG_PREFS, "Notifying listeners that pref %s changed\n",
902
meta_preference_to_string (pref));
904
copy = g_list_copy (listeners);
910
MetaPrefsListener *l = tmp->data;
912
(* l->func) (pref, l->data);
921
changed_idle_handler (gpointer data)
928
copy = g_list_copy (changes); /* reentrancy paranoia */
930
g_list_free (changes);
936
MetaPreference pref = GPOINTER_TO_INT (tmp->data);
949
queue_changed (MetaPreference pref)
951
meta_topic (META_DEBUG_PREFS, "Queueing change of pref %s\n",
952
meta_preference_to_string (pref));
954
if (g_list_find (changes, GINT_TO_POINTER (pref)) == NULL)
955
changes = g_list_prepend (changes, GINT_TO_POINTER (pref));
957
meta_topic (META_DEBUG_PREFS, "Change of pref %s was already pending\n",
958
meta_preference_to_string (pref));
960
/* add idle at priority below the gconf notify idle */
961
if (changed_idle == 0)
962
changed_idle = g_idle_add_full (META_PRIORITY_PREFS_NOTIFY,
963
changed_idle_handler, NULL, NULL);
966
#else /* HAVE_GCONF */
969
meta_prefs_add_listener (MetaPrefsChangedFunc func,
972
/* Nothing, because they have gconf turned off */
976
meta_prefs_remove_listener (MetaPrefsChangedFunc func,
979
/* Nothing, because they have gconf turned off */
982
#endif /* HAVE_GCONF */
985
/****************************************************************************/
986
/* Initialisation. */
987
/****************************************************************************/
990
/* @@@ again, use glib's ability to tell you the size of the array */
991
static gchar *gconf_dirs_we_are_interested_in[] = {
994
KEY_GNOME_ACCESSIBILITY,
995
"/desktop/gnome/peripherals/mouse",
996
"/desktop/gnome/interface",
1002
meta_prefs_init (void)
1006
gchar **gconf_dir_cursor;
1008
if (default_client != NULL)
1011
/* returns a reference which we hold forever */
1012
default_client = gconf_client_get_default ();
1014
for (gconf_dir_cursor=gconf_dirs_we_are_interested_in;
1015
*gconf_dir_cursor!=NULL;
1018
gconf_client_add_dir (default_client,
1020
GCONF_CLIENT_PRELOAD_RECURSIVE,
1022
cleanup_error (&err);
1025
/* Pick up initial values. */
1027
handle_preference_init_enum ();
1028
handle_preference_init_bool ();
1029
handle_preference_init_string ();
1030
handle_preference_init_int ();
1032
/* @@@ Is there any reason we don't do the add_dir here? */
1033
for (gconf_dir_cursor=gconf_dirs_we_are_interested_in;
1034
*gconf_dir_cursor!=NULL;
1037
gconf_client_notify_add (default_client,
1043
cleanup_error (&err);
1046
#else /* HAVE_GCONF */
1048
/* Set defaults for some values that can't be set at initialization time of
1049
* the static globals. In the case of the theme, note that there is code
1050
* elsewhere that will do everything possible to fallback to an existing theme
1051
* if the one here does not exist.
1053
titlebar_font = pango_font_description_from_string ("Sans Bold 10");
1054
current_theme = g_strdup ("Atlanta");
1056
init_button_layout();
1057
#endif /* HAVE_GCONF */
1061
init_workspace_names ();
1065
/****************************************************************************/
1067
/****************************************************************************/
1071
gboolean (*preference_update_handler[]) (const gchar*, GConfValue*) = {
1072
handle_preference_update_enum,
1073
handle_preference_update_bool,
1074
handle_preference_update_string,
1075
handle_preference_update_int,
1080
change_notify (GConfClient *client,
1089
key = gconf_entry_get_key (entry);
1090
value = gconf_entry_get_value (entry);
1092
/* First, search for a handler that might know what to do. */
1094
/* FIXME: When this is all working, since the first item in every
1095
* array is the gchar* of the key, there's no reason we can't
1096
* find the correct record for that key here and save code duplication.
1099
while (preference_update_handler[i]!=NULL)
1101
if (preference_update_handler[i] (key, value))
1102
goto out; /* Get rid of this eventually */
1107
if (g_str_has_prefix (key, KEY_WINDOW_BINDINGS_PREFIX) ||
1108
g_str_has_prefix (key, KEY_SCREEN_BINDINGS_PREFIX))
1110
if (g_str_has_suffix (key, KEY_LIST_BINDINGS_SUFFIX))
1114
if (value && value->type != GCONF_VALUE_LIST)
1116
meta_warning (_("GConf key \"%s\" is set to an invalid type\n"),
1121
list = value ? gconf_value_get_list (value) : NULL;
1123
if (update_key_list_binding (key, list))
1124
queue_changed (META_PREF_KEYBINDINGS);
1130
if (value && value->type != GCONF_VALUE_STRING)
1132
meta_warning (_("GConf key \"%s\" is set to an invalid type\n"),
1137
str = value ? gconf_value_get_string (value) : NULL;
1139
if (update_key_binding (key, str))
1140
queue_changed (META_PREF_KEYBINDINGS);
1143
else if (g_str_has_prefix (key, KEY_COMMAND_PREFIX))
1147
if (value && value->type != GCONF_VALUE_STRING)
1149
meta_warning (_("GConf key \"%s\" is set to an invalid type\n"),
1154
str = value ? gconf_value_get_string (value) : NULL;
1156
if (update_command (key, str))
1157
queue_changed (META_PREF_COMMANDS);
1159
else if (g_str_has_prefix (key, KEY_WORKSPACE_NAME_PREFIX))
1163
if (value && value->type != GCONF_VALUE_STRING)
1165
meta_warning (_("GConf key \"%s\" is set to an invalid type\n"),
1170
str = value ? gconf_value_get_string (value) : NULL;
1172
if (update_workspace_name (key, str))
1173
queue_changed (META_PREF_WORKSPACE_NAMES);
1177
meta_topic (META_DEBUG_PREFS, "Key %s doesn't mean anything to Metacity\n",
1183
return; /* AIX compiler wants something after a label like out: */
1187
cleanup_error (GError **error)
1191
meta_warning ("%s\n", (*error)->message);
1193
g_error_free (*error);
1198
/* get_bool returns TRUE if *val is filled in, FALSE otherwise */
1199
/* @@@ probably worth moving this inline; only used once */
1201
get_bool (const char *key, gboolean *val)
1205
gboolean filled_in = FALSE;
1207
value = gconf_client_get (default_client, key, &err);
1208
cleanup_error (&err);
1211
if (value->type == GCONF_VALUE_BOOL)
1213
*val = gconf_value_get_bool (value);
1216
gconf_value_free (value);
1223
* Special case: give a warning the first time disable_workarounds
1227
maybe_give_disable_workarounds_warning (void)
1229
static gboolean first_disable = TRUE;
1231
if (first_disable && disable_workarounds)
1233
first_disable = FALSE;
1235
meta_warning (_("Workarounds for broken applications disabled. "
1236
"Some applications may not behave properly.\n"));
1240
#endif /* HAVE_GCONF */
1243
meta_prefs_get_mouse_button_mods (void)
1245
return mouse_button_mods;
1249
meta_prefs_get_focus_mode (void)
1255
meta_prefs_get_focus_new_windows (void)
1257
return focus_new_windows;
1261
meta_prefs_get_raise_on_click (void)
1263
return raise_on_click;
1267
meta_prefs_get_theme (void)
1269
return current_theme;
1273
meta_prefs_get_cursor_theme (void)
1275
return cursor_theme;
1279
meta_prefs_get_cursor_size (void)
1285
/****************************************************************************/
1286
/* Handlers for string preferences. */
1287
/****************************************************************************/
1292
titlebar_handler (MetaPreference pref,
1293
const gchar *string_value,
1294
gboolean *inform_listeners)
1296
PangoFontDescription *new_desc = NULL;
1299
new_desc = pango_font_description_from_string (string_value);
1301
if (new_desc == NULL)
1303
meta_warning (_("Could not parse font description "
1304
"\"%s\" from GConf key %s\n"),
1305
string_value ? string_value : "(null)",
1308
*inform_listeners = FALSE;
1313
/* Is the new description the same as the old? */
1315
if (titlebar_font &&
1316
pango_font_description_equal (new_desc, titlebar_font))
1318
pango_font_description_free (new_desc);
1319
*inform_listeners = FALSE;
1323
/* No, so free the old one and put ours in instead. */
1326
pango_font_description_free (titlebar_font);
1328
titlebar_font = new_desc;
1333
theme_name_handler (MetaPreference pref,
1334
const gchar *string_value,
1335
gboolean *inform_listeners)
1337
g_free (current_theme);
1339
/* Fallback crackrock */
1340
if (string_value == NULL)
1341
current_theme = g_strdup ("Atlanta");
1343
current_theme = g_strdup (string_value);
1347
mouse_button_mods_handler (MetaPreference pref,
1348
const gchar *string_value,
1349
gboolean *inform_listeners)
1351
MetaVirtualModifier mods;
1353
meta_topic (META_DEBUG_KEYBINDINGS,
1354
"Mouse button modifier has new gconf value \"%s\"\n",
1356
if (string_value && meta_ui_parse_modifier (string_value, &mods))
1358
mouse_button_mods = mods;
1362
meta_topic (META_DEBUG_KEYBINDINGS,
1363
"Failed to parse new gconf value\n");
1365
meta_warning (_("\"%s\" found in configuration database is "
1366
"not a valid value for mouse button modifier\n"),
1369
*inform_listeners = FALSE;
1374
button_layout_equal (const MetaButtonLayout *a,
1375
const MetaButtonLayout *b)
1380
while (i < MAX_BUTTONS_PER_CORNER)
1382
if (a->left_buttons[i] != b->left_buttons[i])
1384
if (a->right_buttons[i] != b->right_buttons[i])
1386
if (a->left_buttons_has_spacer[i] != b->left_buttons_has_spacer[i])
1388
if (a->right_buttons_has_spacer[i] != b->right_buttons_has_spacer[i])
1396
static MetaButtonFunction
1397
button_function_from_string (const char *str)
1399
/* FIXME: gconf_string_to_enum is the obvious way to do this */
1401
if (strcmp (str, "menu") == 0)
1402
return META_BUTTON_FUNCTION_MENU;
1403
else if (strcmp (str, "minimize") == 0)
1404
return META_BUTTON_FUNCTION_MINIMIZE;
1405
else if (strcmp (str, "maximize") == 0)
1406
return META_BUTTON_FUNCTION_MAXIMIZE;
1407
else if (strcmp (str, "close") == 0)
1408
return META_BUTTON_FUNCTION_CLOSE;
1409
else if (strcmp (str, "shade") == 0)
1410
return META_BUTTON_FUNCTION_SHADE;
1411
else if (strcmp (str, "above") == 0)
1412
return META_BUTTON_FUNCTION_ABOVE;
1413
else if (strcmp (str, "stick") == 0)
1414
return META_BUTTON_FUNCTION_STICK;
1416
/* don't know; give up */
1417
return META_BUTTON_FUNCTION_LAST;
1420
static MetaButtonFunction
1421
button_opposite_function (MetaButtonFunction ofwhat)
1425
case META_BUTTON_FUNCTION_SHADE:
1426
return META_BUTTON_FUNCTION_UNSHADE;
1427
case META_BUTTON_FUNCTION_UNSHADE:
1428
return META_BUTTON_FUNCTION_SHADE;
1430
case META_BUTTON_FUNCTION_ABOVE:
1431
return META_BUTTON_FUNCTION_UNABOVE;
1432
case META_BUTTON_FUNCTION_UNABOVE:
1433
return META_BUTTON_FUNCTION_ABOVE;
1435
case META_BUTTON_FUNCTION_STICK:
1436
return META_BUTTON_FUNCTION_UNSTICK;
1437
case META_BUTTON_FUNCTION_UNSTICK:
1438
return META_BUTTON_FUNCTION_STICK;
1441
return META_BUTTON_FUNCTION_LAST;
1446
button_layout_handler (MetaPreference pref,
1447
const gchar *string_value,
1448
gboolean *inform_listeners)
1450
MetaButtonLayout new_layout;
1451
char **sides = NULL;
1454
/* We need to ignore unknown button functions, for
1455
* compat with future versions
1459
sides = g_strsplit (string_value, ":", 2);
1461
if (sides != NULL && sides[0] != NULL)
1465
gboolean used[META_BUTTON_FUNCTION_LAST];
1468
while (i < META_BUTTON_FUNCTION_LAST)
1471
new_layout.left_buttons_has_spacer[i] = FALSE;
1475
buttons = g_strsplit (sides[0], ",", -1);
1478
while (buttons[b] != NULL)
1480
MetaButtonFunction f = button_function_from_string (buttons[b]);
1481
if (i > 0 && strcmp("spacer", buttons[b]) == 0)
1483
new_layout.left_buttons_has_spacer[i-1] = TRUE;
1484
f = button_opposite_function (f);
1486
if (f != META_BUTTON_FUNCTION_LAST)
1488
new_layout.left_buttons_has_spacer[i-2] = TRUE;
1493
if (f != META_BUTTON_FUNCTION_LAST && !used[f])
1495
new_layout.left_buttons[i] = f;
1499
f = button_opposite_function (f);
1501
if (f != META_BUTTON_FUNCTION_LAST)
1502
new_layout.left_buttons[i++] = f;
1507
meta_topic (META_DEBUG_PREFS, "Ignoring unknown or already-used button name \"%s\"\n",
1515
new_layout.left_buttons[i] = META_BUTTON_FUNCTION_LAST;
1516
new_layout.left_buttons_has_spacer[i] = FALSE;
1518
g_strfreev (buttons);
1521
if (sides != NULL && sides[0] != NULL && sides[1] != NULL)
1525
gboolean used[META_BUTTON_FUNCTION_LAST];
1528
while (i < META_BUTTON_FUNCTION_LAST)
1531
new_layout.right_buttons_has_spacer[i] = FALSE;
1535
buttons = g_strsplit (sides[1], ",", -1);
1538
while (buttons[b] != NULL)
1540
MetaButtonFunction f = button_function_from_string (buttons[b]);
1541
if (i > 0 && strcmp("spacer", buttons[b]) == 0)
1543
new_layout.right_buttons_has_spacer[i-1] = TRUE;
1544
f = button_opposite_function (f);
1545
if (f != META_BUTTON_FUNCTION_LAST)
1547
new_layout.right_buttons_has_spacer[i-2] = TRUE;
1552
if (f != META_BUTTON_FUNCTION_LAST && !used[f])
1554
new_layout.right_buttons[i] = f;
1558
f = button_opposite_function (f);
1560
if (f != META_BUTTON_FUNCTION_LAST)
1561
new_layout.right_buttons[i++] = f;
1566
meta_topic (META_DEBUG_PREFS, "Ignoring unknown or already-used button name \"%s\"\n",
1574
new_layout.right_buttons[i] = META_BUTTON_FUNCTION_LAST;
1575
new_layout.right_buttons_has_spacer[i] = FALSE;
1577
g_strfreev (buttons);
1582
/* Invert the button layout for RTL languages */
1583
if (meta_ui_get_direction() == META_UI_DIRECTION_RTL)
1585
MetaButtonLayout rtl_layout;
1588
for (i = 0; new_layout.left_buttons[i] != META_BUTTON_FUNCTION_LAST; i++);
1589
for (j = 0; j < i; j++)
1591
rtl_layout.right_buttons[j] = new_layout.left_buttons[i - j - 1];
1593
rtl_layout.right_buttons_has_spacer[i - 1] = new_layout.left_buttons_has_spacer[i - j - 1];
1595
rtl_layout.right_buttons_has_spacer[j - 1] = new_layout.left_buttons_has_spacer[i - j - 1];
1597
rtl_layout.right_buttons[j] = META_BUTTON_FUNCTION_LAST;
1598
rtl_layout.right_buttons_has_spacer[j] = FALSE;
1600
for (i = 0; new_layout.right_buttons[i] != META_BUTTON_FUNCTION_LAST; i++);
1601
for (j = 0; j < i; j++)
1603
rtl_layout.left_buttons[j] = new_layout.right_buttons[i - j - 1];
1605
rtl_layout.left_buttons_has_spacer[i - 1] = new_layout.right_buttons_has_spacer[i - j - 1];
1607
rtl_layout.left_buttons_has_spacer[j - 1] = new_layout.right_buttons_has_spacer[i - j - 1];
1609
rtl_layout.left_buttons[j] = META_BUTTON_FUNCTION_LAST;
1610
rtl_layout.left_buttons_has_spacer[j] = FALSE;
1612
new_layout = rtl_layout;
1615
if (button_layout_equal (&button_layout, &new_layout))
1617
/* Same as before, so duck out */
1618
*inform_listeners = FALSE;
1622
button_layout = new_layout;
1626
#endif /* HAVE_GCONF */
1628
const PangoFontDescription*
1629
meta_prefs_get_titlebar_font (void)
1631
if (use_system_font)
1634
return titlebar_font;
1638
meta_prefs_get_num_workspaces (void)
1640
return num_workspaces;
1644
meta_prefs_get_application_based (void)
1646
return FALSE; /* For now, we never want this to do anything */
1648
return application_based;
1652
meta_prefs_get_disable_workarounds (void)
1654
return disable_workarounds;
1658
#define MAX_REASONABLE_AUTO_RAISE_DELAY 10000
1660
#endif /* HAVE_GCONF */
1662
#ifdef WITH_VERBOSE_MODE
1664
meta_preference_to_string (MetaPreference pref)
1666
/* FIXME: another case for gconf_string_to_enum */
1669
case META_PREF_MOUSE_BUTTON_MODS:
1670
return "MOUSE_BUTTON_MODS";
1672
case META_PREF_FOCUS_MODE:
1673
return "FOCUS_MODE";
1675
case META_PREF_FOCUS_NEW_WINDOWS:
1676
return "FOCUS_NEW_WINDOWS";
1678
case META_PREF_RAISE_ON_CLICK:
1679
return "RAISE_ON_CLICK";
1681
case META_PREF_THEME:
1684
case META_PREF_TITLEBAR_FONT:
1685
return "TITLEBAR_FONT";
1687
case META_PREF_NUM_WORKSPACES:
1688
return "NUM_WORKSPACES";
1690
case META_PREF_APPLICATION_BASED:
1691
return "APPLICATION_BASED";
1693
case META_PREF_KEYBINDINGS:
1694
return "KEYBINDINGS";
1696
case META_PREF_DISABLE_WORKAROUNDS:
1697
return "DISABLE_WORKAROUNDS";
1699
case META_PREF_ACTION_DOUBLE_CLICK_TITLEBAR:
1700
return "ACTION_DOUBLE_CLICK_TITLEBAR";
1702
case META_PREF_ACTION_MIDDLE_CLICK_TITLEBAR:
1703
return "ACTION_MIDDLE_CLICK_TITLEBAR";
1705
case META_PREF_ACTION_RIGHT_CLICK_TITLEBAR:
1706
return "ACTION_RIGHT_CLICK_TITLEBAR";
1708
case META_PREF_AUTO_RAISE:
1709
return "AUTO_RAISE";
1711
case META_PREF_AUTO_RAISE_DELAY:
1712
return "AUTO_RAISE_DELAY";
1714
case META_PREF_COMMANDS:
1717
case META_PREF_TERMINAL_COMMAND:
1718
return "TERMINAL_COMMAND";
1720
case META_PREF_BUTTON_LAYOUT:
1721
return "BUTTON_LAYOUT";
1723
case META_PREF_WORKSPACE_NAMES:
1724
return "WORKSPACE_NAMES";
1726
case META_PREF_VISUAL_BELL:
1727
return "VISUAL_BELL";
1729
case META_PREF_AUDIBLE_BELL:
1730
return "AUDIBLE_BELL";
1732
case META_PREF_VISUAL_BELL_TYPE:
1733
return "VISUAL_BELL_TYPE";
1735
case META_PREF_REDUCED_RESOURCES:
1736
return "REDUCED_RESOURCES";
1738
case META_PREF_GNOME_ACCESSIBILITY:
1739
return "GNOME_ACCESSIBILTY";
1741
case META_PREF_GNOME_ANIMATIONS:
1742
return "GNOME_ANIMATIONS";
1744
case META_PREF_CURSOR_THEME:
1745
return "CURSOR_THEME";
1747
case META_PREF_CURSOR_SIZE:
1748
return "CURSOR_SIZE";
1750
case META_PREF_COMPOSITING_MANAGER:
1751
return "COMPOSITING_MANAGER";
1753
case META_PREF_RESIZE_WITH_RIGHT_BUTTON:
1754
return "RESIZE_WITH_RIGHT_BUTTON";
1756
case META_PREF_FORCE_FULLSCREEN:
1757
return "FORCE_FULLSCREEN";
1762
#endif /* WITH_VERBOSE_MODE */
1765
meta_prefs_set_num_workspaces (int n_workspaces)
1770
if (default_client == NULL)
1773
if (n_workspaces < 1)
1775
if (n_workspaces > MAX_REASONABLE_WORKSPACES)
1776
n_workspaces = MAX_REASONABLE_WORKSPACES;
1779
gconf_client_set_int (default_client,
1786
meta_warning (_("Error setting number of workspaces to %d: %s\n"),
1791
#endif /* HAVE_GCONF */
1794
#define keybind(name, handler, param, flags, stroke, description) \
1795
{ #name, NULL, !!(flags & BINDING_REVERSES), !!(flags & BINDING_PER_WINDOW) },
1796
static MetaKeyPref key_bindings[] = {
1797
#include "all-keybindings.h"
1798
{ NULL, NULL, FALSE }
1805
* A type to map names of keybindings (such as "switch_windows")
1806
* to the binding strings themselves (such as "<Alt>Tab").
1807
* It exists only when GConf is turned off in ./configure and
1808
* functions as a sort of ersatz GConf.
1813
const char *keybinding;
1814
} MetaSimpleKeyMapping;
1816
/* FIXME: This would be neater if the array only contained entries whose
1817
* default keystroke was non-null. You COULD do this by defining
1818
* ONLY_BOUND_BY_DEFAULT around various blocks at the cost of making
1819
* the bindings file way more complicated. However, we could stop this being
1820
* data and move it into code. Then the compiler would optimise away
1821
* the problem lines.
1824
#define keybind(name, handler, param, flags, stroke, description) \
1827
static MetaSimpleKeyMapping key_string_bindings[] = {
1828
#include "all-keybindings.h"
1833
#endif /* NOT HAVE_GCONF */
1836
init_bindings (void)
1839
const char *prefix[] = {
1840
KEY_WINDOW_BINDINGS_PREFIX,
1841
KEY_SCREEN_BINDINGS_PREFIX,
1845
GSList *list, *l, *list_val;
1846
const char *str_val;
1851
for (i = 0; prefix[i]; i++)
1853
list = gconf_client_all_entries (default_client, prefix[i], NULL);
1854
for (l = list; l; l = l->next)
1857
key = gconf_entry_get_key (entry);
1858
value = gconf_entry_get_value (entry);
1859
if (g_str_has_suffix (key, KEY_LIST_BINDINGS_SUFFIX))
1861
list_val = gconf_client_get_list (default_client, key, GCONF_VALUE_STRING, NULL);
1863
update_key_list_binding (key, list_val);
1864
g_slist_foreach (list_val, (GFunc)g_free, NULL);
1865
g_slist_free (list_val);
1869
str_val = gconf_value_get_string (value);
1870
update_key_binding (key, str_val);
1872
gconf_entry_free (entry);
1874
g_slist_free (list);
1876
#else /* HAVE_GCONF */
1879
while (key_string_bindings[i].name)
1881
if (key_string_bindings[i].keybinding == NULL) {
1886
while (strcmp(key_bindings[which].name,
1887
key_string_bindings[i].name) != 0)
1890
/* Set the binding */
1891
update_binding (&key_bindings[which],
1892
key_string_bindings[i].keybinding);
1896
#endif /* HAVE_GCONF */
1900
init_commands (void)
1904
const char *str_val;
1909
list = gconf_client_all_entries (default_client, KEY_COMMAND_DIRECTORY, NULL);
1910
for (l = list; l; l = l->next)
1913
key = gconf_entry_get_key (entry);
1914
value = gconf_entry_get_value (entry);
1915
str_val = gconf_value_get_string (value);
1916
update_command (key, str_val);
1917
gconf_entry_free (entry);
1919
g_slist_free (list);
1922
for (i = 0; i < MAX_COMMANDS; i++)
1924
#endif /* HAVE_GCONF */
1928
init_workspace_names (void)
1931
for (i = 0; i < MAX_REASONABLE_WORKSPACES; i++)
1932
workspace_names[i] = NULL;
1936
const char *str_val;
1941
list = gconf_client_all_entries (default_client, KEY_WORKSPACE_NAME_DIRECTORY, NULL);
1942
for (l = list; l; l = l->next)
1945
key = gconf_entry_get_key (entry);
1946
value = gconf_entry_get_value (entry);
1947
str_val = gconf_value_get_string (value);
1948
update_workspace_name (key, str_val);
1949
gconf_entry_free (entry);
1951
g_slist_free (list);
1952
#endif /* HAVE_GCONF */
1954
/* initialise any we didn't see */
1955
for (i = 0; i < MAX_REASONABLE_WORKSPACES; i++)
1956
if (workspace_names[i]==NULL)
1957
workspace_names[i] = g_strdup_printf (_("Workspace %d"), i + 1);
1959
meta_topic (META_DEBUG_PREFS,
1960
"Initialized workspace names\n");
1964
update_binding (MetaKeyPref *binding,
1967
unsigned int keysym;
1968
unsigned int keycode;
1969
MetaVirtualModifier mods;
1970
MetaKeyCombo *combo;
1973
meta_topic (META_DEBUG_KEYBINDINGS,
1974
"Binding \"%s\" has new gconf value \"%s\"\n",
1975
binding->name, value ? value : "none");
1982
if (!meta_ui_parse_accelerator (value, &keysym, &keycode, &mods))
1984
meta_topic (META_DEBUG_KEYBINDINGS,
1985
"Failed to parse new gconf value\n");
1986
meta_warning (_("\"%s\" found in configuration database is not a valid value for keybinding \"%s\"\n"),
1987
value, binding->name);
1993
/* If there isn't already a first element, make one. */
1994
if (!binding->bindings)
1996
MetaKeyCombo *blank = g_malloc0 (sizeof (MetaKeyCombo));
1997
binding->bindings = g_slist_alloc();
1998
binding->bindings->data = blank;
2001
combo = binding->bindings->data;
2004
/* Bug 329676: Bindings which can be shifted must not have no modifiers,
2005
* nor only SHIFT as a modifier.
2008
if (binding->add_shift &&
2010
(META_VIRTUAL_SHIFT_MASK == mods || 0 == mods))
2016
meta_warning ("Cannot bind \"%s\" to %s: it needs a modifier "
2017
"such as Ctrl or Alt.\n",
2021
old_setting = meta_ui_accelerator_name (combo->keysym,
2024
if (!strcmp(old_setting, value))
2026
/* We were about to set it to the same value
2027
* that it had originally! This must be caused
2028
* by getting an invalid string back from
2029
* meta_ui_accelerator_name. Bail out now
2030
* so we don't get into an infinite loop.
2032
g_free (old_setting);
2036
meta_warning ("Reverting \"%s\" to %s.\n",
2040
/* FIXME: add_shift is currently screen_bindings only, but
2041
* there's no really good reason it should always be.
2042
* So we shouldn't blindly add KEY_SCREEN_BINDINGS_PREFIX
2045
key = g_strconcat (KEY_SCREEN_BINDINGS_PREFIX, "/",
2046
binding->name, NULL);
2048
gconf_client_set_string (gconf_client_get_default (),
2049
key, old_setting, &err);
2053
meta_warning ("Error while reverting keybinding: %s\n",
2059
g_free (old_setting);
2062
/* The call to gconf_client_set_string() will cause this function
2063
* to be called again with the new value, so there's no need to
2071
if (keysym != combo->keysym ||
2072
keycode != combo->keycode ||
2073
mods != combo->modifiers)
2077
combo->keysym = keysym;
2078
combo->keycode = keycode;
2079
combo->modifiers = mods;
2081
meta_topic (META_DEBUG_KEYBINDINGS,
2082
"New keybinding for \"%s\" is keysym = 0x%x keycode = 0x%x mods = 0x%x\n",
2083
binding->name, combo->keysym, combo->keycode,
2088
meta_topic (META_DEBUG_KEYBINDINGS,
2089
"Keybinding for \"%s\" is unchanged\n", binding->name);
2097
update_list_binding (MetaKeyPref *binding,
2099
MetaStringListType type_of_value)
2101
unsigned int keysym;
2102
unsigned int keycode;
2103
MetaVirtualModifier mods;
2104
gboolean changed = FALSE;
2105
const gchar *pref_string;
2106
GSList *pref_iterator = value, *tmp;
2107
MetaKeyCombo *combo;
2109
meta_topic (META_DEBUG_KEYBINDINGS,
2110
"Binding \"%s\" has new gconf value\n",
2113
if (binding->bindings == NULL)
2115
/* We need to insert a dummy element into the list, because the first
2116
* element is the one governed by update_binding. We only handle the
2117
* subsequent elements.
2119
MetaKeyCombo *blank = g_malloc0 (sizeof (MetaKeyCombo));
2120
binding->bindings = g_slist_alloc();
2121
binding->bindings->data = blank;
2124
/* Okay, so, we're about to provide a new list of key combos for this
2125
* action. Delete any pre-existing list.
2127
tmp = binding->bindings->next;
2133
g_slist_free (binding->bindings->next);
2134
binding->bindings->next = NULL;
2136
while (pref_iterator)
2142
if (!pref_iterator->data)
2144
pref_iterator = pref_iterator->next;
2148
switch (type_of_value)
2150
case META_LIST_OF_STRINGS:
2151
pref_string = pref_iterator->data;
2153
case META_LIST_OF_GCONFVALUE_STRINGS:
2154
pref_string = gconf_value_get_string (pref_iterator->data);
2157
g_assert_not_reached ();
2160
if (!meta_ui_parse_accelerator (pref_string, &keysym, &keycode, &mods))
2162
meta_topic (META_DEBUG_KEYBINDINGS,
2163
"Failed to parse new gconf value\n");
2164
meta_warning (_("\"%s\" found in configuration database is not a valid value for keybinding \"%s\"\n"),
2165
pref_string, binding->name);
2167
/* Should we remove this value from the list in gconf? */
2168
pref_iterator = pref_iterator->next;
2172
/* Bug 329676: Bindings which can be shifted must not have no modifiers,
2173
* nor only SHIFT as a modifier.
2176
if (binding->add_shift &&
2178
(META_VIRTUAL_SHIFT_MASK == mods || 0 == mods))
2180
meta_warning ("Cannot bind \"%s\" to %s: it needs a modifier "
2181
"such as Ctrl or Alt.\n",
2185
/* Should we remove this value from the list in gconf? */
2187
pref_iterator = pref_iterator->next;
2193
combo = g_malloc0 (sizeof (MetaKeyCombo));
2194
combo->keysym = keysym;
2195
combo->keycode = keycode;
2196
combo->modifiers = mods;
2197
binding->bindings->next = g_slist_prepend (binding->bindings->next, combo);
2199
meta_topic (META_DEBUG_KEYBINDINGS,
2200
"New keybinding for \"%s\" is keysym = 0x%x keycode = 0x%x mods = 0x%x\n",
2201
binding->name, keysym, keycode, mods);
2203
pref_iterator = pref_iterator->next;
2209
relative_key (const gchar* key)
2213
end = strrchr (key, '/');
2220
/* Return value is TRUE if a preference changed and we need to
2224
find_and_update_binding (MetaKeyPref *bindings,
2232
key = relative_key (name);
2237
while (bindings[i].name &&
2238
strcmp (key, bindings[i].name) != 0)
2241
if (bindings[i].name)
2242
return update_binding (&bindings[i], value);
2248
update_key_binding (const char *name,
2251
return find_and_update_binding (key_bindings, name, value);
2255
find_and_update_list_binding (MetaKeyPref *bindings,
2261
gchar *name_without_suffix = g_strdup(name);
2263
name_without_suffix[strlen(name_without_suffix) - strlen(KEY_LIST_BINDINGS_SUFFIX)] = 0;
2265
if (*name_without_suffix == '/')
2266
key = relative_key (name_without_suffix);
2268
key = name_without_suffix;
2271
while (bindings[i].name &&
2272
strcmp (key, bindings[i].name) != 0)
2275
g_free (name_without_suffix);
2277
if (bindings[i].name)
2278
return update_list_binding (&bindings[i], value, META_LIST_OF_GCONFVALUE_STRINGS);
2284
update_key_list_binding (const char *name,
2287
return find_and_update_list_binding (key_bindings, name, value);
2291
update_command (const char *name,
2297
p = strrchr (name, '_');
2300
meta_topic (META_DEBUG_KEYBINDINGS,
2301
"Command %s has no underscore?\n", name);
2307
if (g_ascii_isdigit (*p))
2310
i -= 1; /* count from 0 not 1 */
2314
p = strrchr (name, '/');
2317
if (strcmp (p, "command_screenshot") == 0)
2319
i = SCREENSHOT_COMMAND_IDX;
2321
else if (strcmp (p, "command_window_screenshot") == 0)
2323
i = WIN_SCREENSHOT_COMMAND_IDX;
2327
meta_topic (META_DEBUG_KEYBINDINGS,
2328
"Command %s doesn't end in number?\n", name);
2333
if (i >= MAX_COMMANDS)
2335
meta_topic (META_DEBUG_KEYBINDINGS,
2336
"Command %d is too highly numbered, ignoring\n", i);
2340
if ((commands[i] == NULL && value == NULL) ||
2341
(commands[i] && value && strcmp (commands[i], value) == 0))
2343
meta_topic (META_DEBUG_KEYBINDINGS,
2344
"Command %d is unchanged\n", i);
2348
g_free (commands[i]);
2349
commands[i] = g_strdup (value);
2351
meta_topic (META_DEBUG_KEYBINDINGS,
2352
"Updated command %d to \"%s\"\n",
2353
i, commands[i] ? commands[i] : "none");
2358
#endif /* HAVE_GCONF */
2361
meta_prefs_get_command (int i)
2363
g_return_val_if_fail (i >= 0 && i < MAX_COMMANDS, NULL);
2369
meta_prefs_get_gconf_key_for_command (int i)
2375
case SCREENSHOT_COMMAND_IDX:
2376
key = g_strdup (KEY_COMMAND_PREFIX "screenshot");
2378
case WIN_SCREENSHOT_COMMAND_IDX:
2379
key = g_strdup (KEY_COMMAND_PREFIX "window_screenshot");
2382
key = g_strdup_printf (KEY_COMMAND_PREFIX"%d", i + 1);
2390
meta_prefs_get_terminal_command (void)
2392
return terminal_command;
2396
meta_prefs_get_gconf_key_for_terminal_command (void)
2398
return KEY_TERMINAL_COMMAND;
2403
update_workspace_name (const char *name,
2409
p = strrchr (name, '_');
2412
meta_topic (META_DEBUG_PREFS,
2413
"Workspace name %s has no underscore?\n", name);
2419
if (!g_ascii_isdigit (*p))
2421
meta_topic (META_DEBUG_PREFS,
2422
"Workspace name %s doesn't end in number?\n", name);
2427
i -= 1; /* count from 0 not 1 */
2429
if (i >= MAX_REASONABLE_WORKSPACES)
2431
meta_topic (META_DEBUG_PREFS,
2432
"Workspace name %d is too highly numbered, ignoring\n", i);
2436
if (workspace_names[i] && value && strcmp (workspace_names[i], value) == 0)
2438
meta_topic (META_DEBUG_PREFS,
2439
"Workspace name %d is unchanged\n", i);
2443
/* This is a bad hack. We have to treat empty string as
2444
* "unset" because the root window property can't contain
2445
* null. So it gets empty string instead and we don't want
2446
* that to result in setting the empty string as a value that
2447
* overrides "unset".
2449
if (value != NULL && *value != '\0')
2451
g_free (workspace_names[i]);
2452
workspace_names[i] = g_strdup (value);
2456
/* use a default name */
2459
d = g_strdup_printf (_("Workspace %d"), i + 1);
2460
if (workspace_names[i] && strcmp (workspace_names[i], d) == 0)
2467
g_free (workspace_names[i]);
2468
workspace_names[i] = d;
2472
meta_topic (META_DEBUG_PREFS,
2473
"Updated workspace name %d to \"%s\"\n",
2474
i, workspace_names[i] ? workspace_names[i] : "none");
2478
#endif /* HAVE_GCONF */
2481
meta_prefs_get_workspace_name (int i)
2483
g_return_val_if_fail (i >= 0 && i < MAX_REASONABLE_WORKSPACES, NULL);
2485
g_assert (workspace_names[i] != NULL);
2487
meta_topic (META_DEBUG_PREFS,
2488
"Getting workspace name for %d: \"%s\"\n",
2489
i, workspace_names[i]);
2491
return workspace_names[i];
2495
meta_prefs_change_workspace_name (int i,
2502
g_return_if_fail (i >= 0 && i < MAX_REASONABLE_WORKSPACES);
2504
meta_topic (META_DEBUG_PREFS,
2505
"Changing name of workspace %d to %s\n",
2506
i, name ? name : "none");
2508
/* This is a bad hack. We have to treat empty string as
2509
* "unset" because the root window property can't contain
2510
* null. So it gets empty string instead and we don't want
2511
* that to result in setting the empty string as a value that
2512
* overrides "unset".
2514
if (name && *name == '\0')
2517
if ((name == NULL && workspace_names[i] == NULL) ||
2518
(name && workspace_names[i] && strcmp (name, workspace_names[i]) == 0))
2520
meta_topic (META_DEBUG_PREFS,
2521
"Workspace %d already has name %s\n",
2522
i, name ? name : "none");
2526
key = gconf_key_for_workspace_name (i);
2530
gconf_client_set_string (default_client,
2534
gconf_client_unset (default_client,
2540
meta_warning (_("Error setting name for workspace %d to \"%s\": %s\n"),
2541
i, name ? name : "none",
2548
g_free (workspace_names[i]);
2549
workspace_names[i] = g_strdup (name);
2550
#endif /* HAVE_GCONF */
2555
gconf_key_for_workspace_name (int i)
2559
key = g_strdup_printf (KEY_WORKSPACE_NAME_PREFIX"%d", i + 1);
2563
#endif /* HAVE_GCONF */
2566
meta_prefs_get_button_layout (MetaButtonLayout *button_layout_p)
2568
*button_layout_p = button_layout;
2572
meta_prefs_get_visual_bell (void)
2574
return provide_visual_bell;
2578
meta_prefs_bell_is_audible (void)
2580
return bell_is_audible;
2584
meta_prefs_get_visual_bell_type (void)
2586
return visual_bell_type;
2590
meta_prefs_get_key_bindings (const MetaKeyPref **bindings,
2594
*bindings = key_bindings;
2595
*n_bindings = (int) G_N_ELEMENTS (key_bindings) - 1;
2599
meta_prefs_get_action_double_click_titlebar (void)
2601
return action_double_click_titlebar;
2605
meta_prefs_get_action_middle_click_titlebar (void)
2607
return action_middle_click_titlebar;
2611
meta_prefs_get_action_right_click_titlebar (void)
2613
return action_right_click_titlebar;
2617
meta_prefs_get_auto_raise (void)
2623
meta_prefs_get_auto_raise_delay (void)
2625
return auto_raise_delay;
2629
meta_prefs_get_reduced_resources (void)
2631
return reduced_resources;
2635
meta_prefs_get_gnome_accessibility ()
2637
return gnome_accessibility;
2641
meta_prefs_get_gnome_animations ()
2643
return gnome_animations;
2646
MetaKeyBindingAction
2647
meta_prefs_get_keybinding_action (const char *name)
2651
i = G_N_ELEMENTS (key_bindings) - 2; /* -2 for dummy entry at end */
2654
if (strcmp (key_bindings[i].name, name) == 0)
2655
return (MetaKeyBindingAction) i;
2660
return META_KEYBINDING_ACTION_NONE;
2663
/* This is used by the menu system to decide what key binding
2664
* to display next to an option. We return the first non-disabled
2668
meta_prefs_get_window_binding (const char *name,
2669
unsigned int *keysym,
2670
MetaVirtualModifier *modifiers)
2674
i = G_N_ELEMENTS (key_bindings) - 2; /* -2 for dummy entry at end */
2677
if (key_bindings[i].per_window &&
2678
strcmp (key_bindings[i].name, name) == 0)
2680
GSList *s = key_bindings[i].bindings;
2684
MetaKeyCombo *c = s->data;
2686
if (c->keysym!=0 || c->modifiers!=0)
2688
*keysym = c->keysym;
2689
*modifiers = c->modifiers;
2696
/* Not found; return the disabled value */
2697
*keysym = *modifiers = 0;
2704
g_assert_not_reached ();
2708
meta_prefs_get_compositing_manager (void)
2710
return compositing_manager;
2714
meta_prefs_get_mouse_button_resize (void)
2716
return resize_with_right_button ? 3: 2;
2720
meta_prefs_get_mouse_button_menu (void)
2722
return resize_with_right_button ? 2: 3;
2726
meta_prefs_get_force_fullscreen (void)
2728
return force_fullscreen;
2732
meta_prefs_set_compositing_manager (gboolean whether)
2737
gconf_client_set_bool (default_client,
2744
meta_warning (_("Error setting compositor status: %s\n"),
2749
compositing_manager = whether;
2755
init_button_layout(void)
2757
MetaButtonLayout button_layout_ltr = {
2759
/* buttons in the group on the left side */
2760
META_BUTTON_FUNCTION_MENU,
2761
META_BUTTON_FUNCTION_LAST
2764
/* buttons in the group on the right side */
2765
META_BUTTON_FUNCTION_MINIMIZE,
2766
META_BUTTON_FUNCTION_MAXIMIZE,
2767
META_BUTTON_FUNCTION_CLOSE,
2768
META_BUTTON_FUNCTION_LAST
2771
MetaButtonLayout button_layout_rtl = {
2773
/* buttons in the group on the left side */
2774
META_BUTTON_FUNCTION_CLOSE,
2775
META_BUTTON_FUNCTION_MAXIMIZE,
2776
META_BUTTON_FUNCTION_MINIMIZE,
2777
META_BUTTON_FUNCTION_LAST
2780
/* buttons in the group on the right side */
2781
META_BUTTON_FUNCTION_MENU,
2782
META_BUTTON_FUNCTION_LAST
2786
button_layout = meta_ui_get_direction() == META_UI_DIRECTION_LTR ?
2787
button_layout_ltr : button_layout_rtl;
2793
meta_prefs_set_force_fullscreen (gboolean whether)
2795
force_fullscreen = whether;