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

« back to all changes in this revision

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