~ubuntu-branches/ubuntu/raring/metacity/raring

« back to all changes in this revision

Viewing changes to .pc/11_hide_tooltip_on_decorator.patch/src/core/prefs.c

  • Committer: Package Import Robot
  • Author(s): Jeremy Bicha
  • Date: 2012-08-23 11:12:43 UTC
  • mfrom: (1.2.64) (2.1.13 quantal-proposed)
  • Revision ID: package-import@ubuntu.com-20120823111243-v2ome3yisozc1dhw
* Resync with Debian & refresh patches. (LP: #1032120, LP: #1035261)
  Remaining changes:
* debian/control:
  - Suggest gnome-themes-standard instead of recommend
  - Add Vcs-Bzr link
* debian/metacity-common.gsettings-override:
  - Set Ubuntu default button layout order for Classic session
  - Drop previous gconf overrides as obsolete
* debian/patches/04_support_drag_drop_with_alt_tab.patch:
  - Support alt-tab during drag and drop.
* debian/patches/05_raise_on_click_for_click_mode.patch:
  - Use raise on click option.
* debian/patches/06_Add_UXD_shadows_and_borders.patch:
  - patch for a new key in the ubuntu theme for shows and borders
* debian/patches/10_no-ws-switcher.patch:
  - Don't show the workspace switcher if we only have one.
* debian/patches/12_dont-show-as-user.patch:
  - Don't show "as user" in title bar.
* debian/patches/13_better_support_for_button_layout.patch:
  - Corrected support for buttons backgrounds with transparency
* debian/patches/14_wrong_colormap.patch:
  - Use correct colormap to avoid crash with client side decorations
* debian/patches/20_do-not-place-windows-over-the-launcher.patch:
  - Try to avoid an already visible launcher in intellihide mode when
    initially positioning new windows.
* debian/patches/21_fix_compositing_startup.patch:
  Fix some weird rendering effect at startup with compositing activated
* debian/patches/100_fade_on_long_title.patch:
  - Fade on the end if the title is too long.
* debian/patches/102_workarea.patch,
  debian/patches/103_struts_in_the_middle.patch,
  debian/patches/104_workarea_union.patch:
  - Add barriers and multimonitor strut support for unity-2d
* debian/patches/104_workarea_union.patch:
  - Ensure each screen_region generated by
    meta_rectangle_get_minimal_spanning_set_for_region is not outside
    the xinerama screens
* Dropped patch:
  - 11_hide_tooltip_on_decorator.patch: Obsolete
* debian/patches/03_strict_focus.patch:
  - Disabled. This needs gsettings-desktop-schemas to be patched if
    we want to bring this back
* Disabled Unity 2D-related patches that need porting to gsettings:
  - 15_show_maximized_titlebars.patch
  - 16-capture-before-unmap.patch
  - 17-workspace-switcher-cycle.patch
  - 18-auto-maximize-windows.patch
  - 19_add_unity_hud_configuration.patch
  - 101_override_gconf_settings.patch

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
 
 
3
 
/* Metacity preferences */
4
 
 
5
 
/* 
6
 
 * Copyright (C) 2001 Havoc Pennington, Copyright (C) 2002 Red Hat Inc.
7
 
 * Copyright (C) 2006 Elijah Newren
8
 
 * Copyright (C) 2008 Thomas Thurman
9
 
 * 
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.
14
 
 *
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.
19
 
 * 
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
23
 
 * 02111-1307, USA.
24
 
 */
25
 
 
26
 
#include <config.h>
27
 
#include "prefs.h"
28
 
#include "ui.h"
29
 
#include "util.h"
30
 
#ifdef HAVE_GCONF
31
 
#include <gconf/gconf-client.h>
32
 
#endif
33
 
#include <string.h>
34
 
#include <stdlib.h>
35
 
 
36
 
#define MAX_REASONABLE_WORKSPACES 36
37
 
 
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)
42
 
 
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.
45
 
 *
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.
49
 
 */
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"
54
 
 
55
 
#define KEY_COMMAND_DIRECTORY "/apps/metacity/keybinding_commands"
56
 
#define KEY_COMMAND_PREFIX "/apps/metacity/keybinding_commands/command_"
57
 
 
58
 
#define KEY_TERMINAL_DIR "/desktop/gnome/applications/terminal"
59
 
#define KEY_TERMINAL_COMMAND KEY_TERMINAL_DIR "/exec"
60
 
 
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"
64
 
 
65
 
#define KEY_WORKSPACE_NAME_DIRECTORY "/apps/metacity/workspace_names"
66
 
#define KEY_WORKSPACE_NAME_PREFIX "/apps/metacity/workspace_names/name_"
67
 
 
68
 
 
69
 
#ifdef HAVE_GCONF
70
 
static GConfClient *default_client = NULL;
71
 
static GList *changes = NULL;
72
 
static guint changed_idle;
73
 
static GList *listeners = NULL;
74
 
#endif
75
 
 
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;
101
 
 
102
 
static MetaVisualBellType visual_bell_type = META_VISUAL_BELL_FULLSCREEN_FLASH;
103
 
static MetaButtonLayout button_layout;
104
 
 
105
 
/* The screenshot commands are at the end */
106
 
static char *commands[MAX_COMMANDS] = { NULL, };
107
 
 
108
 
static char *terminal_command = NULL;
109
 
 
110
 
static char *workspace_names[MAX_REASONABLE_WORKSPACES] = { NULL, };
111
 
 
112
 
#ifdef HAVE_GCONF
113
 
static gboolean handle_preference_update_enum (const gchar *key, GConfValue *value);
114
 
 
115
 
static gboolean update_key_binding     (const char *name,
116
 
                                        const char *value);
117
 
static gboolean find_and_update_list_binding (MetaKeyPref *bindings,
118
 
                                              const char  *name,
119
 
                                              GSList      *value);
120
 
static gboolean update_key_list_binding (const char *name,
121
 
                                         GSList      *value);
122
 
static gboolean update_command            (const char  *name,
123
 
                                           const char  *value);
124
 
static gboolean update_workspace_name     (const char  *name,
125
 
                                           const char  *value);
126
 
 
127
 
static void change_notify (GConfClient    *client,
128
 
                           guint           cnxn_id,
129
 
                           GConfEntry     *entry,
130
 
                           gpointer        user_data);
131
 
 
132
 
static char* gconf_key_for_workspace_name (int i);
133
 
 
134
 
static void queue_changed (MetaPreference  pref);
135
 
 
136
 
typedef enum
137
 
  {
138
 
    META_LIST_OF_STRINGS,
139
 
    META_LIST_OF_GCONFVALUE_STRINGS
140
 
  } MetaStringListType;
141
 
 
142
 
static gboolean update_list_binding       (MetaKeyPref *binding,
143
 
                                           GSList      *value,
144
 
                                           MetaStringListType type_of_value);
145
 
 
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);
149
 
 
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*);
154
 
 
155
 
#endif /* HAVE_GCONF */
156
 
 
157
 
static gboolean update_binding            (MetaKeyPref *binding,
158
 
                                           const char  *value);
159
 
 
160
 
static void     init_bindings             (void);
161
 
static void     init_commands             (void);
162
 
static void     init_workspace_names      (void);
163
 
 
164
 
#ifndef HAVE_GCONF
165
 
static void     init_button_layout        (void);
166
 
#endif /* !HAVE_GCONF */
167
 
 
168
 
#ifdef HAVE_GCONF
169
 
 
170
 
typedef struct
171
 
{
172
 
  MetaPrefsChangedFunc func;
173
 
  gpointer data;
174
 
} MetaPrefsListener;
175
 
 
176
 
static GConfEnumStringPair symtab_focus_mode[] =
177
 
  {
178
 
    { META_FOCUS_MODE_CLICK,  "click" },
179
 
    { META_FOCUS_MODE_SLOPPY, "sloppy" },
180
 
    { META_FOCUS_MODE_MOUSE,  "mouse" },
181
 
    { META_FOCUS_MODE_STRICT, "strict" },
182
 
    { 0, NULL },
183
 
  };
184
 
 
185
 
static GConfEnumStringPair symtab_focus_new_windows[] =
186
 
  {
187
 
    { META_FOCUS_NEW_WINDOWS_SMART,  "smart" },
188
 
    { META_FOCUS_NEW_WINDOWS_STRICT, "strict" },
189
 
    { 0, NULL },
190
 
  };
191
 
 
192
 
static GConfEnumStringPair symtab_visual_bell_type[] =
193
 
  {
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" },
197
 
    { 0, NULL },
198
 
  };
199
 
 
200
 
static GConfEnumStringPair symtab_titlebar_action[] =
201
 
  {
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" },
213
 
    { 0, NULL },
214
 
  };
215
 
 
216
 
/**
217
 
 * The details of one preference which is constrained to be
218
 
 * one of a small number of string values-- in other words,
219
 
 * an enumeration.
220
 
 *
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.
229
 
 *
230
 
 * Other things we might consider doing to clean this up in the
231
 
 * future include:
232
 
 *
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
235
 
 *
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.)
240
 
 *
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.
244
 
 */
245
 
typedef struct
246
 
{
247
 
  gchar *key;
248
 
  MetaPreference pref;
249
 
  GConfEnumStringPair *symtab;
250
 
  gpointer target;
251
 
} MetaEnumPreference;
252
 
 
253
 
typedef struct
254
 
{
255
 
  gchar *key;
256
 
  MetaPreference pref;
257
 
  gboolean *target;
258
 
  gboolean becomes_true_on_destruction;
259
 
} MetaBoolPreference;
260
 
 
261
 
typedef struct
262
 
{
263
 
  gchar *key;
264
 
  MetaPreference pref;
265
 
 
266
 
  /**
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.
272
 
   *
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.
277
 
   *
278
 
   * This may be NULL.  If it is, see "target", below.
279
 
   */
280
 
  void (*handler) (MetaPreference pref,
281
 
                     const gchar *string_value,
282
 
                     gboolean *inform_listeners);
283
 
 
284
 
  /**
285
 
   * Where to write the incoming string.
286
 
   *
287
 
   * This must be NULL if the handler is non-NULL.
288
 
   * If the incoming string is NULL, no change will be made.
289
 
   */
290
 
  gchar **target;
291
 
 
292
 
} MetaStringPreference;
293
 
 
294
 
#define METAINTPREFERENCE_NO_CHANGE_ON_DESTROY G_MININT
295
 
 
296
 
typedef struct
297
 
{
298
 
  gchar *key;
299
 
  MetaPreference pref;
300
 
  gint *target;
301
 
  /**
302
 
   * Minimum and maximum values of the integer.
303
 
   * If the new value is out of bounds, it will be discarded with a warning.
304
 
   */
305
 
  gint minimum, maximum;
306
 
  /**
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.
310
 
   */
311
 
  gint value_if_destroyed;
312
 
} MetaIntPreference;
313
 
 
314
 
/* FIXMEs: */
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? */
318
 
 
319
 
static MetaEnumPreference preferences_enum[] =
320
 
  {
321
 
    { "/apps/metacity/general/focus_new_windows",
322
 
      META_PREF_FOCUS_NEW_WINDOWS,
323
 
      symtab_focus_new_windows,
324
 
      &focus_new_windows,
325
 
    },
326
 
    { "/apps/metacity/general/focus_mode",
327
 
      META_PREF_FOCUS_MODE,
328
 
      symtab_focus_mode,
329
 
      &focus_mode,
330
 
    },
331
 
    { "/apps/metacity/general/visual_bell_type",
332
 
      META_PREF_VISUAL_BELL_TYPE,
333
 
      symtab_visual_bell_type,
334
 
      &visual_bell_type,
335
 
    },
336
 
    { "/apps/metacity/general/action_double_click_titlebar",
337
 
      META_PREF_ACTION_DOUBLE_CLICK_TITLEBAR,
338
 
      symtab_titlebar_action,
339
 
      &action_double_click_titlebar,
340
 
    },
341
 
    { "/apps/metacity/general/action_middle_click_titlebar",
342
 
      META_PREF_ACTION_MIDDLE_CLICK_TITLEBAR,
343
 
      symtab_titlebar_action,
344
 
      &action_middle_click_titlebar,
345
 
    },
346
 
    { "/apps/metacity/general/action_right_click_titlebar",
347
 
      META_PREF_ACTION_RIGHT_CLICK_TITLEBAR,
348
 
      symtab_titlebar_action,
349
 
      &action_right_click_titlebar,
350
 
    },
351
 
    { NULL, 0, NULL, NULL },
352
 
  };
353
 
 
354
 
static MetaBoolPreference preferences_bool[] =
355
 
  {
356
 
    { "/apps/metacity/general/raise_on_click",
357
 
      META_PREF_RAISE_ON_CLICK,
358
 
      &raise_on_click,
359
 
      TRUE,
360
 
    },
361
 
    { "/apps/metacity/general/titlebar_uses_system_font",
362
 
      META_PREF_TITLEBAR_FONT, /* note! shares a pref */
363
 
      &use_system_font,
364
 
      TRUE,
365
 
    },
366
 
    { "/apps/metacity/general/application_based",
367
 
      META_PREF_APPLICATION_BASED,
368
 
      NULL, /* feature is known but disabled */
369
 
      FALSE,
370
 
    },
371
 
    { "/apps/metacity/general/disable_workarounds",
372
 
      META_PREF_DISABLE_WORKAROUNDS,
373
 
      &disable_workarounds,
374
 
      FALSE,
375
 
    },
376
 
    { "/apps/metacity/general/auto_raise",
377
 
      META_PREF_AUTO_RAISE,
378
 
      &auto_raise,
379
 
      FALSE,
380
 
    },
381
 
    { "/apps/metacity/general/visual_bell",
382
 
      META_PREF_VISUAL_BELL,
383
 
      &provide_visual_bell, /* FIXME: change the name: it's confusing */
384
 
      FALSE,
385
 
    },
386
 
    { "/apps/metacity/general/audible_bell",
387
 
      META_PREF_AUDIBLE_BELL,
388
 
      &bell_is_audible, /* FIXME: change the name: it's confusing */
389
 
      FALSE,
390
 
    },
391
 
    { "/apps/metacity/general/reduced_resources",
392
 
      META_PREF_REDUCED_RESOURCES,
393
 
      &reduced_resources,
394
 
      FALSE,
395
 
    },
396
 
    { "/desktop/gnome/interface/accessibility",
397
 
      META_PREF_GNOME_ACCESSIBILITY,
398
 
      &gnome_accessibility,
399
 
      FALSE,
400
 
    },
401
 
    { "/desktop/gnome/interface/enable_animations",
402
 
      META_PREF_GNOME_ANIMATIONS,
403
 
      &gnome_animations,
404
 
      TRUE,
405
 
    },
406
 
    { "/apps/metacity/general/compositing_manager",
407
 
      META_PREF_COMPOSITING_MANAGER,
408
 
      &compositing_manager,
409
 
      FALSE,
410
 
    },
411
 
    { "/apps/metacity/general/resize_with_right_button",
412
 
      META_PREF_RESIZE_WITH_RIGHT_BUTTON,
413
 
      &resize_with_right_button,
414
 
      FALSE,
415
 
    },
416
 
    { NULL, 0, NULL, FALSE },
417
 
  };
418
 
 
419
 
static MetaStringPreference preferences_string[] =
420
 
  {
421
 
    { "/apps/metacity/general/mouse_button_modifier",
422
 
      META_PREF_MOUSE_BUTTON_MODS,
423
 
      mouse_button_mods_handler,
424
 
      NULL,
425
 
    },
426
 
    { "/apps/metacity/general/theme",
427
 
      META_PREF_THEME,
428
 
      theme_name_handler,
429
 
      NULL,
430
 
    },
431
 
    { KEY_TITLEBAR_FONT,
432
 
      META_PREF_TITLEBAR_FONT,
433
 
      titlebar_handler,
434
 
      NULL,
435
 
    },
436
 
    { KEY_TERMINAL_COMMAND,
437
 
      META_PREF_TERMINAL_COMMAND,
438
 
      NULL,
439
 
      &terminal_command,
440
 
    },
441
 
    { "/apps/metacity/general/button_layout",
442
 
      META_PREF_BUTTON_LAYOUT,
443
 
      button_layout_handler,
444
 
      NULL,
445
 
    },
446
 
    { "/desktop/gnome/peripherals/mouse/cursor_theme",
447
 
      META_PREF_CURSOR_THEME,
448
 
      NULL,
449
 
      &cursor_theme,
450
 
    },
451
 
    { NULL, 0, NULL, NULL },
452
 
  };
453
 
 
454
 
static MetaIntPreference preferences_int[] =
455
 
  {
456
 
    { "/apps/metacity/general/num_workspaces",
457
 
      META_PREF_NUM_WORKSPACES,
458
 
      &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.
461
 
       *  -- tthurman
462
 
       */
463
 
      1, MAX_REASONABLE_WORKSPACES, METAINTPREFERENCE_NO_CHANGE_ON_DESTROY,
464
 
    },
465
 
    { "/apps/metacity/general/auto_raise_delay",
466
 
      META_PREF_AUTO_RAISE_DELAY,
467
 
      &auto_raise_delay,
468
 
      0, 10000, 0,
469
 
      /* @@@ Get rid of MAX_REASONABLE_AUTO_RAISE_DELAY */
470
 
    },
471
 
    { "/desktop/gnome/peripherals/mouse/cursor_size",
472
 
      META_PREF_CURSOR_SIZE,
473
 
      &cursor_size,
474
 
      1, 128, 24,
475
 
    },
476
 
    { NULL, 0, NULL, 0, 0, 0, },
477
 
  };
478
 
 
479
 
static void
480
 
handle_preference_init_enum (void)
481
 
{
482
 
  MetaEnumPreference *cursor = preferences_enum;
483
 
 
484
 
  while (cursor->key!=NULL)
485
 
    {
486
 
      char *value;
487
 
      GError *error = NULL;
488
 
 
489
 
      if (cursor->target==NULL)
490
 
        {
491
 
          ++cursor;
492
 
          continue;
493
 
        }
494
 
 
495
 
      value = gconf_client_get_string (default_client,
496
 
                                       cursor->key,
497
 
                                       &error);
498
 
      cleanup_error (&error);
499
 
 
500
 
      if (value==NULL)
501
 
        {
502
 
          ++cursor;
503
 
          continue;
504
 
        }
505
 
 
506
 
      if (!gconf_string_to_enum (cursor->symtab,
507
 
                                 value,
508
 
                                 (gint *) cursor->target))
509
 
        meta_warning (_("GConf key '%s' is set to an invalid value\n"),
510
 
                      cursor->key);
511
 
 
512
 
      g_free (value);
513
 
 
514
 
      ++cursor;
515
 
    }
516
 
}
517
 
 
518
 
static void
519
 
handle_preference_init_bool (void)
520
 
{
521
 
  MetaBoolPreference *cursor = preferences_bool;
522
 
 
523
 
  while (cursor->key!=NULL)
524
 
    {
525
 
      if (cursor->target!=NULL)
526
 
        get_bool (cursor->key, cursor->target);
527
 
 
528
 
      ++cursor;
529
 
    }
530
 
 
531
 
  maybe_give_disable_workarounds_warning ();
532
 
}
533
 
 
534
 
static void
535
 
handle_preference_init_string (void)
536
 
{
537
 
  MetaStringPreference *cursor = preferences_string;
538
 
 
539
 
  while (cursor->key!=NULL)
540
 
    {
541
 
      char *value;
542
 
      GError *error = NULL;
543
 
      gboolean dummy = TRUE;
544
 
 
545
 
      /* the string "value" will be newly allocated */
546
 
      value = gconf_client_get_string (default_client,
547
 
                                       cursor->key,
548
 
                                       &error);
549
 
      cleanup_error (&error);
550
 
 
551
 
      if (cursor->handler)
552
 
        {
553
 
          if (cursor->target)
554
 
            meta_bug ("%s has both a target and a handler\n", cursor->key);
555
 
 
556
 
          cursor->handler (cursor->pref, value, &dummy);
557
 
 
558
 
          g_free (value);
559
 
        }
560
 
      else if (cursor->target)
561
 
        {
562
 
          if (*(cursor->target))
563
 
            g_free (*(cursor->target));
564
 
 
565
 
          *(cursor->target) = value;
566
 
        }
567
 
 
568
 
      ++cursor;
569
 
    }
570
 
}
571
 
 
572
 
static void
573
 
handle_preference_init_int (void)
574
 
{
575
 
  MetaIntPreference *cursor = preferences_int;
576
 
 
577
 
  
578
 
  while (cursor->key!=NULL)
579
 
    {
580
 
      gint value;
581
 
      GError *error = NULL;
582
 
 
583
 
      value = gconf_client_get_int (default_client,
584
 
                                    cursor->key,
585
 
                                    &error);
586
 
      cleanup_error (&error);
587
 
 
588
 
      if (value < cursor->minimum || value > cursor->maximum)
589
 
        {
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.
596
 
           *
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.
601
 
           */
602
 
        }
603
 
      else if (cursor->target)
604
 
        *cursor->target = value;
605
 
 
606
 
      ++cursor;
607
 
    }
608
 
}
609
 
 
610
 
static gboolean
611
 
handle_preference_update_enum (const gchar *key, GConfValue *value)
612
 
{
613
 
  MetaEnumPreference *cursor = preferences_enum;
614
 
  gint old_value;
615
 
 
616
 
  while (cursor->key!=NULL && strcmp (key, cursor->key)!=0)
617
 
    ++cursor;
618
 
 
619
 
  if (cursor->key==NULL)
620
 
    /* Didn't recognise that key. */
621
 
    return FALSE;
622
 
      
623
 
  /* Setting it to null (that is, removing it) always means
624
 
   * "don't change".
625
 
   */
626
 
 
627
 
  if (value==NULL)
628
 
    return TRUE;
629
 
 
630
 
  /* Check the type.  Enums are always strings. */
631
 
 
632
 
  if (value->type != GCONF_VALUE_STRING)
633
 
    {
634
 
      meta_warning (_("GConf key \"%s\" is set to an invalid type\n"),
635
 
                    key);
636
 
      /* But we did recognise it. */
637
 
      return TRUE;
638
 
    }
639
 
 
640
 
  /* We need to know whether the value changes, so
641
 
   * store the current value away.
642
 
   */
643
 
 
644
 
  old_value = * ((gint *) cursor->target);
645
 
  
646
 
  /* Now look it up... */
647
 
 
648
 
  if (!gconf_string_to_enum (cursor->symtab,
649
 
                             gconf_value_get_string (value),
650
 
                             (gint *) cursor->target))
651
 
    {
652
 
      /*
653
 
       * We found it, but it was invalid.  Complain.
654
 
       *
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
658
 
       * the symtab.)
659
 
       *
660
 
       * (Empty comment follows so the translators don't see this.)
661
 
       */
662
 
 
663
 
      /*  */      
664
 
      meta_warning (_("GConf key '%s' is set to an invalid value\n"),
665
 
                    key);
666
 
      return TRUE;
667
 
    }
668
 
 
669
 
  /* Did it change?  If so, tell the listeners about it. */
670
 
 
671
 
  if (old_value != *((gint *) cursor->target))
672
 
    queue_changed (cursor->pref);
673
 
 
674
 
  return TRUE;
675
 
}
676
 
 
677
 
static gboolean
678
 
handle_preference_update_bool (const gchar *key, GConfValue *value)
679
 
{
680
 
  MetaBoolPreference *cursor = preferences_bool;
681
 
  gboolean old_value;
682
 
 
683
 
  while (cursor->key!=NULL && strcmp (key, cursor->key)!=0)
684
 
    ++cursor;
685
 
 
686
 
  if (cursor->key==NULL)
687
 
    /* Didn't recognise that key. */
688
 
    return FALSE;
689
 
 
690
 
  if (cursor->target==NULL)
691
 
    /* No work for us to do. */
692
 
    return TRUE;
693
 
      
694
 
  if (value==NULL)
695
 
    {
696
 
      /* Value was destroyed; let's get out of here. */
697
 
 
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.
701
 
         */
702
 
        *((gboolean *)cursor->target) = TRUE;
703
 
 
704
 
      return TRUE;
705
 
    }
706
 
 
707
 
  /* Check the type. */
708
 
 
709
 
  if (value->type != GCONF_VALUE_BOOL)
710
 
    {
711
 
      meta_warning (_("GConf key \"%s\" is set to an invalid type\n"),
712
 
                    key);
713
 
      /* But we did recognise it. */
714
 
      return TRUE;
715
 
    }
716
 
 
717
 
  /* We need to know whether the value changes, so
718
 
   * store the current value away.
719
 
   */
720
 
 
721
 
  old_value = * ((gboolean *) cursor->target);
722
 
  
723
 
  /* Now look it up... */
724
 
 
725
 
  *((gboolean *) cursor->target) = gconf_value_get_bool (value);
726
 
 
727
 
  /* Did it change?  If so, tell the listeners about it. */
728
 
 
729
 
  if (old_value != *((gboolean *) cursor->target))
730
 
    queue_changed (cursor->pref);
731
 
 
732
 
  if (cursor->pref==META_PREF_DISABLE_WORKAROUNDS)
733
 
    maybe_give_disable_workarounds_warning ();
734
 
 
735
 
  return TRUE;
736
 
}
737
 
 
738
 
static gboolean
739
 
handle_preference_update_string (const gchar *key, GConfValue *value)
740
 
{
741
 
  MetaStringPreference *cursor = preferences_string;
742
 
  const gchar *value_as_string;
743
 
  gboolean inform_listeners = TRUE;
744
 
 
745
 
  while (cursor->key!=NULL && strcmp (key, cursor->key)!=0)
746
 
    ++cursor;
747
 
 
748
 
  if (cursor->key==NULL)
749
 
    /* Didn't recognise that key. */
750
 
    return FALSE;
751
 
 
752
 
  if (value==NULL)
753
 
    return TRUE;
754
 
 
755
 
  /* Check the type. */
756
 
 
757
 
  if (value->type != GCONF_VALUE_STRING)
758
 
    {
759
 
      meta_warning (_("GConf key \"%s\" is set to an invalid type\n"),
760
 
                    key);
761
 
      /* But we did recognise it. */
762
 
      return TRUE;
763
 
    }
764
 
 
765
 
  /* Docs: "The returned string is not a copy, don't try to free it." */
766
 
  value_as_string = gconf_value_get_string (value);
767
 
 
768
 
  if (cursor->handler)
769
 
    cursor->handler (cursor->pref, value_as_string, &inform_listeners);
770
 
  else if (cursor->target)
771
 
    {
772
 
      if (*(cursor->target))
773
 
        g_free(*(cursor->target));
774
 
 
775
 
      if (value_as_string!=NULL)
776
 
        *(cursor->target) = g_strdup (value_as_string);
777
 
      else
778
 
        *(cursor->target) = NULL;
779
 
 
780
 
      inform_listeners =
781
 
        (value_as_string==NULL && *(cursor->target)==NULL) ||
782
 
        (value_as_string!=NULL && *(cursor->target)!=NULL &&
783
 
         strcmp (value_as_string, *(cursor->target))==0);
784
 
    }
785
 
 
786
 
  if (inform_listeners)
787
 
    queue_changed (cursor->pref);
788
 
 
789
 
  return TRUE;
790
 
}
791
 
 
792
 
static gboolean
793
 
handle_preference_update_int (const gchar *key, GConfValue *value)
794
 
{
795
 
  MetaIntPreference *cursor = preferences_int;
796
 
  gint new_value;
797
 
 
798
 
  while (cursor->key!=NULL && strcmp (key, cursor->key)!=0)
799
 
    ++cursor;
800
 
 
801
 
  if (cursor->key==NULL)
802
 
    /* Didn't recognise that key. */
803
 
    return FALSE;
804
 
 
805
 
  if (cursor->target==NULL)
806
 
    /* No work for us to do. */
807
 
    return TRUE;
808
 
      
809
 
  if (value==NULL)
810
 
    {
811
 
      /* Value was destroyed. */
812
 
 
813
 
      if (cursor->value_if_destroyed != METAINTPREFERENCE_NO_CHANGE_ON_DESTROY)
814
 
        *((gint *)cursor->target) = cursor->value_if_destroyed;
815
 
 
816
 
      return TRUE;
817
 
    }
818
 
 
819
 
  /* Check the type. */
820
 
 
821
 
  if (value->type != GCONF_VALUE_INT)
822
 
    {
823
 
      meta_warning (_("GConf key \"%s\" is set to an invalid type\n"),
824
 
                    key);
825
 
      /* But we did recognise it. */
826
 
      return TRUE;
827
 
    }
828
 
 
829
 
  new_value = gconf_value_get_int (value);
830
 
 
831
 
  if (new_value < cursor->minimum || new_value > cursor->maximum)
832
 
    {
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);
836
 
      return TRUE;
837
 
    }
838
 
 
839
 
  /* Did it change?  If so, tell the listeners about it. */
840
 
 
841
 
  if (*cursor->target != new_value)
842
 
    {
843
 
      *cursor->target = new_value;
844
 
      queue_changed (cursor->pref);
845
 
    }
846
 
 
847
 
  return TRUE;
848
 
  
849
 
}
850
 
 
851
 
 
852
 
/****************************************************************************/
853
 
/* Listeners.                                                               */
854
 
/****************************************************************************/
855
 
 
856
 
void
857
 
meta_prefs_add_listener (MetaPrefsChangedFunc func,
858
 
                         gpointer             data)
859
 
{
860
 
  MetaPrefsListener *l;
861
 
 
862
 
  l = g_new (MetaPrefsListener, 1);
863
 
  l->func = func;
864
 
  l->data = data;
865
 
 
866
 
  listeners = g_list_prepend (listeners, l);
867
 
}
868
 
 
869
 
void
870
 
meta_prefs_remove_listener (MetaPrefsChangedFunc func,
871
 
                            gpointer             data)
872
 
{
873
 
  GList *tmp;
874
 
 
875
 
  tmp = listeners;
876
 
  while (tmp != NULL)
877
 
    {
878
 
      MetaPrefsListener *l = tmp->data;
879
 
 
880
 
      if (l->func == func &&
881
 
          l->data == data)
882
 
        {
883
 
          g_free (l);
884
 
          listeners = g_list_delete_link (listeners, tmp);
885
 
 
886
 
          return;
887
 
        }
888
 
      
889
 
      tmp = tmp->next;
890
 
    }
891
 
 
892
 
  meta_bug ("Did not find listener to remove\n");
893
 
}
894
 
 
895
 
static void
896
 
emit_changed (MetaPreference pref)
897
 
{
898
 
  GList *tmp;
899
 
  GList *copy;
900
 
 
901
 
  meta_topic (META_DEBUG_PREFS, "Notifying listeners that pref %s changed\n",
902
 
              meta_preference_to_string (pref));
903
 
  
904
 
  copy = g_list_copy (listeners);
905
 
  
906
 
  tmp = copy;
907
 
 
908
 
  while (tmp != NULL)
909
 
    {
910
 
      MetaPrefsListener *l = tmp->data;
911
 
 
912
 
      (* l->func) (pref, l->data);
913
 
 
914
 
      tmp = tmp->next;
915
 
    }
916
 
 
917
 
  g_list_free (copy);
918
 
}
919
 
 
920
 
static gboolean
921
 
changed_idle_handler (gpointer data)
922
 
{
923
 
  GList *tmp;
924
 
  GList *copy;
925
 
 
926
 
  changed_idle = 0;
927
 
  
928
 
  copy = g_list_copy (changes); /* reentrancy paranoia */
929
 
 
930
 
  g_list_free (changes);
931
 
  changes = NULL;
932
 
  
933
 
  tmp = copy;
934
 
  while (tmp != NULL)
935
 
    {
936
 
      MetaPreference pref = GPOINTER_TO_INT (tmp->data);
937
 
 
938
 
      emit_changed (pref);
939
 
      
940
 
      tmp = tmp->next;
941
 
    }
942
 
 
943
 
  g_list_free (copy);
944
 
  
945
 
  return FALSE;
946
 
}
947
 
 
948
 
static void
949
 
queue_changed (MetaPreference pref)
950
 
{
951
 
  meta_topic (META_DEBUG_PREFS, "Queueing change of pref %s\n",
952
 
              meta_preference_to_string (pref));  
953
 
 
954
 
  if (g_list_find (changes, GINT_TO_POINTER (pref)) == NULL)
955
 
    changes = g_list_prepend (changes, GINT_TO_POINTER (pref));
956
 
  else
957
 
    meta_topic (META_DEBUG_PREFS, "Change of pref %s was already pending\n",
958
 
                meta_preference_to_string (pref));
959
 
 
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);
964
 
}
965
 
 
966
 
#else /* HAVE_GCONF */
967
 
 
968
 
void
969
 
meta_prefs_add_listener (MetaPrefsChangedFunc func,
970
 
                         gpointer             data)
971
 
{
972
 
  /* Nothing, because they have gconf turned off */
973
 
}
974
 
 
975
 
void
976
 
meta_prefs_remove_listener (MetaPrefsChangedFunc func,
977
 
                            gpointer             data)
978
 
{
979
 
  /* Nothing, because they have gconf turned off */
980
 
}
981
 
 
982
 
#endif /* HAVE_GCONF */
983
 
 
984
 
 
985
 
/****************************************************************************/
986
 
/* Initialisation.                                                          */
987
 
/****************************************************************************/
988
 
 
989
 
#ifdef HAVE_GCONF
990
 
/* @@@ again, use glib's ability to tell you the size of the array */
991
 
static gchar *gconf_dirs_we_are_interested_in[] = {
992
 
  "/apps/metacity",
993
 
  KEY_TERMINAL_DIR,
994
 
  KEY_GNOME_ACCESSIBILITY,
995
 
  "/desktop/gnome/peripherals/mouse",
996
 
  "/desktop/gnome/interface",
997
 
  NULL,
998
 
};
999
 
#endif
1000
 
 
1001
 
void
1002
 
meta_prefs_init (void)
1003
 
{
1004
 
#ifdef HAVE_GCONF
1005
 
  GError *err = NULL;
1006
 
  gchar **gconf_dir_cursor;
1007
 
  
1008
 
  if (default_client != NULL)
1009
 
    return;
1010
 
  
1011
 
  /* returns a reference which we hold forever */
1012
 
  default_client = gconf_client_get_default ();
1013
 
 
1014
 
  for (gconf_dir_cursor=gconf_dirs_we_are_interested_in;
1015
 
       *gconf_dir_cursor!=NULL;
1016
 
       gconf_dir_cursor++)
1017
 
    {
1018
 
      gconf_client_add_dir (default_client,
1019
 
                            *gconf_dir_cursor,
1020
 
                            GCONF_CLIENT_PRELOAD_RECURSIVE,
1021
 
                            &err);
1022
 
      cleanup_error (&err);
1023
 
    }
1024
 
 
1025
 
  /* Pick up initial values. */
1026
 
 
1027
 
  handle_preference_init_enum ();
1028
 
  handle_preference_init_bool ();
1029
 
  handle_preference_init_string ();
1030
 
  handle_preference_init_int ();
1031
 
 
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;
1035
 
       gconf_dir_cursor++)
1036
 
    {
1037
 
      gconf_client_notify_add (default_client,
1038
 
                               *gconf_dir_cursor,
1039
 
                               change_notify,
1040
 
                               NULL,
1041
 
                               NULL,
1042
 
                               &err);
1043
 
      cleanup_error (&err);
1044
 
    }
1045
 
 
1046
 
#else  /* HAVE_GCONF */
1047
 
 
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.
1052
 
   */
1053
 
  titlebar_font = pango_font_description_from_string ("Sans Bold 10");
1054
 
  current_theme = g_strdup ("Atlanta");
1055
 
  
1056
 
  init_button_layout();
1057
 
#endif /* HAVE_GCONF */
1058
 
  
1059
 
  init_bindings ();
1060
 
  init_commands ();
1061
 
  init_workspace_names ();
1062
 
}
1063
 
 
1064
 
 
1065
 
/****************************************************************************/
1066
 
/* Updates.                                                                 */
1067
 
/****************************************************************************/
1068
 
 
1069
 
#ifdef HAVE_GCONF
1070
 
 
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,
1076
 
  NULL
1077
 
};
1078
 
 
1079
 
static void
1080
 
change_notify (GConfClient    *client,
1081
 
               guint           cnxn_id,
1082
 
               GConfEntry     *entry,
1083
 
               gpointer        user_data)
1084
 
{
1085
 
  const char *key;
1086
 
  GConfValue *value;
1087
 
  gint i=0;
1088
 
  
1089
 
  key = gconf_entry_get_key (entry);
1090
 
  value = gconf_entry_get_value (entry);
1091
 
 
1092
 
  /* First, search for a handler that might know what to do. */
1093
 
 
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.
1097
 
   */
1098
 
 
1099
 
  while (preference_update_handler[i]!=NULL)
1100
 
    {
1101
 
      if (preference_update_handler[i] (key, value))
1102
 
        goto out; /* Get rid of this eventually */
1103
 
 
1104
 
      i++;
1105
 
    }
1106
 
  
1107
 
  if (g_str_has_prefix (key, KEY_WINDOW_BINDINGS_PREFIX) ||
1108
 
      g_str_has_prefix (key, KEY_SCREEN_BINDINGS_PREFIX))
1109
 
    {
1110
 
      if (g_str_has_suffix (key, KEY_LIST_BINDINGS_SUFFIX))
1111
 
        {
1112
 
          GSList *list;
1113
 
 
1114
 
          if (value && value->type != GCONF_VALUE_LIST)
1115
 
            {
1116
 
              meta_warning (_("GConf key \"%s\" is set to an invalid type\n"),
1117
 
                            key);
1118
 
              goto out;
1119
 
            }
1120
 
 
1121
 
          list = value ? gconf_value_get_list (value) : NULL;
1122
 
 
1123
 
          if (update_key_list_binding (key, list))
1124
 
            queue_changed (META_PREF_KEYBINDINGS);
1125
 
        }
1126
 
      else
1127
 
        {
1128
 
          const char *str;
1129
 
 
1130
 
          if (value && value->type != GCONF_VALUE_STRING)
1131
 
            {
1132
 
              meta_warning (_("GConf key \"%s\" is set to an invalid type\n"),
1133
 
                            key);
1134
 
              goto out;
1135
 
            }
1136
 
 
1137
 
          str = value ? gconf_value_get_string (value) : NULL;
1138
 
 
1139
 
          if (update_key_binding (key, str))
1140
 
            queue_changed (META_PREF_KEYBINDINGS);
1141
 
        }
1142
 
    }
1143
 
  else if (g_str_has_prefix (key, KEY_COMMAND_PREFIX))
1144
 
    {
1145
 
      const char *str;
1146
 
 
1147
 
      if (value && value->type != GCONF_VALUE_STRING)
1148
 
        {
1149
 
          meta_warning (_("GConf key \"%s\" is set to an invalid type\n"),
1150
 
                        key);
1151
 
          goto out;
1152
 
        }
1153
 
 
1154
 
      str = value ? gconf_value_get_string (value) : NULL;
1155
 
 
1156
 
      if (update_command (key, str))
1157
 
        queue_changed (META_PREF_COMMANDS);
1158
 
    }
1159
 
  else if (g_str_has_prefix (key, KEY_WORKSPACE_NAME_PREFIX))
1160
 
    {
1161
 
      const char *str;
1162
 
 
1163
 
      if (value && value->type != GCONF_VALUE_STRING)
1164
 
        {
1165
 
          meta_warning (_("GConf key \"%s\" is set to an invalid type\n"),
1166
 
                        key);
1167
 
          goto out;
1168
 
        }
1169
 
 
1170
 
      str = value ? gconf_value_get_string (value) : NULL;
1171
 
 
1172
 
      if (update_workspace_name (key, str))
1173
 
        queue_changed (META_PREF_WORKSPACE_NAMES);
1174
 
    }
1175
 
  else
1176
 
    {
1177
 
      meta_topic (META_DEBUG_PREFS, "Key %s doesn't mean anything to Metacity\n",
1178
 
                  key);
1179
 
    }
1180
 
  
1181
 
 out:
1182
 
  /* nothing */
1183
 
  return; /* AIX compiler wants something after a label like out: */
1184
 
}
1185
 
 
1186
 
static void
1187
 
cleanup_error (GError **error)
1188
 
{
1189
 
  if (*error)
1190
 
    {
1191
 
      meta_warning ("%s\n", (*error)->message);
1192
 
      
1193
 
      g_error_free (*error);
1194
 
      *error = NULL;
1195
 
    }
1196
 
}
1197
 
 
1198
 
/* get_bool returns TRUE if *val is filled in, FALSE otherwise */
1199
 
/* @@@ probably worth moving this inline; only used once */
1200
 
static gboolean
1201
 
get_bool (const char *key, gboolean *val)
1202
 
{
1203
 
  GError     *err = NULL;
1204
 
  GConfValue *value;
1205
 
  gboolean    filled_in = FALSE;
1206
 
 
1207
 
  value = gconf_client_get (default_client, key, &err);
1208
 
  cleanup_error (&err);
1209
 
  if (value)
1210
 
    {
1211
 
      if (value->type == GCONF_VALUE_BOOL)
1212
 
        {
1213
 
          *val = gconf_value_get_bool (value);
1214
 
          filled_in = TRUE;
1215
 
        }
1216
 
      gconf_value_free (value);
1217
 
    }
1218
 
 
1219
 
  return filled_in;
1220
 
}
1221
 
 
1222
 
/**
1223
 
 * Special case: give a warning the first time disable_workarounds
1224
 
 * is turned on.
1225
 
 */
1226
 
static void
1227
 
maybe_give_disable_workarounds_warning (void)
1228
 
{
1229
 
  static gboolean first_disable = TRUE;
1230
 
    
1231
 
  if (first_disable && disable_workarounds)
1232
 
    {
1233
 
      first_disable = FALSE;
1234
 
 
1235
 
      meta_warning (_("Workarounds for broken applications disabled. "
1236
 
                      "Some applications may not behave properly.\n"));
1237
 
    }
1238
 
}
1239
 
 
1240
 
#endif /* HAVE_GCONF */
1241
 
 
1242
 
MetaVirtualModifier
1243
 
meta_prefs_get_mouse_button_mods  (void)
1244
 
{
1245
 
  return mouse_button_mods;
1246
 
}
1247
 
 
1248
 
MetaFocusMode
1249
 
meta_prefs_get_focus_mode (void)
1250
 
{
1251
 
  return focus_mode;
1252
 
}
1253
 
 
1254
 
MetaFocusNewWindows
1255
 
meta_prefs_get_focus_new_windows (void)
1256
 
{
1257
 
  return focus_new_windows;
1258
 
}
1259
 
 
1260
 
gboolean
1261
 
meta_prefs_get_raise_on_click (void)
1262
 
{
1263
 
  return raise_on_click;
1264
 
}
1265
 
 
1266
 
const char*
1267
 
meta_prefs_get_theme (void)
1268
 
{
1269
 
  return current_theme;
1270
 
}
1271
 
 
1272
 
const char*
1273
 
meta_prefs_get_cursor_theme (void)
1274
 
{
1275
 
  return cursor_theme;
1276
 
}
1277
 
 
1278
 
int
1279
 
meta_prefs_get_cursor_size (void)
1280
 
{
1281
 
  return cursor_size;
1282
 
}
1283
 
 
1284
 
 
1285
 
/****************************************************************************/
1286
 
/* Handlers for string preferences.                                         */
1287
 
/****************************************************************************/
1288
 
 
1289
 
#ifdef HAVE_GCONF
1290
 
 
1291
 
static void
1292
 
titlebar_handler (MetaPreference pref,
1293
 
                  const gchar    *string_value,
1294
 
                  gboolean       *inform_listeners)
1295
 
{
1296
 
  PangoFontDescription *new_desc = NULL;
1297
 
 
1298
 
  if (string_value)
1299
 
    new_desc = pango_font_description_from_string (string_value);
1300
 
 
1301
 
  if (new_desc == NULL)
1302
 
    {
1303
 
      meta_warning (_("Could not parse font description "
1304
 
                      "\"%s\" from GConf key %s\n"),
1305
 
                    string_value ? string_value : "(null)",
1306
 
                    KEY_TITLEBAR_FONT);
1307
 
 
1308
 
      *inform_listeners = FALSE;
1309
 
 
1310
 
      return;
1311
 
    }
1312
 
 
1313
 
  /* Is the new description the same as the old? */
1314
 
 
1315
 
  if (titlebar_font &&
1316
 
      pango_font_description_equal (new_desc, titlebar_font))
1317
 
    {
1318
 
      pango_font_description_free (new_desc);
1319
 
      *inform_listeners = FALSE;
1320
 
      return;
1321
 
    }
1322
 
 
1323
 
  /* No, so free the old one and put ours in instead. */
1324
 
 
1325
 
  if (titlebar_font)
1326
 
    pango_font_description_free (titlebar_font);
1327
 
 
1328
 
  titlebar_font = new_desc;
1329
 
 
1330
 
}
1331
 
 
1332
 
static void
1333
 
theme_name_handler (MetaPreference pref,
1334
 
                    const gchar *string_value,
1335
 
                    gboolean *inform_listeners)
1336
 
{
1337
 
  g_free (current_theme);
1338
 
 
1339
 
  /* Fallback crackrock */
1340
 
  if (string_value == NULL)
1341
 
    current_theme = g_strdup ("Atlanta");
1342
 
  else
1343
 
    current_theme = g_strdup (string_value);
1344
 
}
1345
 
 
1346
 
static void
1347
 
mouse_button_mods_handler (MetaPreference pref,
1348
 
                           const gchar *string_value,
1349
 
                           gboolean *inform_listeners)
1350
 
{
1351
 
  MetaVirtualModifier mods;
1352
 
 
1353
 
  meta_topic (META_DEBUG_KEYBINDINGS,
1354
 
              "Mouse button modifier has new gconf value \"%s\"\n",
1355
 
              string_value);
1356
 
  if (string_value && meta_ui_parse_modifier (string_value, &mods))
1357
 
    {
1358
 
      mouse_button_mods = mods;
1359
 
    }
1360
 
  else
1361
 
    {
1362
 
      meta_topic (META_DEBUG_KEYBINDINGS,
1363
 
                  "Failed to parse new gconf value\n");
1364
 
          
1365
 
      meta_warning (_("\"%s\" found in configuration database is "
1366
 
                      "not a valid value for mouse button modifier\n"),
1367
 
                    string_value);
1368
 
 
1369
 
      *inform_listeners = FALSE;
1370
 
    }
1371
 
}
1372
 
 
1373
 
static gboolean
1374
 
button_layout_equal (const MetaButtonLayout *a,
1375
 
                     const MetaButtonLayout *b)
1376
 
{  
1377
 
  int i;
1378
 
 
1379
 
  i = 0;
1380
 
  while (i < MAX_BUTTONS_PER_CORNER)
1381
 
    {
1382
 
      if (a->left_buttons[i] != b->left_buttons[i])
1383
 
        return FALSE;
1384
 
      if (a->right_buttons[i] != b->right_buttons[i])
1385
 
        return FALSE;
1386
 
      if (a->left_buttons_has_spacer[i] != b->left_buttons_has_spacer[i])
1387
 
        return FALSE;
1388
 
      if (a->right_buttons_has_spacer[i] != b->right_buttons_has_spacer[i])
1389
 
        return FALSE;
1390
 
      ++i;
1391
 
    }
1392
 
 
1393
 
  return TRUE;
1394
 
}
1395
 
 
1396
 
static MetaButtonFunction
1397
 
button_function_from_string (const char *str)
1398
 
{
1399
 
  /* FIXME: gconf_string_to_enum is the obvious way to do this */
1400
 
 
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;
1415
 
  else 
1416
 
    /* don't know; give up */
1417
 
    return META_BUTTON_FUNCTION_LAST;
1418
 
}
1419
 
 
1420
 
static MetaButtonFunction
1421
 
button_opposite_function (MetaButtonFunction ofwhat)
1422
 
{
1423
 
  switch (ofwhat)
1424
 
    {
1425
 
    case META_BUTTON_FUNCTION_SHADE:
1426
 
      return META_BUTTON_FUNCTION_UNSHADE;
1427
 
    case META_BUTTON_FUNCTION_UNSHADE:
1428
 
      return META_BUTTON_FUNCTION_SHADE;
1429
 
 
1430
 
    case META_BUTTON_FUNCTION_ABOVE:
1431
 
      return META_BUTTON_FUNCTION_UNABOVE;
1432
 
    case META_BUTTON_FUNCTION_UNABOVE:
1433
 
      return META_BUTTON_FUNCTION_ABOVE;
1434
 
 
1435
 
    case META_BUTTON_FUNCTION_STICK:
1436
 
      return META_BUTTON_FUNCTION_UNSTICK;
1437
 
    case META_BUTTON_FUNCTION_UNSTICK:
1438
 
      return META_BUTTON_FUNCTION_STICK;
1439
 
 
1440
 
    default:
1441
 
      return META_BUTTON_FUNCTION_LAST;
1442
 
    }
1443
 
}
1444
 
 
1445
 
static void
1446
 
button_layout_handler (MetaPreference pref,
1447
 
                         const gchar *string_value,
1448
 
                         gboolean *inform_listeners)
1449
 
{
1450
 
  MetaButtonLayout new_layout;
1451
 
  char **sides = NULL;
1452
 
  int i;
1453
 
  
1454
 
  /* We need to ignore unknown button functions, for
1455
 
   * compat with future versions
1456
 
   */
1457
 
  
1458
 
  if (string_value)
1459
 
    sides = g_strsplit (string_value, ":", 2);
1460
 
 
1461
 
  if (sides != NULL && sides[0] != NULL)
1462
 
    {
1463
 
      char **buttons;
1464
 
      int b;
1465
 
      gboolean used[META_BUTTON_FUNCTION_LAST];
1466
 
 
1467
 
      i = 0;
1468
 
      while (i < META_BUTTON_FUNCTION_LAST)
1469
 
        {
1470
 
          used[i] = FALSE;
1471
 
          new_layout.left_buttons_has_spacer[i] = FALSE;
1472
 
          ++i;
1473
 
        }
1474
 
      
1475
 
      buttons = g_strsplit (sides[0], ",", -1);
1476
 
      i = 0;
1477
 
      b = 0;
1478
 
      while (buttons[b] != NULL)
1479
 
        {
1480
 
          MetaButtonFunction f = button_function_from_string (buttons[b]);
1481
 
          if (i > 0 && strcmp("spacer", buttons[b]) == 0)
1482
 
            {
1483
 
              new_layout.left_buttons_has_spacer[i-1] = TRUE;
1484
 
              f = button_opposite_function (f);
1485
 
 
1486
 
              if (f != META_BUTTON_FUNCTION_LAST)
1487
 
                {
1488
 
                  new_layout.left_buttons_has_spacer[i-2] = TRUE;
1489
 
                }
1490
 
            }
1491
 
          else
1492
 
            {
1493
 
              if (f != META_BUTTON_FUNCTION_LAST && !used[f])
1494
 
                {
1495
 
                  new_layout.left_buttons[i] = f;
1496
 
                  used[f] = TRUE;
1497
 
                  ++i;
1498
 
 
1499
 
                  f = button_opposite_function (f);
1500
 
 
1501
 
                  if (f != META_BUTTON_FUNCTION_LAST)
1502
 
                      new_layout.left_buttons[i++] = f;
1503
 
 
1504
 
                }
1505
 
              else
1506
 
                {
1507
 
                  meta_topic (META_DEBUG_PREFS, "Ignoring unknown or already-used button name \"%s\"\n",
1508
 
                              buttons[b]);
1509
 
                }
1510
 
            }
1511
 
          
1512
 
          ++b;
1513
 
        }
1514
 
 
1515
 
      new_layout.left_buttons[i] = META_BUTTON_FUNCTION_LAST;
1516
 
      new_layout.left_buttons_has_spacer[i] = FALSE;
1517
 
      
1518
 
      g_strfreev (buttons);
1519
 
    }
1520
 
 
1521
 
  if (sides != NULL && sides[0] != NULL && sides[1] != NULL)
1522
 
    {
1523
 
      char **buttons;
1524
 
      int b;
1525
 
      gboolean used[META_BUTTON_FUNCTION_LAST];
1526
 
 
1527
 
      i = 0;
1528
 
      while (i < META_BUTTON_FUNCTION_LAST)
1529
 
        {
1530
 
          used[i] = FALSE;
1531
 
          new_layout.right_buttons_has_spacer[i] = FALSE;
1532
 
          ++i;
1533
 
        }
1534
 
      
1535
 
      buttons = g_strsplit (sides[1], ",", -1);
1536
 
      i = 0;
1537
 
      b = 0;
1538
 
      while (buttons[b] != NULL)
1539
 
        {
1540
 
          MetaButtonFunction f = button_function_from_string (buttons[b]);
1541
 
          if (i > 0 && strcmp("spacer", buttons[b]) == 0)
1542
 
            {
1543
 
              new_layout.right_buttons_has_spacer[i-1] = TRUE;
1544
 
              f = button_opposite_function (f);
1545
 
              if (f != META_BUTTON_FUNCTION_LAST)
1546
 
                {
1547
 
                  new_layout.right_buttons_has_spacer[i-2] = TRUE;
1548
 
                }
1549
 
            }
1550
 
          else
1551
 
            {
1552
 
              if (f != META_BUTTON_FUNCTION_LAST && !used[f])
1553
 
                {
1554
 
                  new_layout.right_buttons[i] = f;
1555
 
                  used[f] = TRUE;
1556
 
                  ++i;
1557
 
 
1558
 
                  f = button_opposite_function (f);
1559
 
 
1560
 
                  if (f != META_BUTTON_FUNCTION_LAST)
1561
 
                      new_layout.right_buttons[i++] = f;
1562
 
 
1563
 
                }
1564
 
              else
1565
 
                {
1566
 
                  meta_topic (META_DEBUG_PREFS, "Ignoring unknown or already-used button name \"%s\"\n",
1567
 
                              buttons[b]);
1568
 
                }
1569
 
            }
1570
 
          
1571
 
          ++b;
1572
 
        }
1573
 
 
1574
 
      new_layout.right_buttons[i] = META_BUTTON_FUNCTION_LAST;
1575
 
      new_layout.right_buttons_has_spacer[i] = FALSE;
1576
 
      
1577
 
      g_strfreev (buttons);
1578
 
    }
1579
 
 
1580
 
  g_strfreev (sides);
1581
 
  
1582
 
  /* Invert the button layout for RTL languages */
1583
 
  if (meta_ui_get_direction() == META_UI_DIRECTION_RTL)
1584
 
  {
1585
 
    MetaButtonLayout rtl_layout;
1586
 
    int j;
1587
 
    
1588
 
    for (i = 0; new_layout.left_buttons[i] != META_BUTTON_FUNCTION_LAST; i++);
1589
 
    for (j = 0; j < i; j++)
1590
 
      {
1591
 
        rtl_layout.right_buttons[j] = new_layout.left_buttons[i - j - 1];
1592
 
        if (j == 0)
1593
 
          rtl_layout.right_buttons_has_spacer[i - 1] = new_layout.left_buttons_has_spacer[i - j - 1];
1594
 
        else
1595
 
          rtl_layout.right_buttons_has_spacer[j - 1] = new_layout.left_buttons_has_spacer[i - j - 1];
1596
 
      }
1597
 
    rtl_layout.right_buttons[j] = META_BUTTON_FUNCTION_LAST;
1598
 
    rtl_layout.right_buttons_has_spacer[j] = FALSE;
1599
 
      
1600
 
    for (i = 0; new_layout.right_buttons[i] != META_BUTTON_FUNCTION_LAST; i++);
1601
 
    for (j = 0; j < i; j++)
1602
 
      {
1603
 
        rtl_layout.left_buttons[j] = new_layout.right_buttons[i - j - 1];
1604
 
        if (j == 0)
1605
 
          rtl_layout.left_buttons_has_spacer[i - 1] = new_layout.right_buttons_has_spacer[i - j - 1];
1606
 
        else
1607
 
          rtl_layout.left_buttons_has_spacer[j - 1] = new_layout.right_buttons_has_spacer[i - j - 1];
1608
 
      }
1609
 
    rtl_layout.left_buttons[j] = META_BUTTON_FUNCTION_LAST;
1610
 
    rtl_layout.left_buttons_has_spacer[j] = FALSE;
1611
 
 
1612
 
    new_layout = rtl_layout;
1613
 
  }
1614
 
  
1615
 
  if (button_layout_equal (&button_layout, &new_layout))
1616
 
    {
1617
 
      /* Same as before, so duck out */
1618
 
      *inform_listeners = FALSE;
1619
 
    }
1620
 
  else
1621
 
    {
1622
 
      button_layout = new_layout;
1623
 
    }
1624
 
}
1625
 
 
1626
 
#endif /* HAVE_GCONF */
1627
 
 
1628
 
const PangoFontDescription*
1629
 
meta_prefs_get_titlebar_font (void)
1630
 
{
1631
 
  if (use_system_font)
1632
 
    return NULL;
1633
 
  else
1634
 
    return titlebar_font;
1635
 
}
1636
 
 
1637
 
int
1638
 
meta_prefs_get_num_workspaces (void)
1639
 
{
1640
 
  return num_workspaces;
1641
 
}
1642
 
 
1643
 
gboolean
1644
 
meta_prefs_get_application_based (void)
1645
 
{
1646
 
  return FALSE; /* For now, we never want this to do anything */
1647
 
  
1648
 
  return application_based;
1649
 
}
1650
 
 
1651
 
gboolean
1652
 
meta_prefs_get_disable_workarounds (void)
1653
 
{
1654
 
  return disable_workarounds;
1655
 
}
1656
 
 
1657
 
#ifdef HAVE_GCONF
1658
 
#define MAX_REASONABLE_AUTO_RAISE_DELAY 10000
1659
 
  
1660
 
#endif /* HAVE_GCONF */
1661
 
 
1662
 
#ifdef WITH_VERBOSE_MODE
1663
 
const char*
1664
 
meta_preference_to_string (MetaPreference pref)
1665
 
{
1666
 
  /* FIXME: another case for gconf_string_to_enum */
1667
 
  switch (pref)
1668
 
    {
1669
 
    case META_PREF_MOUSE_BUTTON_MODS:
1670
 
      return "MOUSE_BUTTON_MODS";
1671
 
 
1672
 
    case META_PREF_FOCUS_MODE:
1673
 
      return "FOCUS_MODE";
1674
 
 
1675
 
    case META_PREF_FOCUS_NEW_WINDOWS:
1676
 
      return "FOCUS_NEW_WINDOWS";
1677
 
 
1678
 
    case META_PREF_RAISE_ON_CLICK:
1679
 
      return "RAISE_ON_CLICK";
1680
 
      
1681
 
    case META_PREF_THEME:
1682
 
      return "THEME";
1683
 
 
1684
 
    case META_PREF_TITLEBAR_FONT:
1685
 
      return "TITLEBAR_FONT";
1686
 
 
1687
 
    case META_PREF_NUM_WORKSPACES:
1688
 
      return "NUM_WORKSPACES";
1689
 
 
1690
 
    case META_PREF_APPLICATION_BASED:
1691
 
      return "APPLICATION_BASED";
1692
 
 
1693
 
    case META_PREF_KEYBINDINGS:
1694
 
      return "KEYBINDINGS";
1695
 
 
1696
 
    case META_PREF_DISABLE_WORKAROUNDS:
1697
 
      return "DISABLE_WORKAROUNDS";
1698
 
 
1699
 
    case META_PREF_ACTION_DOUBLE_CLICK_TITLEBAR:
1700
 
      return "ACTION_DOUBLE_CLICK_TITLEBAR";
1701
 
 
1702
 
    case META_PREF_ACTION_MIDDLE_CLICK_TITLEBAR:
1703
 
      return "ACTION_MIDDLE_CLICK_TITLEBAR";
1704
 
 
1705
 
    case META_PREF_ACTION_RIGHT_CLICK_TITLEBAR:
1706
 
      return "ACTION_RIGHT_CLICK_TITLEBAR";
1707
 
 
1708
 
    case META_PREF_AUTO_RAISE:
1709
 
      return "AUTO_RAISE";
1710
 
      
1711
 
    case META_PREF_AUTO_RAISE_DELAY:
1712
 
      return "AUTO_RAISE_DELAY";
1713
 
 
1714
 
    case META_PREF_COMMANDS:
1715
 
      return "COMMANDS";
1716
 
 
1717
 
    case META_PREF_TERMINAL_COMMAND:
1718
 
      return "TERMINAL_COMMAND";
1719
 
 
1720
 
    case META_PREF_BUTTON_LAYOUT:
1721
 
      return "BUTTON_LAYOUT";
1722
 
 
1723
 
    case META_PREF_WORKSPACE_NAMES:
1724
 
      return "WORKSPACE_NAMES";
1725
 
 
1726
 
    case META_PREF_VISUAL_BELL:
1727
 
      return "VISUAL_BELL";
1728
 
 
1729
 
    case META_PREF_AUDIBLE_BELL:
1730
 
      return "AUDIBLE_BELL";
1731
 
 
1732
 
    case META_PREF_VISUAL_BELL_TYPE:
1733
 
      return "VISUAL_BELL_TYPE";
1734
 
 
1735
 
    case META_PREF_REDUCED_RESOURCES:
1736
 
      return "REDUCED_RESOURCES";
1737
 
 
1738
 
    case META_PREF_GNOME_ACCESSIBILITY:
1739
 
      return "GNOME_ACCESSIBILTY";
1740
 
 
1741
 
    case META_PREF_GNOME_ANIMATIONS:
1742
 
      return "GNOME_ANIMATIONS";
1743
 
 
1744
 
    case META_PREF_CURSOR_THEME:
1745
 
      return "CURSOR_THEME";
1746
 
 
1747
 
    case META_PREF_CURSOR_SIZE:
1748
 
      return "CURSOR_SIZE";
1749
 
 
1750
 
    case META_PREF_COMPOSITING_MANAGER:
1751
 
      return "COMPOSITING_MANAGER";
1752
 
 
1753
 
    case META_PREF_RESIZE_WITH_RIGHT_BUTTON:
1754
 
      return "RESIZE_WITH_RIGHT_BUTTON";
1755
 
 
1756
 
    case META_PREF_FORCE_FULLSCREEN:
1757
 
      return "FORCE_FULLSCREEN";
1758
 
    }
1759
 
 
1760
 
  return "(unknown)";
1761
 
}
1762
 
#endif /* WITH_VERBOSE_MODE */
1763
 
 
1764
 
void
1765
 
meta_prefs_set_num_workspaces (int n_workspaces)
1766
 
{
1767
 
#ifdef HAVE_GCONF
1768
 
  GError *err;
1769
 
  
1770
 
  if (default_client == NULL)
1771
 
    return;
1772
 
 
1773
 
  if (n_workspaces < 1)
1774
 
    n_workspaces = 1;
1775
 
  if (n_workspaces > MAX_REASONABLE_WORKSPACES)
1776
 
    n_workspaces = MAX_REASONABLE_WORKSPACES;
1777
 
  
1778
 
  err = NULL;
1779
 
  gconf_client_set_int (default_client,
1780
 
                        KEY_NUM_WORKSPACES,
1781
 
                        n_workspaces,
1782
 
                        &err);
1783
 
 
1784
 
  if (err)
1785
 
    {
1786
 
      meta_warning (_("Error setting number of workspaces to %d: %s\n"),
1787
 
                    num_workspaces,
1788
 
                    err->message);
1789
 
      g_error_free (err);
1790
 
    }
1791
 
#endif /* HAVE_GCONF */
1792
 
}
1793
 
 
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 }
1799
 
};
1800
 
#undef keybind
1801
 
 
1802
 
#ifndef HAVE_GCONF
1803
 
 
1804
 
/**
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.
1809
 
 */
1810
 
typedef struct
1811
 
{
1812
 
  const char *name;
1813
 
  const char *keybinding;
1814
 
} MetaSimpleKeyMapping;
1815
 
 
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.
1822
 
 */
1823
 
 
1824
 
#define keybind(name, handler, param, flags, stroke, description) \
1825
 
  { #name, stroke },
1826
 
 
1827
 
static MetaSimpleKeyMapping key_string_bindings[] = {
1828
 
#include "all-keybindings.h"
1829
 
  { NULL, NULL }
1830
 
};
1831
 
#undef keybind
1832
 
 
1833
 
#endif /* NOT HAVE_GCONF */
1834
 
 
1835
 
static void
1836
 
init_bindings (void)
1837
 
{
1838
 
#ifdef HAVE_GCONF
1839
 
  const char *prefix[] = {
1840
 
    KEY_WINDOW_BINDINGS_PREFIX,
1841
 
    KEY_SCREEN_BINDINGS_PREFIX,
1842
 
    NULL
1843
 
  };
1844
 
  int i;
1845
 
  GSList *list, *l, *list_val;
1846
 
  const char *str_val;
1847
 
  const char *key;
1848
 
  GConfEntry *entry;
1849
 
  GConfValue *value;
1850
 
 
1851
 
  for (i = 0; prefix[i]; i++)
1852
 
    {
1853
 
      list = gconf_client_all_entries (default_client, prefix[i], NULL);
1854
 
      for (l = list; l; l = l->next)
1855
 
        {
1856
 
          entry = l->data;
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))
1860
 
            {
1861
 
              list_val = gconf_client_get_list (default_client, key, GCONF_VALUE_STRING, NULL);
1862
 
 
1863
 
              update_key_list_binding (key, list_val);
1864
 
              g_slist_foreach (list_val, (GFunc)g_free, NULL);
1865
 
              g_slist_free (list_val);
1866
 
            }
1867
 
          else
1868
 
            {
1869
 
              str_val = gconf_value_get_string (value);
1870
 
              update_key_binding (key, str_val);
1871
 
            }
1872
 
          gconf_entry_free (entry);
1873
 
        }
1874
 
      g_slist_free (list);
1875
 
    }
1876
 
#else /* HAVE_GCONF */
1877
 
  int i = 0;
1878
 
  int which = 0;
1879
 
  while (key_string_bindings[i].name)
1880
 
    {
1881
 
      if (key_string_bindings[i].keybinding == NULL) {
1882
 
        ++i;
1883
 
        continue;
1884
 
      }
1885
 
    
1886
 
      while (strcmp(key_bindings[which].name, 
1887
 
                    key_string_bindings[i].name) != 0)
1888
 
        which++;
1889
 
 
1890
 
      /* Set the binding */
1891
 
      update_binding (&key_bindings[which], 
1892
 
                      key_string_bindings[i].keybinding);
1893
 
 
1894
 
      ++i;
1895
 
    }
1896
 
#endif /* HAVE_GCONF */
1897
 
}
1898
 
 
1899
 
static void
1900
 
init_commands (void)
1901
 
{
1902
 
#ifdef HAVE_GCONF
1903
 
  GSList *list, *l;
1904
 
  const char *str_val;
1905
 
  const char *key;
1906
 
  GConfEntry *entry;
1907
 
  GConfValue *value;
1908
 
 
1909
 
  list = gconf_client_all_entries (default_client, KEY_COMMAND_DIRECTORY, NULL);
1910
 
  for (l = list; l; l = l->next)
1911
 
    {
1912
 
      entry = l->data;
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);
1918
 
    }
1919
 
  g_slist_free (list);
1920
 
#else
1921
 
  int i;
1922
 
  for (i = 0; i < MAX_COMMANDS; i++)
1923
 
    commands[i] = NULL;
1924
 
#endif /* HAVE_GCONF */
1925
 
}
1926
 
 
1927
 
static void
1928
 
init_workspace_names (void)
1929
 
{
1930
 
  int i;
1931
 
  for (i = 0; i < MAX_REASONABLE_WORKSPACES; i++)
1932
 
    workspace_names[i] = NULL;
1933
 
 
1934
 
#ifdef HAVE_GCONF
1935
 
  GSList *list, *l;
1936
 
  const char *str_val;
1937
 
  const char *key;
1938
 
  GConfEntry *entry;
1939
 
  GConfValue *value;
1940
 
 
1941
 
  list = gconf_client_all_entries (default_client, KEY_WORKSPACE_NAME_DIRECTORY, NULL);
1942
 
  for (l = list; l; l = l->next)
1943
 
    {
1944
 
      entry = l->data;
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);
1950
 
    }
1951
 
  g_slist_free (list);
1952
 
#endif /* HAVE_GCONF */
1953
 
 
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);
1958
 
 
1959
 
  meta_topic (META_DEBUG_PREFS,
1960
 
              "Initialized workspace names\n");
1961
 
}
1962
 
 
1963
 
static gboolean
1964
 
update_binding (MetaKeyPref *binding,
1965
 
                const char  *value)
1966
 
{
1967
 
  unsigned int keysym;
1968
 
  unsigned int keycode;
1969
 
  MetaVirtualModifier mods;
1970
 
  MetaKeyCombo *combo;
1971
 
  gboolean changed;
1972
 
 
1973
 
  meta_topic (META_DEBUG_KEYBINDINGS,
1974
 
              "Binding \"%s\" has new gconf value \"%s\"\n",
1975
 
              binding->name, value ? value : "none");
1976
 
  
1977
 
  keysym = 0;
1978
 
  keycode = 0;
1979
 
  mods = 0;
1980
 
  if (value)
1981
 
    {
1982
 
      if (!meta_ui_parse_accelerator (value, &keysym, &keycode, &mods))
1983
 
        {
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);
1988
 
 
1989
 
          return FALSE;
1990
 
        }
1991
 
    }
1992
 
 
1993
 
  /* If there isn't already a first element, make one. */
1994
 
  if (!binding->bindings)
1995
 
    {
1996
 
      MetaKeyCombo *blank = g_malloc0 (sizeof (MetaKeyCombo));
1997
 
      binding->bindings = g_slist_alloc();
1998
 
      binding->bindings->data = blank;
1999
 
    }
2000
 
  
2001
 
   combo = binding->bindings->data;
2002
 
 
2003
 
#ifdef HAVE_GCONF
2004
 
   /* Bug 329676: Bindings which can be shifted must not have no modifiers,
2005
 
    * nor only SHIFT as a modifier.
2006
 
    */
2007
 
 
2008
 
  if (binding->add_shift &&
2009
 
      0 != keysym &&
2010
 
      (META_VIRTUAL_SHIFT_MASK == mods || 0 == mods))
2011
 
    {
2012
 
      gchar *old_setting;
2013
 
      gchar *key;
2014
 
      GError *err = NULL;
2015
 
      
2016
 
      meta_warning ("Cannot bind \"%s\" to %s: it needs a modifier "
2017
 
                    "such as Ctrl or Alt.\n",
2018
 
                    binding->name,
2019
 
                    value);
2020
 
 
2021
 
      old_setting = meta_ui_accelerator_name (combo->keysym,
2022
 
                                              combo->modifiers);
2023
 
 
2024
 
      if (!strcmp(old_setting, value))
2025
 
        {
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.
2031
 
           */
2032
 
           g_free (old_setting);
2033
 
           return TRUE;
2034
 
        }
2035
 
 
2036
 
      meta_warning ("Reverting \"%s\" to %s.\n",
2037
 
                    binding->name,
2038
 
                    old_setting);
2039
 
 
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
2043
 
       * onto here.
2044
 
       */
2045
 
      key = g_strconcat (KEY_SCREEN_BINDINGS_PREFIX, "/",
2046
 
                         binding->name, NULL);
2047
 
      
2048
 
      gconf_client_set_string (gconf_client_get_default (),
2049
 
                               key, old_setting, &err);
2050
 
 
2051
 
      if (err)
2052
 
        {
2053
 
          meta_warning ("Error while reverting keybinding: %s\n",
2054
 
                        err->message);
2055
 
          g_error_free (err);
2056
 
          err = NULL;
2057
 
        }
2058
 
      
2059
 
      g_free (old_setting);
2060
 
      g_free (key);
2061
 
 
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
2064
 
       * carry on.
2065
 
       */
2066
 
      return TRUE;
2067
 
    }
2068
 
#endif
2069
 
  
2070
 
  changed = FALSE;
2071
 
  if (keysym != combo->keysym ||
2072
 
      keycode != combo->keycode ||
2073
 
      mods != combo->modifiers)
2074
 
    {
2075
 
      changed = TRUE;
2076
 
      
2077
 
      combo->keysym = keysym;
2078
 
      combo->keycode = keycode;
2079
 
      combo->modifiers = mods;
2080
 
      
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,
2084
 
                  combo->modifiers);
2085
 
    }
2086
 
  else
2087
 
    {
2088
 
      meta_topic (META_DEBUG_KEYBINDINGS,
2089
 
                  "Keybinding for \"%s\" is unchanged\n", binding->name);
2090
 
    }
2091
 
  
2092
 
  return changed;
2093
 
}
2094
 
 
2095
 
#ifdef HAVE_GCONF
2096
 
static gboolean
2097
 
update_list_binding (MetaKeyPref *binding,
2098
 
                     GSList      *value,
2099
 
                     MetaStringListType type_of_value)
2100
 
{
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;
2108
 
 
2109
 
  meta_topic (META_DEBUG_KEYBINDINGS,
2110
 
              "Binding \"%s\" has new gconf value\n",
2111
 
              binding->name);
2112
 
  
2113
 
  if (binding->bindings == NULL)
2114
 
    {
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.
2118
 
       */
2119
 
      MetaKeyCombo *blank = g_malloc0 (sizeof (MetaKeyCombo));
2120
 
      binding->bindings = g_slist_alloc();
2121
 
      binding->bindings->data = blank;
2122
 
    }
2123
 
       
2124
 
  /* Okay, so, we're about to provide a new list of key combos for this
2125
 
   * action. Delete any pre-existing list.
2126
 
   */
2127
 
  tmp = binding->bindings->next;
2128
 
  while (tmp)
2129
 
    {
2130
 
      g_free (tmp->data);
2131
 
      tmp = tmp->next;
2132
 
    }
2133
 
  g_slist_free (binding->bindings->next);
2134
 
  binding->bindings->next = NULL;
2135
 
  
2136
 
  while (pref_iterator)
2137
 
    {
2138
 
      keysym = 0;
2139
 
      keycode = 0;
2140
 
      mods = 0;
2141
 
 
2142
 
      if (!pref_iterator->data)
2143
 
        {
2144
 
          pref_iterator = pref_iterator->next;
2145
 
          continue;
2146
 
        }
2147
 
 
2148
 
      switch (type_of_value)
2149
 
        {
2150
 
        case META_LIST_OF_STRINGS:
2151
 
          pref_string = pref_iterator->data;
2152
 
          break;
2153
 
        case META_LIST_OF_GCONFVALUE_STRINGS:
2154
 
          pref_string = gconf_value_get_string (pref_iterator->data);
2155
 
          break;
2156
 
        default:
2157
 
          g_assert_not_reached ();
2158
 
        }
2159
 
      
2160
 
      if (!meta_ui_parse_accelerator (pref_string, &keysym, &keycode, &mods))
2161
 
        {
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);
2166
 
 
2167
 
          /* Should we remove this value from the list in gconf? */
2168
 
          pref_iterator = pref_iterator->next;
2169
 
          continue;
2170
 
        }
2171
 
 
2172
 
      /* Bug 329676: Bindings which can be shifted must not have no modifiers,
2173
 
       * nor only SHIFT as a modifier.
2174
 
       */
2175
 
 
2176
 
      if (binding->add_shift &&
2177
 
          0 != keysym &&
2178
 
          (META_VIRTUAL_SHIFT_MASK == mods || 0 == mods))
2179
 
        {
2180
 
          meta_warning ("Cannot bind \"%s\" to %s: it needs a modifier "
2181
 
                        "such as Ctrl or Alt.\n",
2182
 
                        binding->name,
2183
 
                        pref_string);
2184
 
 
2185
 
          /* Should we remove this value from the list in gconf? */
2186
 
 
2187
 
          pref_iterator = pref_iterator->next;
2188
 
          continue;
2189
 
        }
2190
 
  
2191
 
      changed = TRUE;
2192
 
 
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);
2198
 
 
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);
2202
 
 
2203
 
      pref_iterator = pref_iterator->next;
2204
 
    }  
2205
 
  return changed;
2206
 
}
2207
 
 
2208
 
static const gchar*
2209
 
relative_key (const gchar* key)
2210
 
{
2211
 
  const gchar* end;
2212
 
  
2213
 
  end = strrchr (key, '/');
2214
 
 
2215
 
  ++end;
2216
 
 
2217
 
  return end;
2218
 
}
2219
 
 
2220
 
/* Return value is TRUE if a preference changed and we need to
2221
 
 * notify
2222
 
 */
2223
 
static gboolean
2224
 
find_and_update_binding (MetaKeyPref *bindings, 
2225
 
                         const char  *name,
2226
 
                         const char  *value)
2227
 
{
2228
 
  const char *key;
2229
 
  int i;
2230
 
  
2231
 
  if (*name == '/')
2232
 
    key = relative_key (name);
2233
 
  else
2234
 
    key = name;
2235
 
 
2236
 
  i = 0;
2237
 
  while (bindings[i].name &&
2238
 
         strcmp (key, bindings[i].name) != 0)
2239
 
    ++i;
2240
 
 
2241
 
  if (bindings[i].name)
2242
 
    return update_binding (&bindings[i], value);
2243
 
  else
2244
 
    return FALSE;
2245
 
}
2246
 
 
2247
 
static gboolean
2248
 
update_key_binding (const char *name,
2249
 
                       const char *value)
2250
 
{
2251
 
  return find_and_update_binding (key_bindings, name, value);
2252
 
}
2253
 
 
2254
 
static gboolean
2255
 
find_and_update_list_binding (MetaKeyPref *bindings,
2256
 
                              const char  *name,
2257
 
                              GSList      *value)
2258
 
{
2259
 
  const char *key;
2260
 
  int i;
2261
 
  gchar *name_without_suffix = g_strdup(name);
2262
 
 
2263
 
  name_without_suffix[strlen(name_without_suffix) - strlen(KEY_LIST_BINDINGS_SUFFIX)] = 0;
2264
 
 
2265
 
  if (*name_without_suffix == '/')
2266
 
    key = relative_key (name_without_suffix);
2267
 
  else
2268
 
    key = name_without_suffix;
2269
 
 
2270
 
  i = 0;
2271
 
  while (bindings[i].name &&
2272
 
         strcmp (key, bindings[i].name) != 0)
2273
 
    ++i;
2274
 
 
2275
 
  g_free (name_without_suffix);
2276
 
 
2277
 
  if (bindings[i].name)
2278
 
    return update_list_binding (&bindings[i], value, META_LIST_OF_GCONFVALUE_STRINGS);
2279
 
  else
2280
 
    return FALSE;
2281
 
}
2282
 
 
2283
 
static gboolean
2284
 
update_key_list_binding (const char *name,
2285
 
                            GSList *value)
2286
 
{
2287
 
  return find_and_update_list_binding (key_bindings, name, value);
2288
 
}
2289
 
 
2290
 
static gboolean
2291
 
update_command (const char  *name,
2292
 
                const char  *value)
2293
 
{
2294
 
  char *p;
2295
 
  int i;
2296
 
  
2297
 
  p = strrchr (name, '_');
2298
 
  if (p == NULL)
2299
 
    {
2300
 
      meta_topic (META_DEBUG_KEYBINDINGS,
2301
 
                  "Command %s has no underscore?\n", name);
2302
 
      return FALSE;
2303
 
    }
2304
 
  
2305
 
  ++p;
2306
 
 
2307
 
  if (g_ascii_isdigit (*p))
2308
 
    {
2309
 
      i = atoi (p);
2310
 
      i -= 1; /* count from 0 not 1 */
2311
 
    }
2312
 
  else
2313
 
    {
2314
 
      p = strrchr (name, '/');
2315
 
      ++p;
2316
 
 
2317
 
      if (strcmp (p, "command_screenshot") == 0)
2318
 
        {
2319
 
          i = SCREENSHOT_COMMAND_IDX;
2320
 
        }
2321
 
      else if (strcmp (p, "command_window_screenshot") == 0)
2322
 
        {
2323
 
          i = WIN_SCREENSHOT_COMMAND_IDX;
2324
 
        }
2325
 
      else
2326
 
        {
2327
 
          meta_topic (META_DEBUG_KEYBINDINGS,
2328
 
                      "Command %s doesn't end in number?\n", name);
2329
 
          return FALSE;
2330
 
        }
2331
 
    }
2332
 
  
2333
 
  if (i >= MAX_COMMANDS)
2334
 
    {
2335
 
      meta_topic (META_DEBUG_KEYBINDINGS,
2336
 
                  "Command %d is too highly numbered, ignoring\n", i);
2337
 
      return FALSE;
2338
 
    }
2339
 
 
2340
 
  if ((commands[i] == NULL && value == NULL) ||
2341
 
      (commands[i] && value && strcmp (commands[i], value) == 0))
2342
 
    {
2343
 
      meta_topic (META_DEBUG_KEYBINDINGS,
2344
 
                  "Command %d is unchanged\n", i);
2345
 
      return FALSE;
2346
 
    }
2347
 
  
2348
 
  g_free (commands[i]);
2349
 
  commands[i] = g_strdup (value);
2350
 
 
2351
 
  meta_topic (META_DEBUG_KEYBINDINGS,
2352
 
              "Updated command %d to \"%s\"\n",
2353
 
              i, commands[i] ? commands[i] : "none");
2354
 
  
2355
 
  return TRUE;
2356
 
}
2357
 
 
2358
 
#endif /* HAVE_GCONF */
2359
 
 
2360
 
const char*
2361
 
meta_prefs_get_command (int i)
2362
 
{
2363
 
  g_return_val_if_fail (i >= 0 && i < MAX_COMMANDS, NULL);
2364
 
  
2365
 
  return commands[i];
2366
 
}
2367
 
 
2368
 
char*
2369
 
meta_prefs_get_gconf_key_for_command (int i)
2370
 
{
2371
 
  char *key;
2372
 
 
2373
 
  switch (i)
2374
 
    {
2375
 
    case SCREENSHOT_COMMAND_IDX:
2376
 
      key = g_strdup (KEY_COMMAND_PREFIX "screenshot");
2377
 
      break;
2378
 
    case WIN_SCREENSHOT_COMMAND_IDX:
2379
 
      key = g_strdup (KEY_COMMAND_PREFIX "window_screenshot");
2380
 
      break;
2381
 
    default:
2382
 
      key = g_strdup_printf (KEY_COMMAND_PREFIX"%d", i + 1);
2383
 
      break;
2384
 
    }
2385
 
  
2386
 
  return key;
2387
 
}
2388
 
 
2389
 
const char*
2390
 
meta_prefs_get_terminal_command (void)
2391
 
{
2392
 
  return terminal_command;
2393
 
}
2394
 
 
2395
 
const char*
2396
 
meta_prefs_get_gconf_key_for_terminal_command (void)
2397
 
{
2398
 
  return KEY_TERMINAL_COMMAND;
2399
 
}
2400
 
 
2401
 
#ifdef HAVE_GCONF
2402
 
static gboolean
2403
 
update_workspace_name (const char  *name,
2404
 
                       const char  *value)
2405
 
{
2406
 
  char *p;
2407
 
  int i;
2408
 
  
2409
 
  p = strrchr (name, '_');
2410
 
  if (p == NULL)
2411
 
    {
2412
 
      meta_topic (META_DEBUG_PREFS,
2413
 
                  "Workspace name %s has no underscore?\n", name);
2414
 
      return FALSE;
2415
 
    }
2416
 
  
2417
 
  ++p;
2418
 
 
2419
 
  if (!g_ascii_isdigit (*p))
2420
 
    {
2421
 
      meta_topic (META_DEBUG_PREFS,
2422
 
                  "Workspace name %s doesn't end in number?\n", name);
2423
 
      return FALSE;
2424
 
    }
2425
 
  
2426
 
  i = atoi (p);
2427
 
  i -= 1; /* count from 0 not 1 */
2428
 
  
2429
 
  if (i >= MAX_REASONABLE_WORKSPACES)
2430
 
    {
2431
 
      meta_topic (META_DEBUG_PREFS,
2432
 
                  "Workspace name %d is too highly numbered, ignoring\n", i);
2433
 
      return FALSE;
2434
 
    }
2435
 
 
2436
 
  if (workspace_names[i] && value && strcmp (workspace_names[i], value) == 0)
2437
 
    {
2438
 
      meta_topic (META_DEBUG_PREFS,
2439
 
                  "Workspace name %d is unchanged\n", i);
2440
 
      return FALSE;
2441
 
    }  
2442
 
 
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".
2448
 
   */
2449
 
  if (value != NULL && *value != '\0')
2450
 
    {
2451
 
      g_free (workspace_names[i]);
2452
 
      workspace_names[i] = g_strdup (value);
2453
 
    }
2454
 
  else
2455
 
    {
2456
 
      /* use a default name */
2457
 
      char *d;
2458
 
 
2459
 
      d = g_strdup_printf (_("Workspace %d"), i + 1);
2460
 
      if (workspace_names[i] && strcmp (workspace_names[i], d) == 0)
2461
 
        {
2462
 
          g_free (d);
2463
 
          return FALSE;
2464
 
        }
2465
 
      else
2466
 
        {
2467
 
          g_free (workspace_names[i]);
2468
 
          workspace_names[i] = d;
2469
 
        }
2470
 
    }
2471
 
  
2472
 
  meta_topic (META_DEBUG_PREFS,
2473
 
              "Updated workspace name %d to \"%s\"\n",
2474
 
              i, workspace_names[i] ? workspace_names[i] : "none");
2475
 
  
2476
 
  return TRUE;
2477
 
}
2478
 
#endif /* HAVE_GCONF */
2479
 
 
2480
 
const char*
2481
 
meta_prefs_get_workspace_name (int i)
2482
 
{
2483
 
  g_return_val_if_fail (i >= 0 && i < MAX_REASONABLE_WORKSPACES, NULL);
2484
 
 
2485
 
  g_assert (workspace_names[i] != NULL);
2486
 
 
2487
 
  meta_topic (META_DEBUG_PREFS,
2488
 
              "Getting workspace name for %d: \"%s\"\n",
2489
 
              i, workspace_names[i]);
2490
 
  
2491
 
  return workspace_names[i];
2492
 
}
2493
 
 
2494
 
void
2495
 
meta_prefs_change_workspace_name (int         i,
2496
 
                                  const char *name)
2497
 
{
2498
 
#ifdef HAVE_GCONF
2499
 
  char *key;
2500
 
  GError *err;
2501
 
  
2502
 
  g_return_if_fail (i >= 0 && i < MAX_REASONABLE_WORKSPACES);
2503
 
 
2504
 
  meta_topic (META_DEBUG_PREFS,
2505
 
              "Changing name of workspace %d to %s\n",
2506
 
              i, name ? name : "none");
2507
 
 
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".
2513
 
   */
2514
 
  if (name && *name == '\0')
2515
 
    name = NULL;
2516
 
  
2517
 
  if ((name == NULL && workspace_names[i] == NULL) ||
2518
 
      (name && workspace_names[i] && strcmp (name, workspace_names[i]) == 0))
2519
 
    {
2520
 
      meta_topic (META_DEBUG_PREFS,
2521
 
                  "Workspace %d already has name %s\n",
2522
 
                  i, name ? name : "none");
2523
 
      return;
2524
 
    }
2525
 
  
2526
 
  key = gconf_key_for_workspace_name (i);
2527
 
 
2528
 
  err = NULL;
2529
 
  if (name != NULL)
2530
 
    gconf_client_set_string (default_client,
2531
 
                             key, name,
2532
 
                             &err);
2533
 
  else
2534
 
    gconf_client_unset (default_client,
2535
 
                        key, &err);
2536
 
 
2537
 
  
2538
 
  if (err)
2539
 
    {
2540
 
      meta_warning (_("Error setting name for workspace %d to \"%s\": %s\n"),
2541
 
                    i, name ? name : "none",
2542
 
                    err->message);
2543
 
      g_error_free (err);
2544
 
    }
2545
 
  
2546
 
  g_free (key);
2547
 
#else
2548
 
  g_free (workspace_names[i]);
2549
 
  workspace_names[i] = g_strdup (name);
2550
 
#endif /* HAVE_GCONF */
2551
 
}
2552
 
 
2553
 
#ifdef HAVE_GCONF
2554
 
static char*
2555
 
gconf_key_for_workspace_name (int i)
2556
 
{
2557
 
  char *key;
2558
 
  
2559
 
  key = g_strdup_printf (KEY_WORKSPACE_NAME_PREFIX"%d", i + 1);
2560
 
  
2561
 
  return key;
2562
 
}
2563
 
#endif /* HAVE_GCONF */
2564
 
 
2565
 
void
2566
 
meta_prefs_get_button_layout (MetaButtonLayout *button_layout_p)
2567
 
{
2568
 
  *button_layout_p = button_layout;
2569
 
}
2570
 
 
2571
 
gboolean
2572
 
meta_prefs_get_visual_bell (void)
2573
 
{
2574
 
  return provide_visual_bell;
2575
 
}
2576
 
 
2577
 
gboolean
2578
 
meta_prefs_bell_is_audible (void)
2579
 
{
2580
 
  return bell_is_audible;
2581
 
}
2582
 
 
2583
 
MetaVisualBellType
2584
 
meta_prefs_get_visual_bell_type (void)
2585
 
{
2586
 
  return visual_bell_type;
2587
 
}
2588
 
 
2589
 
void
2590
 
meta_prefs_get_key_bindings (const MetaKeyPref **bindings,
2591
 
                                int                *n_bindings)
2592
 
{
2593
 
  
2594
 
  *bindings = key_bindings;
2595
 
  *n_bindings = (int) G_N_ELEMENTS (key_bindings) - 1;
2596
 
}
2597
 
 
2598
 
MetaActionTitlebar
2599
 
meta_prefs_get_action_double_click_titlebar (void)
2600
 
{
2601
 
  return action_double_click_titlebar;
2602
 
}
2603
 
 
2604
 
MetaActionTitlebar
2605
 
meta_prefs_get_action_middle_click_titlebar (void)
2606
 
{
2607
 
  return action_middle_click_titlebar;
2608
 
}
2609
 
 
2610
 
MetaActionTitlebar
2611
 
meta_prefs_get_action_right_click_titlebar (void)
2612
 
{
2613
 
  return action_right_click_titlebar;
2614
 
}
2615
 
 
2616
 
gboolean
2617
 
meta_prefs_get_auto_raise (void)
2618
 
{
2619
 
  return auto_raise;
2620
 
}
2621
 
 
2622
 
int
2623
 
meta_prefs_get_auto_raise_delay (void)
2624
 
{
2625
 
  return auto_raise_delay;
2626
 
}
2627
 
 
2628
 
gboolean
2629
 
meta_prefs_get_reduced_resources (void)
2630
 
{
2631
 
  return reduced_resources;
2632
 
}
2633
 
 
2634
 
gboolean
2635
 
meta_prefs_get_gnome_accessibility ()
2636
 
{
2637
 
  return gnome_accessibility;
2638
 
}
2639
 
 
2640
 
gboolean
2641
 
meta_prefs_get_gnome_animations ()
2642
 
{
2643
 
  return gnome_animations;
2644
 
}
2645
 
 
2646
 
MetaKeyBindingAction
2647
 
meta_prefs_get_keybinding_action (const char *name)
2648
 
{
2649
 
  int i;
2650
 
 
2651
 
  i = G_N_ELEMENTS (key_bindings) - 2; /* -2 for dummy entry at end */
2652
 
  while (i >= 0)
2653
 
    {
2654
 
      if (strcmp (key_bindings[i].name, name) == 0)
2655
 
        return (MetaKeyBindingAction) i;
2656
 
      
2657
 
      --i;
2658
 
    }
2659
 
 
2660
 
  return META_KEYBINDING_ACTION_NONE;
2661
 
}
2662
 
 
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
2665
 
 * binding, if any.
2666
 
 */
2667
 
void
2668
 
meta_prefs_get_window_binding (const char          *name,
2669
 
                               unsigned int        *keysym,
2670
 
                               MetaVirtualModifier *modifiers)
2671
 
{
2672
 
  int i;
2673
 
 
2674
 
  i = G_N_ELEMENTS (key_bindings) - 2; /* -2 for dummy entry at end */
2675
 
  while (i >= 0)
2676
 
    {
2677
 
      if (key_bindings[i].per_window &&
2678
 
          strcmp (key_bindings[i].name, name) == 0)
2679
 
        {
2680
 
          GSList *s = key_bindings[i].bindings;
2681
 
 
2682
 
          while (s)
2683
 
            {
2684
 
              MetaKeyCombo *c = s->data;
2685
 
 
2686
 
              if (c->keysym!=0 || c->modifiers!=0)
2687
 
                {
2688
 
                  *keysym = c->keysym;
2689
 
                  *modifiers = c->modifiers;
2690
 
                  return;
2691
 
                }
2692
 
 
2693
 
              s = s->next;
2694
 
            }
2695
 
 
2696
 
          /* Not found; return the disabled value */
2697
 
          *keysym = *modifiers = 0;
2698
 
          return;
2699
 
        }
2700
 
      
2701
 
      --i;
2702
 
    }
2703
 
 
2704
 
  g_assert_not_reached ();
2705
 
}
2706
 
 
2707
 
gboolean
2708
 
meta_prefs_get_compositing_manager (void)
2709
 
{
2710
 
  return compositing_manager;
2711
 
}
2712
 
 
2713
 
guint
2714
 
meta_prefs_get_mouse_button_resize (void)
2715
 
{
2716
 
  return resize_with_right_button ? 3: 2;
2717
 
}
2718
 
 
2719
 
guint
2720
 
meta_prefs_get_mouse_button_menu (void)
2721
 
{
2722
 
  return resize_with_right_button ? 2: 3;
2723
 
}
2724
 
 
2725
 
gboolean
2726
 
meta_prefs_get_force_fullscreen (void)
2727
 
{
2728
 
  return force_fullscreen;
2729
 
}
2730
 
 
2731
 
void
2732
 
meta_prefs_set_compositing_manager (gboolean whether)
2733
 
{
2734
 
#ifdef HAVE_GCONF
2735
 
  GError *err = NULL;
2736
 
 
2737
 
  gconf_client_set_bool (default_client,
2738
 
                         KEY_COMPOSITOR,
2739
 
                         whether,
2740
 
                         &err);
2741
 
 
2742
 
  if (err)
2743
 
    {
2744
 
      meta_warning (_("Error setting compositor status: %s\n"),
2745
 
                    err->message);
2746
 
      g_error_free (err);
2747
 
    }
2748
 
#else
2749
 
  compositing_manager = whether;
2750
 
#endif
2751
 
}
2752
 
 
2753
 
#ifndef HAVE_GCONF
2754
 
static void
2755
 
init_button_layout(void)
2756
 
{
2757
 
  MetaButtonLayout button_layout_ltr = {
2758
 
    {    
2759
 
      /* buttons in the group on the left side */
2760
 
      META_BUTTON_FUNCTION_MENU,
2761
 
      META_BUTTON_FUNCTION_LAST
2762
 
    },
2763
 
    {
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
2769
 
    }
2770
 
  };
2771
 
  MetaButtonLayout button_layout_rtl = {
2772
 
    {    
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
2778
 
    },
2779
 
    {
2780
 
      /* buttons in the group on the right side */
2781
 
      META_BUTTON_FUNCTION_MENU,
2782
 
      META_BUTTON_FUNCTION_LAST
2783
 
    }
2784
 
  };
2785
 
 
2786
 
  button_layout = meta_ui_get_direction() == META_UI_DIRECTION_LTR ?
2787
 
    button_layout_ltr : button_layout_rtl;
2788
 
};
2789
 
 
2790
 
#endif
2791
 
 
2792
 
void
2793
 
meta_prefs_set_force_fullscreen (gboolean whether)
2794
 
{
2795
 
  force_fullscreen = whether;
2796
 
}
2797