prefs.c

Go to the documentation of this file.
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
00002 
00003 /* Metacity preferences */
00004 
00005 /* 
00006  * Copyright (C) 2001 Havoc Pennington, Copyright (C) 2002 Red Hat Inc.
00007  * Copyright (C) 2006 Elijah Newren
00008  * Copyright (C) 2008 Thomas Thurman
00009  * 
00010  * This program is free software; you can redistribute it and/or
00011  * modify it under the terms of the GNU General Public License as
00012  * published by the Free Software Foundation; either version 2 of the
00013  * License, or (at your option) any later version.
00014  *
00015  * This program is distributed in the hope that it will be useful, but
00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018  * General Public License for more details.
00019  * 
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program; if not, write to the Free Software
00022  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
00023  * 02111-1307, USA.
00024  */
00025 
00026 #include <config.h>
00027 #include "prefs.h"
00028 #include "ui.h"
00029 #include "util.h"
00030 #ifdef HAVE_GCONF
00031 #include <gconf/gconf-client.h>
00032 #endif
00033 #include <string.h>
00034 #include <stdlib.h>
00035 
00036 #define MAX_REASONABLE_WORKSPACES 36
00037 
00038 #define MAX_COMMANDS (32 + NUM_EXTRA_COMMANDS)
00039 #define NUM_EXTRA_COMMANDS 2
00040 #define SCREENSHOT_COMMAND_IDX (MAX_COMMANDS - 2)
00041 #define WIN_SCREENSHOT_COMMAND_IDX (MAX_COMMANDS - 1)
00042 
00043 /* If you add a key, it needs updating in init() and in the gconf
00044  * notify listener and of course in the .schemas file.
00045  *
00046  * Keys which are handled by one of the unified handlers below are
00047  * not given a name here, because the purpose of the unified handlers
00048  * is that keys should be referred to exactly once.
00049  */
00050 #define KEY_TITLEBAR_FONT "/apps/metacity/general/titlebar_font"
00051 #define KEY_NUM_WORKSPACES "/apps/metacity/general/num_workspaces"
00052 #define KEY_GNOME_ACCESSIBILITY "/desktop/gnome/interface/accessibility"
00053 
00054 #define KEY_COMMAND_PREFIX "/apps/metacity/keybinding_commands/command_"
00055 
00056 #define KEY_TERMINAL_DIR "/desktop/gnome/applications/terminal"
00057 #define KEY_TERMINAL_COMMAND KEY_TERMINAL_DIR "/exec"
00058 
00059 #define KEY_SCREEN_BINDINGS_PREFIX "/apps/metacity/global_keybindings"
00060 #define KEY_WINDOW_BINDINGS_PREFIX "/apps/metacity/window_keybindings"
00061 #define KEY_LIST_BINDINGS_SUFFIX "_list"
00062 
00063 #define KEY_WORKSPACE_NAME_PREFIX "/apps/metacity/workspace_names/name_"
00064 
00065 
00066 #ifdef HAVE_GCONF
00067 static GConfClient *default_client = NULL;
00068 static GList *changes = NULL;
00069 static guint changed_idle;
00070 #endif
00071 static GList *listeners = NULL;
00072 
00073 static gboolean use_system_font = FALSE;
00074 static PangoFontDescription *titlebar_font = NULL;
00075 static MetaVirtualModifier mouse_button_mods = Mod1Mask;
00076 static MetaFocusMode focus_mode = META_FOCUS_MODE_CLICK;
00077 static MetaFocusNewWindows focus_new_windows = META_FOCUS_NEW_WINDOWS_SMART;
00078 static gboolean raise_on_click = TRUE;
00079 static char* current_theme = NULL;
00080 static int num_workspaces = 4;
00081 static MetaActionTitlebar action_double_click_titlebar = META_ACTION_TITLEBAR_TOGGLE_MAXIMIZE;
00082 static MetaActionTitlebar action_middle_click_titlebar = META_ACTION_TITLEBAR_LOWER;
00083 static MetaActionTitlebar action_right_click_titlebar = META_ACTION_TITLEBAR_MENU;
00084 static gboolean application_based = FALSE;
00085 static gboolean disable_workarounds = FALSE;
00086 static gboolean auto_raise = FALSE;
00087 static gboolean auto_raise_delay = 500;
00088 static gboolean provide_visual_bell = FALSE;
00089 static gboolean bell_is_audible = TRUE;
00090 static gboolean reduced_resources = FALSE;
00091 static gboolean gnome_accessibility = FALSE;
00092 static gboolean gnome_animations = TRUE;
00093 static char *cursor_theme = NULL;
00094 static int   cursor_size = 24;
00095 static gboolean compositing_manager = FALSE;
00096 
00097 static MetaVisualBellType visual_bell_type = META_VISUAL_BELL_FULLSCREEN_FLASH;
00098 static MetaButtonLayout button_layout;
00099 
00100 /* The screenshot commands are at the end */
00101 static char *commands[MAX_COMMANDS] = { NULL, };
00102 
00103 static char *terminal_command = NULL;
00104 
00105 static char *workspace_names[MAX_REASONABLE_WORKSPACES] = { NULL, };
00106 
00107 #ifdef HAVE_GCONF
00108 static gboolean handle_preference_update_enum (const gchar *key, GConfValue *value);
00109 
00110 static gboolean update_window_binding     (const char *name,
00111                                            const char *value);
00112 static gboolean update_screen_binding     (const char *name,
00113                                            const char *value);
00114 static gboolean find_and_update_list_binding (MetaKeyPref *bindings,
00115                                               const char  *name,
00116                                               GSList      *value);
00117 static gboolean update_window_list_binding (const char *name,
00118                                             GSList      *value);
00119 static gboolean update_screen_list_binding (const char *name,
00120                                             GSList      *value);
00121 static gboolean update_command            (const char  *name,
00122                                            const char  *value);
00123 static gboolean update_workspace_name     (const char  *name,
00124                                            const char  *value);
00125 
00126 static void change_notify (GConfClient    *client,
00127                            guint           cnxn_id,
00128                            GConfEntry     *entry,
00129                            gpointer        user_data);
00130 
00131 static char* gconf_key_for_workspace_name (int i);
00132 
00133 static void queue_changed (MetaPreference  pref);
00134 
00135 typedef enum
00136   {
00137     META_LIST_OF_STRINGS,
00138     META_LIST_OF_GCONFVALUE_STRINGS
00139   } MetaStringListType;
00140 
00141 static gboolean update_list_binding       (MetaKeyPref *binding,
00142                                            GSList      *value,
00143                                            MetaStringListType type_of_value);
00144 
00145 static void     cleanup_error             (GError **error);
00146 static gboolean get_bool                  (const char *key, gboolean *val);
00147 static void maybe_give_disable_workarounds_warning (void);
00148 
00149 static void titlebar_handler (MetaPreference, const gchar*, gboolean*);
00150 static void theme_name_handler (MetaPreference, const gchar*, gboolean*);
00151 static void mouse_button_mods_handler (MetaPreference, const gchar*, gboolean*);
00152 static void button_layout_handler (MetaPreference, const gchar*, gboolean*);
00153 
00154 #endif /* HAVE_GCONF */
00155 
00156 static gboolean update_binding            (MetaKeyPref *binding,
00157                                            const char  *value);
00158 
00159 static void     init_bindings             (void);
00160 static void     init_commands             (void);
00161 static void     init_workspace_names      (void);
00162 
00163 #ifndef HAVE_GCONF
00164 static void     init_button_layout        (void);
00165 #endif /* !HAVE_GCONF */
00166 
00167 #ifdef HAVE_GCONF
00168 
00169 typedef struct
00170 {
00171   MetaPrefsChangedFunc func;
00172   gpointer data;
00173 } MetaPrefsListener;
00174 
00175 static GConfEnumStringPair symtab_focus_mode[] =
00176   {
00177     { META_FOCUS_MODE_CLICK,  "click" },
00178     { META_FOCUS_MODE_SLOPPY, "sloppy" },
00179     { META_FOCUS_MODE_MOUSE,  "mouse" },
00180     { 0, NULL },
00181   };
00182 
00183 static GConfEnumStringPair symtab_focus_new_windows[] =
00184   {
00185     { META_FOCUS_NEW_WINDOWS_SMART,  "smart" },
00186     { META_FOCUS_NEW_WINDOWS_STRICT, "strict" },
00187     { 0, NULL },
00188   };
00189 
00190 static GConfEnumStringPair symtab_visual_bell_type[] =
00191   {
00192     /* Note to the reader: 0 is an invalid value; these start at 1. */
00193     { META_VISUAL_BELL_FULLSCREEN_FLASH, "fullscreen" },
00194     { META_VISUAL_BELL_FRAME_FLASH,      "frame_flash" },
00195     { 0, NULL },
00196   };
00197 
00198 static GConfEnumStringPair symtab_titlebar_action[] =
00199   {
00200     { META_ACTION_TITLEBAR_TOGGLE_SHADE,    "toggle_shade" },
00201     { META_ACTION_TITLEBAR_TOGGLE_MAXIMIZE, "toggle_maximize" },
00202     { META_ACTION_TITLEBAR_TOGGLE_MAXIMIZE_HORIZONTALLY,
00203                                 "toggle_maximize_horizontally" },
00204     { META_ACTION_TITLEBAR_TOGGLE_MAXIMIZE_VERTICALLY,
00205                                 "toggle_maximize_vertically" },
00206     { META_ACTION_TITLEBAR_MINIMIZE,        "minimize" },
00207     { META_ACTION_TITLEBAR_NONE,            "none" },
00208     { META_ACTION_TITLEBAR_LOWER,           "lower" },
00209     { META_ACTION_TITLEBAR_MENU,            "menu" },
00210     { META_ACTION_TITLEBAR_TOGGLE_SHADE,    "toggle_shade" },
00211     { 0, NULL },
00212   };
00213 
00243 typedef struct
00244 {
00245   gchar *key;
00246   MetaPreference pref;
00247   GConfEnumStringPair *symtab;
00248   gpointer target;
00249 } MetaEnumPreference;
00250 
00251 typedef struct
00252 {
00253   gchar *key;
00254   MetaPreference pref;
00255   gboolean *target;
00256   gboolean becomes_true_on_destruction;
00257 } MetaBoolPreference;
00258 
00259 typedef struct
00260 {
00261   gchar *key;
00262   MetaPreference pref;
00263 
00278   void (*handler) (MetaPreference pref,
00279                      const gchar *string_value,
00280                      gboolean *inform_listeners);
00281 
00288   gchar **target;
00289 
00290 } MetaStringPreference;
00291 
00292 #define METAINTPREFERENCE_NO_CHANGE_ON_DESTROY G_MININT
00293 
00294 typedef struct
00295 {
00296   gchar *key;
00297   MetaPreference pref;
00298   gint *target;
00303   gint minimum, maximum;
00309   gint value_if_destroyed;
00310 } MetaIntPreference;
00311 
00312 /* FIXMEs: */
00313 /* @@@ Don't use NULL lines at the end; glib can tell you how big it is */
00314 /* @@@ /apps/metacity/general should be assumed if first char is not / */
00315 /* @@@ Will it ever be possible to merge init and update? If not, why not? */
00316 
00317 static MetaEnumPreference preferences_enum[] =
00318   {
00319     { "/apps/metacity/general/focus_new_windows",
00320       META_PREF_FOCUS_NEW_WINDOWS,
00321       symtab_focus_new_windows,
00322       &focus_new_windows,
00323     },
00324     { "/apps/metacity/general/focus_mode",
00325       META_PREF_FOCUS_MODE,
00326       symtab_focus_mode,
00327       &focus_mode,
00328     },
00329     { "/apps/metacity/general/visual_bell_type",
00330       META_PREF_VISUAL_BELL_TYPE,
00331       symtab_visual_bell_type,
00332       &visual_bell_type,
00333     },
00334     { "/apps/metacity/general/action_double_click_titlebar",
00335       META_PREF_ACTION_DOUBLE_CLICK_TITLEBAR,
00336       symtab_titlebar_action,
00337       &action_double_click_titlebar,
00338     },
00339     { "/apps/metacity/general/action_middle_click_titlebar",
00340       META_PREF_ACTION_MIDDLE_CLICK_TITLEBAR,
00341       symtab_titlebar_action,
00342       &action_middle_click_titlebar,
00343     },
00344     { "/apps/metacity/general/action_right_click_titlebar",
00345       META_PREF_ACTION_RIGHT_CLICK_TITLEBAR,
00346       symtab_titlebar_action,
00347       &action_right_click_titlebar,
00348     },
00349     { NULL, 0, NULL, NULL },
00350   };
00351 
00352 static MetaBoolPreference preferences_bool[] =
00353   {
00354     { "/apps/metacity/general/raise_on_click",
00355       META_PREF_RAISE_ON_CLICK,
00356       &raise_on_click,
00357       TRUE,
00358     },
00359     { "/apps/metacity/general/titlebar_uses_system_font",
00360       META_PREF_TITLEBAR_FONT, /* note! shares a pref */
00361       &use_system_font,
00362       TRUE,
00363     },
00364     { "/apps/metacity/general/application_based",
00365       META_PREF_APPLICATION_BASED,
00366       NULL, /* feature is known but disabled */
00367       FALSE,
00368     },
00369     { "/apps/metacity/general/disable_workarounds",
00370       META_PREF_DISABLE_WORKAROUNDS,
00371       &disable_workarounds,
00372       FALSE,
00373     },
00374     { "/apps/metacity/general/auto_raise",
00375       META_PREF_AUTO_RAISE,
00376       &auto_raise,
00377       FALSE,
00378     },
00379     { "/apps/metacity/general/visual_bell",
00380       META_PREF_VISUAL_BELL,
00381       &provide_visual_bell, /* FIXME: change the name: it's confusing */
00382       FALSE,
00383     },
00384     { "/apps/metacity/general/audible_bell",
00385       META_PREF_AUDIBLE_BELL,
00386       &bell_is_audible, /* FIXME: change the name: it's confusing */
00387       FALSE,
00388     },
00389     { "/apps/metacity/general/reduced_resources",
00390       META_PREF_REDUCED_RESOURCES,
00391       &reduced_resources,
00392       FALSE,
00393     },
00394     { "/desktop/gnome/interface/accessibility",
00395       META_PREF_GNOME_ACCESSIBILITY,
00396       &gnome_accessibility,
00397       FALSE,
00398     },
00399     { "/desktop/gnome/interface/enable_animations",
00400       META_PREF_GNOME_ANIMATIONS,
00401       &gnome_animations,
00402       TRUE,
00403     },
00404     { "/apps/metacity/general/compositing_manager",
00405       META_PREF_COMPOSITING_MANAGER,
00406       &compositing_manager,
00407       FALSE,
00408     },
00409     { NULL, 0, NULL, FALSE },
00410   };
00411 
00412 static MetaStringPreference preferences_string[] =
00413   {
00414     { "/apps/metacity/general/mouse_button_modifier",
00415       META_PREF_MOUSE_BUTTON_MODS,
00416       mouse_button_mods_handler,
00417       NULL,
00418     },
00419     { "/apps/metacity/general/theme",
00420       META_PREF_THEME,
00421       theme_name_handler,
00422       NULL,
00423     },
00424     { KEY_TITLEBAR_FONT,
00425       META_PREF_TITLEBAR_FONT,
00426       titlebar_handler,
00427       NULL,
00428     },
00429     { KEY_TERMINAL_COMMAND,
00430       META_PREF_TERMINAL_COMMAND,
00431       NULL,
00432       &terminal_command,
00433     },
00434     { "/apps/metacity/general/button_layout",
00435       META_PREF_BUTTON_LAYOUT,
00436       button_layout_handler,
00437       NULL,
00438     },
00439     { "/desktop/gnome/peripherals/mouse/cursor_theme",
00440       META_PREF_CURSOR_THEME,
00441       NULL,
00442       &cursor_theme,
00443     },
00444     { NULL, 0, NULL, NULL },
00445   };
00446 
00447 static MetaIntPreference preferences_int[] =
00448   {
00449     { "/apps/metacity/general/num_workspaces",
00450       META_PREF_NUM_WORKSPACES,
00451       &num_workspaces,
00452       /* I would actually recommend we change the destroy value to 4
00453        * and get rid of METAINTPREFERENCE_NO_CHANGE_ON_DESTROY entirely.
00454        *  -- tthurman
00455        */
00456       1, MAX_REASONABLE_WORKSPACES, METAINTPREFERENCE_NO_CHANGE_ON_DESTROY,
00457     },
00458     { "/apps/metacity/general/auto_raise_delay",
00459       META_PREF_AUTO_RAISE_DELAY,
00460       &auto_raise_delay,
00461       0, 10000, 0,
00462       /* @@@ Get rid of MAX_REASONABLE_AUTO_RAISE_DELAY */
00463     },
00464     { "/desktop/gnome/peripherals/mouse/cursor_size",
00465       META_PREF_CURSOR_SIZE,
00466       &cursor_size,
00467       1, 128, 24,
00468     },
00469     { NULL, 0, NULL, 0, 0, 0, },
00470   };
00471 
00472 static void
00473 handle_preference_init_enum (void)
00474 {
00475   MetaEnumPreference *cursor = preferences_enum;
00476 
00477   while (cursor->key!=NULL)
00478     {
00479       char *value;
00480       GError *error = NULL;
00481 
00482       if (cursor->target==NULL)
00483         {
00484           ++cursor;
00485           continue;
00486         }
00487 
00488       value = gconf_client_get_string (default_client,
00489                                        cursor->key,
00490                                        &error);
00491       cleanup_error (&error);
00492 
00493       if (value==NULL)
00494         {
00495           ++cursor;
00496           continue;
00497         }
00498 
00499       if (!gconf_string_to_enum (cursor->symtab,
00500                                  value,
00501                                  (gint *) cursor->target))
00502         meta_warning (_("GConf key '%s' is set to an invalid value\n"),
00503                       cursor->key);
00504 
00505       g_free (value);
00506 
00507       ++cursor;
00508     }
00509 }
00510 
00511 static void
00512 handle_preference_init_bool (void)
00513 {
00514   MetaBoolPreference *cursor = preferences_bool;
00515 
00516   while (cursor->key!=NULL)
00517     {
00518       if (cursor->target!=NULL)
00519         get_bool (cursor->key, cursor->target);
00520 
00521       ++cursor;
00522     }
00523 
00524   maybe_give_disable_workarounds_warning ();
00525 }
00526 
00527 static void
00528 handle_preference_init_string (void)
00529 {
00530   MetaStringPreference *cursor = preferences_string;
00531 
00532   while (cursor->key!=NULL)
00533     {
00534       char *value;
00535       GError *error = NULL;
00536       gboolean dummy = TRUE;
00537 
00538       /* the string "value" will be newly allocated */
00539       value = gconf_client_get_string (default_client,
00540                                        cursor->key,
00541                                        &error);
00542       cleanup_error (&error);
00543 
00544       if (cursor->handler)
00545         {
00546           if (cursor->target)
00547             meta_bug ("%s has both a target and a handler\n", cursor->key);
00548 
00549           cursor->handler (cursor->pref, value, &dummy);
00550 
00551           g_free (value);
00552         }
00553       else if (cursor->target)
00554         {
00555           if (*(cursor->target))
00556             g_free (*(cursor->target));
00557 
00558           *(cursor->target) = value;
00559         }
00560 
00561       ++cursor;
00562     }
00563 }
00564 
00565 static void
00566 handle_preference_init_int (void)
00567 {
00568   MetaIntPreference *cursor = preferences_int;
00569 
00570   
00571   while (cursor->key!=NULL)
00572     {
00573       gint value;
00574       GError *error = NULL;
00575 
00576       value = gconf_client_get_int (default_client,
00577                                     cursor->key,
00578                                     &error);
00579       cleanup_error (&error);
00580 
00581       if (value < cursor->minimum || value > cursor->maximum)
00582         {
00583           meta_warning (_("%d stored in GConf key %s is out of range %d to %d\n"),
00584                         value, cursor->key,  cursor->minimum, cursor->maximum);
00585           /* Former behaviour for out-of-range values was:
00586            *   - number of workspaces was clamped;
00587            *   - auto raise delay was always reset to zero even if too high!;
00588            *   - cursor size was ignored.
00589            *
00590            * These seem to be meaningless variations.  If they did
00591            * have meaning we could have put them into MetaIntPreference.
00592            * The last of these is the closest to how we behave for
00593            * other types, so I think we should standardise on that.
00594            */
00595         }
00596       else if (cursor->target)
00597         *cursor->target = value;
00598 
00599       ++cursor;
00600     }
00601 }
00602 
00603 static gboolean
00604 handle_preference_update_enum (const gchar *key, GConfValue *value)
00605 {
00606   MetaEnumPreference *cursor = preferences_enum;
00607   gint old_value;
00608 
00609   while (cursor->key!=NULL && strcmp (key, cursor->key)!=0)
00610     ++cursor;
00611 
00612   if (cursor->key==NULL)
00613     /* Didn't recognise that key. */
00614     return FALSE;
00615       
00616   /* Setting it to null (that is, removing it) always means
00617    * "don't change".
00618    */
00619 
00620   if (value==NULL)
00621     return TRUE;
00622 
00623   /* Check the type.  Enums are always strings. */
00624 
00625   if (value->type != GCONF_VALUE_STRING)
00626     {
00627       meta_warning (_("GConf key \"%s\" is set to an invalid type\n"),
00628                     key);
00629       /* But we did recognise it. */
00630       return TRUE;
00631     }
00632 
00633   /* We need to know whether the value changes, so
00634    * store the current value away.
00635    */
00636 
00637   old_value = * ((gint *) cursor->target);
00638   
00639   /* Now look it up... */
00640 
00641   if (!gconf_string_to_enum (cursor->symtab,
00642                              gconf_value_get_string (value),
00643                              (gint *) cursor->target))
00644     {
00645       /*
00646        * We found it, but it was invalid.  Complain.
00647        *
00648        * FIXME: This replicates the original behaviour, but in the future
00649        * we might consider reverting invalid keys to their original values.
00650        * (We know the old value, so we can look up a suitable string in
00651        * the symtab.)
00652        */
00653       
00654       meta_warning (_("GConf key '%s' is set to an invalid value\n"),
00655                     key);
00656       return TRUE;
00657     }
00658 
00659   /* Did it change?  If so, tell the listeners about it. */
00660 
00661   if (old_value != *((gint *) cursor->target))
00662     queue_changed (cursor->pref);
00663 
00664   return TRUE;
00665 }
00666 
00667 static gboolean
00668 handle_preference_update_bool (const gchar *key, GConfValue *value)
00669 {
00670   MetaBoolPreference *cursor = preferences_bool;
00671   gboolean old_value;
00672 
00673   while (cursor->key!=NULL && strcmp (key, cursor->key)!=0)
00674     ++cursor;
00675 
00676   if (cursor->key==NULL)
00677     /* Didn't recognise that key. */
00678     return FALSE;
00679 
00680   if (cursor->target==NULL)
00681     /* No work for us to do. */
00682     return TRUE;
00683       
00684   if (value==NULL)
00685     {
00686       /* Value was destroyed; let's get out of here. */
00687 
00688       if (cursor->becomes_true_on_destruction)
00689         /* This preserves the behaviour of the old system, but
00690          * for all I know that might have been an oversight.
00691          */
00692         *((gboolean *)cursor->target) = TRUE;
00693 
00694       return TRUE;
00695     }
00696 
00697   /* Check the type. */
00698 
00699   if (value->type != GCONF_VALUE_BOOL)
00700     {
00701       meta_warning (_("GConf key \"%s\" is set to an invalid type\n"),
00702                     key);
00703       /* But we did recognise it. */
00704       return TRUE;
00705     }
00706 
00707   /* We need to know whether the value changes, so
00708    * store the current value away.
00709    */
00710 
00711   old_value = * ((gboolean *) cursor->target);
00712   
00713   /* Now look it up... */
00714 
00715   *((gboolean *) cursor->target) = gconf_value_get_bool (value);
00716 
00717   /* Did it change?  If so, tell the listeners about it. */
00718 
00719   if (old_value != *((gboolean *) cursor->target))
00720     queue_changed (cursor->pref);
00721 
00722   if (cursor->pref==META_PREF_DISABLE_WORKAROUNDS)
00723     maybe_give_disable_workarounds_warning ();
00724 
00725   return TRUE;
00726 }
00727 
00728 static gboolean
00729 handle_preference_update_string (const gchar *key, GConfValue *value)
00730 {
00731   MetaStringPreference *cursor = preferences_string;
00732   const gchar *value_as_string;
00733   gboolean inform_listeners = TRUE;
00734 
00735   while (cursor->key!=NULL && strcmp (key, cursor->key)!=0)
00736     ++cursor;
00737 
00738   if (cursor->key==NULL)
00739     /* Didn't recognise that key. */
00740     return FALSE;
00741 
00742   if (value==NULL)
00743     return TRUE;
00744 
00745   /* Check the type. */
00746 
00747   if (value->type != GCONF_VALUE_STRING)
00748     {
00749       meta_warning (_("GConf key \"%s\" is set to an invalid type\n"),
00750                     key);
00751       /* But we did recognise it. */
00752       return TRUE;
00753     }
00754 
00755   /* Docs: "The returned string is not a copy, don't try to free it." */
00756   value_as_string = gconf_value_get_string (value);
00757 
00758   if (cursor->handler)
00759     cursor->handler (cursor->pref, value_as_string, &inform_listeners);
00760   else if (cursor->target)
00761     {
00762       if (*(cursor->target))
00763         g_free(*(cursor->target));
00764 
00765       if (value_as_string!=NULL)
00766         *(cursor->target) = g_strdup (value_as_string);
00767       else
00768         *(cursor->target) = NULL;
00769 
00770       inform_listeners =
00771         (value_as_string==NULL && *(cursor->target)==NULL) ||
00772         (value_as_string!=NULL && *(cursor->target)!=NULL &&
00773          strcmp (value_as_string, *(cursor->target))==0);
00774     }
00775 
00776   if (inform_listeners)
00777     queue_changed (cursor->pref);
00778 
00779   return TRUE;
00780 }
00781 
00782 static gboolean
00783 handle_preference_update_int (const gchar *key, GConfValue *value)
00784 {
00785   MetaIntPreference *cursor = preferences_int;
00786   gint new_value;
00787 
00788   while (cursor->key!=NULL && strcmp (key, cursor->key)!=0)
00789     ++cursor;
00790 
00791   if (cursor->key==NULL)
00792     /* Didn't recognise that key. */
00793     return FALSE;
00794 
00795   if (cursor->target==NULL)
00796     /* No work for us to do. */
00797     return TRUE;
00798       
00799   if (value==NULL)
00800     {
00801       /* Value was destroyed. */
00802 
00803       if (cursor->value_if_destroyed != METAINTPREFERENCE_NO_CHANGE_ON_DESTROY)
00804         *((gint *)cursor->target) = cursor->value_if_destroyed;
00805 
00806       return TRUE;
00807     }
00808 
00809   /* Check the type. */
00810 
00811   if (value->type != GCONF_VALUE_INT)
00812     {
00813       meta_warning (_("GConf key \"%s\" is set to an invalid type\n"),
00814                     key);
00815       /* But we did recognise it. */
00816       return TRUE;
00817     }
00818 
00819   new_value = gconf_value_get_int (value);
00820 
00821   if (new_value < cursor->minimum || new_value > cursor->maximum)
00822     {
00823       meta_warning (_("%d stored in GConf key %s is out of range %d to %d\n"),
00824                     new_value, cursor->key,
00825                     cursor->minimum, cursor->maximum);
00826       return TRUE;
00827     }
00828 
00829   /* Did it change?  If so, tell the listeners about it. */
00830 
00831   if (*cursor->target != new_value)
00832     {
00833       *cursor->target = new_value;
00834       queue_changed (cursor->pref);
00835     }
00836 
00837   return TRUE;
00838   
00839 }
00840 
00841 
00842 /****************************************************************************/
00843 /* Listeners.                                                               */
00844 /****************************************************************************/
00845 
00846 void
00847 meta_prefs_add_listener (MetaPrefsChangedFunc func,
00848                          gpointer             data)
00849 {
00850   MetaPrefsListener *l;
00851 
00852   l = g_new (MetaPrefsListener, 1);
00853   l->func = func;
00854   l->data = data;
00855 
00856   listeners = g_list_prepend (listeners, l);
00857 }
00858 
00859 void
00860 meta_prefs_remove_listener (MetaPrefsChangedFunc func,
00861                             gpointer             data)
00862 {
00863   GList *tmp;
00864 
00865   tmp = listeners;
00866   while (tmp != NULL)
00867     {
00868       MetaPrefsListener *l = tmp->data;
00869 
00870       if (l->func == func &&
00871           l->data == data)
00872         {
00873           g_free (l);
00874           listeners = g_list_delete_link (listeners, tmp);
00875 
00876           return;
00877         }
00878       
00879       tmp = tmp->next;
00880     }
00881 
00882   meta_bug ("Did not find listener to remove\n");
00883 }
00884 
00885 static void
00886 emit_changed (MetaPreference pref)
00887 {
00888   GList *tmp;
00889   GList *copy;
00890 
00891   meta_topic (META_DEBUG_PREFS, "Notifying listeners that pref %s changed\n",
00892               meta_preference_to_string (pref));
00893   
00894   copy = g_list_copy (listeners);
00895   
00896   tmp = copy;
00897 
00898   while (tmp != NULL)
00899     {
00900       MetaPrefsListener *l = tmp->data;
00901 
00902       (* l->func) (pref, l->data);
00903 
00904       tmp = tmp->next;
00905     }
00906 
00907   g_list_free (copy);
00908 }
00909 
00910 static gboolean
00911 changed_idle_handler (gpointer data)
00912 {
00913   GList *tmp;
00914   GList *copy;
00915 
00916   changed_idle = 0;
00917   
00918   copy = g_list_copy (changes); /* reentrancy paranoia */
00919 
00920   g_list_free (changes);
00921   changes = NULL;
00922   
00923   tmp = copy;
00924   while (tmp != NULL)
00925     {
00926       MetaPreference pref = GPOINTER_TO_INT (tmp->data);
00927 
00928       emit_changed (pref);
00929       
00930       tmp = tmp->next;
00931     }
00932 
00933   g_list_free (copy);
00934   
00935   return FALSE;
00936 }
00937 
00938 static void
00939 queue_changed (MetaPreference pref)
00940 {
00941   meta_topic (META_DEBUG_PREFS, "Queueing change of pref %s\n",
00942               meta_preference_to_string (pref));  
00943 
00944   if (g_list_find (changes, GINT_TO_POINTER (pref)) == NULL)
00945     changes = g_list_prepend (changes, GINT_TO_POINTER (pref));
00946   else
00947     meta_topic (META_DEBUG_PREFS, "Change of pref %s was already pending\n",
00948                 meta_preference_to_string (pref));
00949 
00950   /* add idle at priority below the gconf notify idle */
00951   if (changed_idle == 0)
00952     changed_idle = g_idle_add_full (META_PRIORITY_PREFS_NOTIFY,
00953                                     changed_idle_handler, NULL, NULL);
00954 }
00955 
00956 #else /* HAVE_GCONF */
00957 
00958 void
00959 meta_prefs_add_listener (MetaPrefsChangedFunc func,
00960                          gpointer             data)
00961 {
00962   /* Nothing, because they have gconf turned off */
00963 }
00964 
00965 void
00966 meta_prefs_remove_listener (MetaPrefsChangedFunc func,
00967                             gpointer             data)
00968 {
00969   /* Nothing, because they have gconf turned off */
00970 }
00971 
00972 #endif /* HAVE_GCONF */
00973 
00974 
00975 /****************************************************************************/
00976 /* Initialisation.                                                          */
00977 /****************************************************************************/
00978 
00979 /* @@@ again, use glib's ability to tell you the size of the array */
00980 static gchar *gconf_dirs_we_are_interested_in[] = {
00981   "/apps/metacity",
00982   KEY_TERMINAL_DIR,
00983   KEY_GNOME_ACCESSIBILITY,
00984   "/desktop/gnome/peripherals/mouse",
00985   "/desktop/gnome/interface",
00986   NULL,
00987 };
00988 
00989 void
00990 meta_prefs_init (void)
00991 {
00992 #ifdef HAVE_GCONF
00993   GError *err = NULL;
00994   gchar **gconf_dir_cursor;
00995   
00996   if (default_client != NULL)
00997     return;
00998   
00999   /* returns a reference which we hold forever */
01000   default_client = gconf_client_get_default ();
01001 
01002   for (gconf_dir_cursor=gconf_dirs_we_are_interested_in;
01003        *gconf_dir_cursor!=NULL;
01004        gconf_dir_cursor++)
01005     {
01006       gconf_client_add_dir (default_client,
01007                             *gconf_dir_cursor,
01008                             GCONF_CLIENT_PRELOAD_RECURSIVE,
01009                             &err);
01010       cleanup_error (&err);
01011     }
01012 
01013   /* Pick up initial values. */
01014 
01015   handle_preference_init_enum ();
01016   handle_preference_init_bool ();
01017   handle_preference_init_string ();
01018   handle_preference_init_int ();
01019 
01020   /* @@@ Is there any reason we don't do the add_dir here? */
01021   for (gconf_dir_cursor=gconf_dirs_we_are_interested_in;
01022        *gconf_dir_cursor!=NULL;
01023        gconf_dir_cursor++)
01024     {
01025       gconf_client_notify_add (default_client,
01026                                *gconf_dir_cursor,
01027                                change_notify,
01028                                NULL,
01029                                NULL,
01030                                &err);
01031       cleanup_error (&err);
01032     }
01033 
01034 #else  /* HAVE_GCONF */
01035 
01036   /* Set defaults for some values that can't be set at initialization time of
01037    * the static globals.  In the case of the theme, note that there is code
01038    * elsewhere that will do everything possible to fallback to an existing theme
01039    * if the one here does not exist.
01040    */
01041   titlebar_font = pango_font_description_from_string ("Sans Bold 10");
01042   current_theme = g_strdup ("Atlanta");
01043   
01044   init_button_layout();
01045 #endif /* HAVE_GCONF */
01046   
01047   init_bindings ();
01048   init_commands ();
01049   init_workspace_names ();
01050 }
01051 
01052 
01053 /****************************************************************************/
01054 /* Updates.                                                                 */
01055 /****************************************************************************/
01056 
01057 #ifdef HAVE_GCONF
01058 
01059 gboolean (*preference_update_handler[]) (const gchar*, GConfValue*) = {
01060   handle_preference_update_enum,
01061   handle_preference_update_bool,
01062   handle_preference_update_string,
01063   handle_preference_update_int,
01064   NULL
01065 };
01066 
01067 static void
01068 change_notify (GConfClient    *client,
01069                guint           cnxn_id,
01070                GConfEntry     *entry,
01071                gpointer        user_data)
01072 {
01073   const char *key;
01074   GConfValue *value;
01075   gint i=0;
01076   
01077   key = gconf_entry_get_key (entry);
01078   value = gconf_entry_get_value (entry);
01079 
01080   /* First, search for a handler that might know what to do. */
01081 
01082   /* FIXME: When this is all working, since the first item in every
01083    * array is the gchar* of the key, there's no reason we can't
01084    * find the correct record for that key here and save code duplication.
01085    */
01086 
01087   while (preference_update_handler[i]!=NULL)
01088     {
01089       if (preference_update_handler[i] (key, value))
01090         goto out; /* Get rid of this when we're done with the if */
01091 
01092       i++;
01093     }
01094 
01095   /* Otherwise, use the enormous if statement. We'll move entries
01096    * out of here as it becomes possible to deal with them in a
01097    * more general way.
01098    */
01099 
01100   if (g_str_has_prefix (key, KEY_WINDOW_BINDINGS_PREFIX))
01101     {
01102       if (g_str_has_suffix (key, KEY_LIST_BINDINGS_SUFFIX))
01103         {
01104           GSList *list;
01105 
01106           if (value && value->type != GCONF_VALUE_LIST)
01107             {
01108               meta_warning (_("GConf key \"%s\" is set to an invalid type\n"),
01109                             key);
01110               goto out;
01111             }
01112 
01113           list = value ? gconf_value_get_list (value) : NULL;
01114 
01115           if (update_window_list_binding (key, list))
01116              queue_changed (META_PREF_WINDOW_KEYBINDINGS);
01117         }
01118       else
01119         {
01120           const char *str;
01121 
01122           if (value && value->type != GCONF_VALUE_STRING)
01123             {
01124               meta_warning (_("GConf key \"%s\" is set to an invalid type\n"),
01125                             key);
01126               goto out;
01127             }
01128 
01129           str = value ? gconf_value_get_string (value) : NULL;
01130 
01131           if (update_window_binding (key, str))
01132              queue_changed (META_PREF_WINDOW_KEYBINDINGS);
01133         }
01134     }
01135   else if (g_str_has_prefix (key, KEY_SCREEN_BINDINGS_PREFIX))
01136     {
01137       if (g_str_has_suffix (key, KEY_LIST_BINDINGS_SUFFIX))
01138         {
01139           GSList *list;
01140 
01141           if (value && value->type != GCONF_VALUE_LIST)
01142             {
01143               meta_warning (_("GConf key \"%s\" is set to an invalid type\n"),
01144                             key);
01145               goto out;
01146             }
01147 
01148           list = value ? gconf_value_get_list (value) : NULL;
01149 
01150           if (update_screen_list_binding (key, list))
01151              queue_changed (META_PREF_SCREEN_KEYBINDINGS);
01152          }
01153       else
01154         {
01155           const char *str;
01156 
01157           if (value && value->type != GCONF_VALUE_STRING)
01158             {
01159                meta_warning (_("GConf key \"%s\" is set to an invalid type\n"),
01160                             key);
01161                goto out;
01162             }
01163 
01164           str = value ? gconf_value_get_string (value) : NULL;
01165 
01166           if (update_screen_binding (key, str))
01167              queue_changed (META_PREF_SCREEN_KEYBINDINGS);
01168         }
01169     }
01170   else if (g_str_has_prefix (key, KEY_COMMAND_PREFIX))
01171     {
01172       const char *str;
01173 
01174       if (value && value->type != GCONF_VALUE_STRING)
01175         {
01176           meta_warning (_("GConf key \"%s\" is set to an invalid type\n"),
01177                         key);
01178           goto out;
01179         }
01180 
01181       str = value ? gconf_value_get_string (value) : NULL;
01182 
01183       if (update_command (key, str))
01184         queue_changed (META_PREF_COMMANDS);
01185     }
01186   else if (g_str_has_prefix (key, KEY_WORKSPACE_NAME_PREFIX))
01187     {
01188       const char *str;
01189 
01190       if (value && value->type != GCONF_VALUE_STRING)
01191         {
01192           meta_warning (_("GConf key \"%s\" is set to an invalid type\n"),
01193                         key);
01194           goto out;
01195         }
01196 
01197       str = value ? gconf_value_get_string (value) : NULL;
01198 
01199       if (update_workspace_name (key, str))
01200         queue_changed (META_PREF_WORKSPACE_NAMES);
01201     }
01202   else
01203     {
01204       meta_topic (META_DEBUG_PREFS, "Key %s doesn't mean anything to Metacity\n",
01205                   key);
01206     }
01207   
01208  out:
01209   /* nothing */
01210   return; /* AIX compiler wants something after a label like out: */
01211 }
01212 
01213 static void
01214 cleanup_error (GError **error)
01215 {
01216   if (*error)
01217     {
01218       meta_warning ("%s\n", (*error)->message);
01219       
01220       g_error_free (*error);
01221       *error = NULL;
01222     }
01223 }
01224 
01225 /* get_bool returns TRUE if *val is filled in, FALSE otherwise */
01226 /* @@@ probably worth moving this inline; only used once */
01227 static gboolean
01228 get_bool (const char *key, gboolean *val)
01229 {
01230   GError     *err = NULL;
01231   GConfValue *value;
01232   gboolean    filled_in = FALSE;
01233 
01234   value = gconf_client_get (default_client, key, &err);
01235   cleanup_error (&err);
01236   if (value)
01237     {
01238       if (value->type == GCONF_VALUE_BOOL)
01239         {
01240           *val = gconf_value_get_bool (value);
01241           filled_in = TRUE;
01242         }
01243       gconf_value_free (value);
01244     }
01245 
01246   return filled_in;
01247 }
01248 
01253 static void
01254 maybe_give_disable_workarounds_warning (void)
01255 {
01256   static gboolean first_disable = TRUE;
01257     
01258   if (first_disable && disable_workarounds)
01259     {
01260       first_disable = FALSE;
01261 
01262       meta_warning (_("Workarounds for broken applications disabled. "
01263                       "Some applications may not behave properly.\n"));
01264     }
01265 }
01266 
01267 #endif /* HAVE_GCONF */
01268 
01269 MetaVirtualModifier
01270 meta_prefs_get_mouse_button_mods  (void)
01271 {
01272   return mouse_button_mods;
01273 }
01274 
01275 MetaFocusMode
01276 meta_prefs_get_focus_mode (void)
01277 {
01278   return focus_mode;
01279 }
01280 
01281 MetaFocusNewWindows
01282 meta_prefs_get_focus_new_windows (void)
01283 {
01284   return focus_new_windows;
01285 }
01286 
01287 gboolean
01288 meta_prefs_get_raise_on_click (void)
01289 {
01290   /* Force raise_on_click on for click-to-focus, as requested by Havoc
01291    * in #326156.
01292    */
01293   return raise_on_click || focus_mode == META_FOCUS_MODE_CLICK;
01294 }
01295 
01296 const char*
01297 meta_prefs_get_theme (void)
01298 {
01299   return current_theme;
01300 }
01301 
01302 const char*
01303 meta_prefs_get_cursor_theme (void)
01304 {
01305   return cursor_theme;
01306 }
01307 
01308 int
01309 meta_prefs_get_cursor_size (void)
01310 {
01311   return cursor_size;
01312 }
01313 
01314 
01315 /****************************************************************************/
01316 /* Handlers for string preferences.                                         */
01317 /****************************************************************************/
01318 
01319 #ifdef HAVE_GCONF
01320 
01321 static void
01322 titlebar_handler (MetaPreference pref,
01323                   const gchar    *string_value,
01324                   gboolean       *inform_listeners)
01325 {
01326   PangoFontDescription *new_desc;
01327 
01328   new_desc = pango_font_description_from_string (string_value);
01329 
01330   if (new_desc == NULL)
01331     {
01332       meta_warning (_("Could not parse font description "
01333                       "\"%s\" from GConf key %s\n"),
01334                     string_value,
01335                     KEY_TITLEBAR_FONT);
01336 
01337       *inform_listeners = FALSE;
01338 
01339       return;
01340     }
01341 
01342   /* Is the new description the same as the old? */
01343 
01344   if (titlebar_font &&
01345       pango_font_description_equal (new_desc, titlebar_font))
01346     {
01347       pango_font_description_free (new_desc);
01348       *inform_listeners = FALSE;
01349       return;
01350     }
01351 
01352   /* No, so free the old one and put ours in instead. */
01353 
01354   if (titlebar_font)
01355     pango_font_description_free (titlebar_font);
01356 
01357   titlebar_font = new_desc;
01358 
01359 }
01360 
01361 static void
01362 theme_name_handler (MetaPreference pref,
01363                     const gchar *string_value,
01364                     gboolean *inform_listeners)
01365 {
01366   /* Fallback crackrock */
01367   if (string_value == NULL)
01368     current_theme = g_strdup ("Atlanta");
01369   else
01370     current_theme = g_strdup (string_value);
01371 }
01372 
01373 static void
01374 mouse_button_mods_handler (MetaPreference pref,
01375                            const gchar *string_value,
01376                            gboolean *inform_listeners)
01377 {
01378   MetaVirtualModifier mods;
01379 
01380   meta_topic (META_DEBUG_KEYBINDINGS,
01381               "Mouse button modifier has new gconf value \"%s\"\n",
01382               string_value);
01383   if (meta_ui_parse_modifier (string_value, &mods))
01384     {
01385       mouse_button_mods = mods;
01386     }
01387   else
01388     {
01389       meta_topic (META_DEBUG_KEYBINDINGS,
01390                   "Failed to parse new gconf value\n");
01391           
01392       meta_warning (_("\"%s\" found in configuration database is "
01393                       "not a valid value for mouse button modifier\n"),
01394                     string_value);
01395 
01396       *inform_listeners = FALSE;
01397     }
01398 }
01399 
01400 static gboolean
01401 button_layout_equal (const MetaButtonLayout *a,
01402                      const MetaButtonLayout *b)
01403 {  
01404   int i;
01405 
01406   i = 0;
01407   while (i < MAX_BUTTONS_PER_CORNER)
01408     {
01409       if (a->left_buttons[i] != b->left_buttons[i])
01410         return FALSE;
01411       if (a->right_buttons[i] != b->right_buttons[i])
01412         return FALSE;
01413       if (a->left_buttons_has_spacer[i] != b->left_buttons_has_spacer[i])
01414         return FALSE;
01415       if (a->right_buttons_has_spacer[i] != b->right_buttons_has_spacer[i])
01416         return FALSE;
01417       ++i;
01418     }
01419 
01420   return TRUE;
01421 }
01422 
01423 static MetaButtonFunction
01424 button_function_from_string (const char *str)
01425 {
01426   /* FIXME: gconf_string_to_enum is the obvious way to do this */
01427 
01428   if (strcmp (str, "menu") == 0)
01429     return META_BUTTON_FUNCTION_MENU;
01430   else if (strcmp (str, "minimize") == 0)
01431     return META_BUTTON_FUNCTION_MINIMIZE;
01432   else if (strcmp (str, "maximize") == 0)
01433     return META_BUTTON_FUNCTION_MAXIMIZE;
01434   else if (strcmp (str, "close") == 0)
01435     return META_BUTTON_FUNCTION_CLOSE;
01436   else if (strcmp (str, "shade") == 0)
01437     return META_BUTTON_FUNCTION_SHADE;
01438   else if (strcmp (str, "above") == 0)
01439     return META_BUTTON_FUNCTION_ABOVE;
01440   else if (strcmp (str, "stick") == 0)
01441     return META_BUTTON_FUNCTION_STICK;
01442   else 
01443     /* don't know; give up */
01444     return META_BUTTON_FUNCTION_LAST;
01445 }
01446 
01447 static MetaButtonFunction
01448 button_opposite_function (MetaButtonFunction ofwhat)
01449 {
01450   switch (ofwhat)
01451     {
01452     case META_BUTTON_FUNCTION_SHADE:
01453       return META_BUTTON_FUNCTION_UNSHADE;
01454     case META_BUTTON_FUNCTION_UNSHADE:
01455       return META_BUTTON_FUNCTION_SHADE;
01456 
01457     case META_BUTTON_FUNCTION_ABOVE:
01458       return META_BUTTON_FUNCTION_UNABOVE;
01459     case META_BUTTON_FUNCTION_UNABOVE:
01460       return META_BUTTON_FUNCTION_ABOVE;
01461 
01462     case META_BUTTON_FUNCTION_STICK:
01463       return META_BUTTON_FUNCTION_UNSTICK;
01464     case META_BUTTON_FUNCTION_UNSTICK:
01465       return META_BUTTON_FUNCTION_STICK;
01466 
01467     default:
01468       return META_BUTTON_FUNCTION_LAST;
01469     }
01470 }
01471 
01472 static void
01473 button_layout_handler (MetaPreference pref,
01474                          const gchar *string_value,
01475                          gboolean *inform_listeners)
01476 {
01477   MetaButtonLayout new_layout;
01478   char **sides;
01479   int i;
01480   
01481   /* We need to ignore unknown button functions, for
01482    * compat with future versions
01483    */
01484   
01485   sides = g_strsplit (string_value, ":", 2);
01486 
01487   if (sides[0] != NULL)
01488     {
01489       char **buttons;
01490       int b;
01491       gboolean used[META_BUTTON_FUNCTION_LAST];
01492 
01493       i = 0;
01494       while (i < META_BUTTON_FUNCTION_LAST)
01495         {
01496           used[i] = FALSE;
01497           new_layout.left_buttons_has_spacer[i] = FALSE;
01498           ++i;
01499         }
01500       
01501       buttons = g_strsplit (sides[0], ",", -1);
01502       i = 0;
01503       b = 0;
01504       while (buttons[b] != NULL)
01505         {
01506           MetaButtonFunction f = button_function_from_string (buttons[b]);
01507           if (i > 0 && strcmp("spacer", buttons[b]) == 0)
01508             {
01509               new_layout.left_buttons_has_spacer[i-1] = TRUE;
01510               f = button_opposite_function (f);
01511 
01512               if (f != META_BUTTON_FUNCTION_LAST)
01513                 {
01514                   new_layout.left_buttons_has_spacer[i-2] = TRUE;
01515                 }
01516             }
01517           else
01518             {
01519               if (f != META_BUTTON_FUNCTION_LAST && !used[f])
01520                 {
01521                   new_layout.left_buttons[i] = f;
01522                   used[f] = TRUE;
01523                   ++i;
01524 
01525                   f = button_opposite_function (f);
01526 
01527                   if (f != META_BUTTON_FUNCTION_LAST)
01528                       new_layout.left_buttons[i++] = f;
01529 
01530                 }
01531               else
01532                 {
01533                   meta_topic (META_DEBUG_PREFS, "Ignoring unknown or already-used button name \"%s\"\n",
01534                               buttons[b]);
01535                 }
01536             }
01537           
01538           ++b;
01539         }
01540 
01541       new_layout.left_buttons[i] = META_BUTTON_FUNCTION_LAST;
01542       new_layout.left_buttons_has_spacer[i] = FALSE;
01543       
01544       g_strfreev (buttons);
01545     }
01546 
01547   if (sides[0] != NULL && sides[1] != NULL)
01548     {
01549       char **buttons;
01550       int b;
01551       gboolean used[META_BUTTON_FUNCTION_LAST];
01552 
01553       i = 0;
01554       while (i < META_BUTTON_FUNCTION_LAST)
01555         {
01556           used[i] = FALSE;
01557           new_layout.right_buttons_has_spacer[i] = FALSE;
01558           ++i;
01559         }
01560       
01561       buttons = g_strsplit (sides[1], ",", -1);
01562       i = 0;
01563       b = 0;
01564       while (buttons[b] != NULL)
01565         {
01566           MetaButtonFunction f = button_function_from_string (buttons[b]);
01567           if (i > 0 && strcmp("spacer", buttons[b]) == 0)
01568             {
01569               new_layout.right_buttons_has_spacer[i-1] = TRUE;
01570               f = button_opposite_function (f);
01571               if (f != META_BUTTON_FUNCTION_LAST)
01572                 {
01573                   new_layout.right_buttons_has_spacer[i-2] = TRUE;
01574                 }
01575             }
01576           else
01577             {
01578               if (f != META_BUTTON_FUNCTION_LAST && !used[f])
01579                 {
01580                   new_layout.right_buttons[i] = f;
01581                   used[f] = TRUE;
01582                   ++i;
01583 
01584                   f = button_opposite_function (f);
01585 
01586                   if (f != META_BUTTON_FUNCTION_LAST)
01587                       new_layout.right_buttons[i++] = f;
01588 
01589                 }
01590               else
01591                 {
01592                   meta_topic (META_DEBUG_PREFS, "Ignoring unknown or already-used button name \"%s\"\n",
01593                               buttons[b]);
01594                 }
01595             }
01596           
01597           ++b;
01598         }
01599 
01600       new_layout.right_buttons[i] = META_BUTTON_FUNCTION_LAST;
01601       new_layout.right_buttons_has_spacer[i] = FALSE;
01602       
01603       g_strfreev (buttons);
01604     }
01605 
01606   g_strfreev (sides);
01607   
01608   /* Invert the button layout for RTL languages */
01609   if (meta_ui_get_direction() == META_UI_DIRECTION_RTL)
01610   {
01611     MetaButtonLayout rtl_layout;
01612     int j;
01613     
01614     for (i = 0; new_layout.left_buttons[i] != META_BUTTON_FUNCTION_LAST; i++);
01615     for (j = 0; j < i; j++)
01616       {
01617         rtl_layout.right_buttons[j] = new_layout.left_buttons[i - j - 1];
01618         if (j == 0)
01619           rtl_layout.right_buttons_has_spacer[i - 1] = new_layout.left_buttons_has_spacer[i - j - 1];
01620         else
01621           rtl_layout.right_buttons_has_spacer[j - 1] = new_layout.left_buttons_has_spacer[i - j - 1];
01622       }
01623     rtl_layout.right_buttons[j] = META_BUTTON_FUNCTION_LAST;
01624     rtl_layout.right_buttons_has_spacer[j] = FALSE;
01625       
01626     for (i = 0; new_layout.right_buttons[i] != META_BUTTON_FUNCTION_LAST; i++);
01627     for (j = 0; j < i; j++)
01628       {
01629         rtl_layout.left_buttons[j] = new_layout.right_buttons[i - j - 1];
01630         if (j == 0)
01631           rtl_layout.left_buttons_has_spacer[i - 1] = new_layout.right_buttons_has_spacer[i - j - 1];
01632         else
01633           rtl_layout.left_buttons_has_spacer[j - 1] = new_layout.right_buttons_has_spacer[i - j - 1];
01634       }
01635     rtl_layout.left_buttons[j] = META_BUTTON_FUNCTION_LAST;
01636     rtl_layout.left_buttons_has_spacer[j] = FALSE;
01637 
01638     new_layout = rtl_layout;
01639   }
01640   
01641   if (button_layout_equal (&button_layout, &new_layout))
01642     {
01643       /* Same as before, so duck out */
01644       *inform_listeners = FALSE;
01645     }
01646   else
01647     {
01648       button_layout = new_layout;
01649     }
01650 }
01651 
01652 #endif /* HAVE_GCONF */
01653 
01654 const PangoFontDescription*
01655 meta_prefs_get_titlebar_font (void)
01656 {
01657   if (use_system_font)
01658     return NULL;
01659   else
01660     return titlebar_font;
01661 }
01662 
01663 int
01664 meta_prefs_get_num_workspaces (void)
01665 {
01666   return num_workspaces;
01667 }
01668 
01669 gboolean
01670 meta_prefs_get_application_based (void)
01671 {
01672   return FALSE; /* For now, we never want this to do anything */
01673   
01674   return application_based;
01675 }
01676 
01677 gboolean
01678 meta_prefs_get_disable_workarounds (void)
01679 {
01680   return disable_workarounds;
01681 }
01682 
01683 #ifdef HAVE_GCONF
01684 #define MAX_REASONABLE_AUTO_RAISE_DELAY 10000
01685   
01686 #endif /* HAVE_GCONF */
01687 
01688 #ifdef WITH_VERBOSE_MODE
01689 const char*
01690 meta_preference_to_string (MetaPreference pref)
01691 {
01692   /* FIXME: another case for gconf_string_to_enum */
01693   switch (pref)
01694     {
01695     case META_PREF_MOUSE_BUTTON_MODS:
01696       return "MOUSE_BUTTON_MODS";
01697 
01698     case META_PREF_FOCUS_MODE:
01699       return "FOCUS_MODE";
01700 
01701     case META_PREF_FOCUS_NEW_WINDOWS:
01702       return "FOCUS_NEW_WINDOWS";
01703 
01704     case META_PREF_RAISE_ON_CLICK:
01705       return "RAISE_ON_CLICK";
01706       
01707     case META_PREF_THEME:
01708       return "THEME";
01709 
01710     case META_PREF_TITLEBAR_FONT:
01711       return "TITLEBAR_FONT";
01712 
01713     case META_PREF_NUM_WORKSPACES:
01714       return "NUM_WORKSPACES";
01715 
01716     case META_PREF_APPLICATION_BASED:
01717       return "APPLICATION_BASED";
01718 
01719     case META_PREF_SCREEN_KEYBINDINGS:
01720       return "SCREEN_KEYBINDINGS";
01721 
01722     case META_PREF_WINDOW_KEYBINDINGS:
01723       return "WINDOW_KEYBINDINGS";
01724 
01725     case META_PREF_DISABLE_WORKAROUNDS:
01726       return "DISABLE_WORKAROUNDS";
01727 
01728     case META_PREF_ACTION_DOUBLE_CLICK_TITLEBAR:
01729       return "ACTION_DOUBLE_CLICK_TITLEBAR";
01730 
01731     case META_PREF_ACTION_MIDDLE_CLICK_TITLEBAR:
01732       return "ACTION_MIDDLE_CLICK_TITLEBAR";
01733 
01734     case META_PREF_ACTION_RIGHT_CLICK_TITLEBAR:
01735       return "ACTION_RIGHT_CLICK_TITLEBAR";
01736 
01737     case META_PREF_AUTO_RAISE:
01738       return "AUTO_RAISE";
01739       
01740     case META_PREF_AUTO_RAISE_DELAY:
01741       return "AUTO_RAISE_DELAY";
01742 
01743     case META_PREF_COMMANDS:
01744       return "COMMANDS";
01745 
01746     case META_PREF_TERMINAL_COMMAND:
01747       return "TERMINAL_COMMAND";
01748 
01749     case META_PREF_BUTTON_LAYOUT:
01750       return "BUTTON_LAYOUT";
01751 
01752     case META_PREF_WORKSPACE_NAMES:
01753       return "WORKSPACE_NAMES";
01754 
01755     case META_PREF_VISUAL_BELL:
01756       return "VISUAL_BELL";
01757 
01758     case META_PREF_AUDIBLE_BELL:
01759       return "AUDIBLE_BELL";
01760 
01761     case META_PREF_VISUAL_BELL_TYPE:
01762       return "VISUAL_BELL_TYPE";
01763 
01764     case META_PREF_REDUCED_RESOURCES:
01765       return "REDUCED_RESOURCES";
01766 
01767     case META_PREF_GNOME_ACCESSIBILITY:
01768       return "GNOME_ACCESSIBILTY";
01769 
01770     case META_PREF_GNOME_ANIMATIONS:
01771       return "GNOME_ANIMATIONS";
01772 
01773     case META_PREF_CURSOR_THEME:
01774       return "CURSOR_THEME";
01775 
01776     case META_PREF_CURSOR_SIZE:
01777       return "CURSOR_SIZE";
01778 
01779     case META_PREF_COMPOSITING_MANAGER:
01780       return "COMPOSITING_MANAGER";
01781     }
01782 
01783   return "(unknown)";
01784 }
01785 #endif /* WITH_VERBOSE_MODE */
01786 
01787 void
01788 meta_prefs_set_num_workspaces (int n_workspaces)
01789 {
01790 #ifdef HAVE_GCONF
01791   GError *err;
01792   
01793   if (default_client == NULL)
01794     return;
01795 
01796   if (n_workspaces < 1)
01797     n_workspaces = 1;
01798   if (n_workspaces > MAX_REASONABLE_WORKSPACES)
01799     n_workspaces = MAX_REASONABLE_WORKSPACES;
01800   
01801   err = NULL;
01802   gconf_client_set_int (default_client,
01803                         KEY_NUM_WORKSPACES,
01804                         n_workspaces,
01805                         &err);
01806 
01807   if (err)
01808     {
01809       meta_warning (_("Error setting number of workspaces to %d: %s\n"),
01810                     num_workspaces,
01811                     err->message);
01812       g_error_free (err);
01813     }
01814 #endif /* HAVE_GCONF */
01815 }
01816 
01817 /* Indexes must correspond to MetaKeybindingAction */
01818 static MetaKeyPref screen_bindings[] = {
01819   { META_KEYBINDING_WORKSPACE_1, NULL, FALSE },
01820   { META_KEYBINDING_WORKSPACE_2, NULL, FALSE },
01821   { META_KEYBINDING_WORKSPACE_3, NULL, FALSE },
01822   { META_KEYBINDING_WORKSPACE_4, NULL, FALSE },
01823   { META_KEYBINDING_WORKSPACE_5, NULL, FALSE },
01824   { META_KEYBINDING_WORKSPACE_6, NULL, FALSE },
01825   { META_KEYBINDING_WORKSPACE_7, NULL, FALSE },
01826   { META_KEYBINDING_WORKSPACE_8, NULL, FALSE }, 
01827   { META_KEYBINDING_WORKSPACE_9, NULL, FALSE },
01828   { META_KEYBINDING_WORKSPACE_10, NULL, FALSE },
01829   { META_KEYBINDING_WORKSPACE_11, NULL, FALSE },
01830   { META_KEYBINDING_WORKSPACE_12, NULL, FALSE },
01831   { META_KEYBINDING_WORKSPACE_LEFT, NULL, FALSE },
01832   { META_KEYBINDING_WORKSPACE_RIGHT, NULL, FALSE },
01833   { META_KEYBINDING_WORKSPACE_UP, NULL, FALSE },
01834   { META_KEYBINDING_WORKSPACE_DOWN, NULL, FALSE },
01835   { META_KEYBINDING_SWITCH_GROUP, NULL, TRUE },
01836   { META_KEYBINDING_SWITCH_GROUP_BACKWARD, NULL, TRUE },
01837   { META_KEYBINDING_SWITCH_WINDOWS, NULL, TRUE },
01838   { META_KEYBINDING_SWITCH_WINDOWS_BACKWARD, NULL, TRUE },
01839   { META_KEYBINDING_SWITCH_PANELS, NULL, TRUE },
01840   { META_KEYBINDING_SWITCH_PANELS_BACKWARD, NULL, TRUE },
01841   { META_KEYBINDING_CYCLE_GROUP, NULL, TRUE },
01842   { META_KEYBINDING_CYCLE_GROUP_BACKWARD, NULL, TRUE },
01843   { META_KEYBINDING_CYCLE_WINDOWS, NULL, TRUE },
01844   { META_KEYBINDING_CYCLE_WINDOWS_BACKWARD, NULL, TRUE },
01845   { META_KEYBINDING_CYCLE_PANELS, NULL, TRUE },
01846   { META_KEYBINDING_CYCLE_PANELS_BACKWARD, NULL, TRUE },
01847   { META_KEYBINDING_SHOW_DESKTOP, NULL, FALSE },
01848   { META_KEYBINDING_PANEL_MAIN_MENU, NULL, FALSE },
01849   { META_KEYBINDING_PANEL_RUN_DIALOG, NULL, FALSE },
01850   { META_KEYBINDING_COMMAND_1, NULL, FALSE },
01851   { META_KEYBINDING_COMMAND_2, NULL, FALSE },
01852   { META_KEYBINDING_COMMAND_3, NULL, FALSE },
01853   { META_KEYBINDING_COMMAND_4, NULL, FALSE },
01854   { META_KEYBINDING_COMMAND_5, NULL, FALSE },
01855   { META_KEYBINDING_COMMAND_6, NULL, FALSE },
01856   { META_KEYBINDING_COMMAND_7, NULL, FALSE },
01857   { META_KEYBINDING_COMMAND_8, NULL, FALSE }, 
01858   { META_KEYBINDING_COMMAND_9, NULL, FALSE },
01859   { META_KEYBINDING_COMMAND_10, NULL, FALSE },
01860   { META_KEYBINDING_COMMAND_11, NULL, FALSE },
01861   { META_KEYBINDING_COMMAND_12, NULL, FALSE },
01862   { META_KEYBINDING_COMMAND_13, NULL, FALSE },
01863   { META_KEYBINDING_COMMAND_14, NULL, FALSE },
01864   { META_KEYBINDING_COMMAND_15, NULL, FALSE },
01865   { META_KEYBINDING_COMMAND_16, NULL, FALSE },
01866   { META_KEYBINDING_COMMAND_17, NULL, FALSE },
01867   { META_KEYBINDING_COMMAND_18, NULL, FALSE },
01868   { META_KEYBINDING_COMMAND_19, NULL, FALSE },
01869   { META_KEYBINDING_COMMAND_20, NULL, FALSE },
01870   { META_KEYBINDING_COMMAND_21, NULL, FALSE },
01871   { META_KEYBINDING_COMMAND_22, NULL, FALSE },
01872   { META_KEYBINDING_COMMAND_23, NULL, FALSE },
01873   { META_KEYBINDING_COMMAND_24, NULL, FALSE },
01874   { META_KEYBINDING_COMMAND_25, NULL, FALSE },
01875   { META_KEYBINDING_COMMAND_26, NULL, FALSE },
01876   { META_KEYBINDING_COMMAND_27, NULL, FALSE },
01877   { META_KEYBINDING_COMMAND_28, NULL, FALSE },
01878   { META_KEYBINDING_COMMAND_29, NULL, FALSE },
01879   { META_KEYBINDING_COMMAND_30, NULL, FALSE },
01880   { META_KEYBINDING_COMMAND_31, NULL, FALSE },
01881   { META_KEYBINDING_COMMAND_32, NULL, FALSE },
01882   { META_KEYBINDING_COMMAND_SCREENSHOT, NULL, FALSE },
01883   { META_KEYBINDING_COMMAND_WIN_SCREENSHOT, NULL, FALSE },
01884   { META_KEYBINDING_RUN_COMMAND_TERMINAL, NULL, FALSE },
01885   { META_KEYBINDING_SET_SPEW_MARK, NULL, FALSE },
01886   { NULL, NULL, FALSE}
01887 };
01888 
01889 static MetaKeyPref window_bindings[] = {
01890   { META_KEYBINDING_WINDOW_MENU, NULL, FALSE },
01891   { META_KEYBINDING_TOGGLE_FULLSCREEN, NULL, FALSE },
01892   { META_KEYBINDING_TOGGLE_MAXIMIZE, NULL, FALSE },
01893   { META_KEYBINDING_TOGGLE_ABOVE, NULL, FALSE },
01894   { META_KEYBINDING_MAXIMIZE, NULL, FALSE },
01895   { META_KEYBINDING_UNMAXIMIZE, NULL, FALSE },
01896   { META_KEYBINDING_TOGGLE_SHADE, NULL, FALSE },
01897   { META_KEYBINDING_MINIMIZE, NULL, FALSE },
01898   { META_KEYBINDING_CLOSE, NULL, FALSE },
01899   { META_KEYBINDING_BEGIN_MOVE, NULL, FALSE },
01900   { META_KEYBINDING_BEGIN_RESIZE, NULL, FALSE },
01901   { META_KEYBINDING_TOGGLE_STICKY, NULL, FALSE },
01902   { META_KEYBINDING_MOVE_WORKSPACE_1, NULL, FALSE },
01903   { META_KEYBINDING_MOVE_WORKSPACE_2, NULL, FALSE },
01904   { META_KEYBINDING_MOVE_WORKSPACE_3, NULL, FALSE },
01905   { META_KEYBINDING_MOVE_WORKSPACE_4, NULL, FALSE },
01906   { META_KEYBINDING_MOVE_WORKSPACE_5, NULL, FALSE },
01907   { META_KEYBINDING_MOVE_WORKSPACE_6, NULL, FALSE },
01908   { META_KEYBINDING_MOVE_WORKSPACE_7, NULL, FALSE },
01909   { META_KEYBINDING_MOVE_WORKSPACE_8, NULL, FALSE },
01910   { META_KEYBINDING_MOVE_WORKSPACE_9, NULL, FALSE },
01911   { META_KEYBINDING_MOVE_WORKSPACE_10, NULL, FALSE },
01912   { META_KEYBINDING_MOVE_WORKSPACE_11, NULL, FALSE },
01913   { META_KEYBINDING_MOVE_WORKSPACE_12, NULL, FALSE },
01914   { META_KEYBINDING_MOVE_WORKSPACE_LEFT, NULL, FALSE },
01915   { META_KEYBINDING_MOVE_WORKSPACE_RIGHT, NULL, FALSE },
01916   { META_KEYBINDING_MOVE_WORKSPACE_UP, NULL, FALSE },
01917   { META_KEYBINDING_MOVE_WORKSPACE_DOWN, NULL, FALSE },
01918   { META_KEYBINDING_RAISE_OR_LOWER, NULL, FALSE },
01919   { META_KEYBINDING_RAISE, NULL, FALSE },
01920   { META_KEYBINDING_LOWER, NULL, FALSE },
01921   { META_KEYBINDING_MAXIMIZE_VERTICALLY, NULL, FALSE },
01922   { META_KEYBINDING_MAXIMIZE_HORIZONTALLY, NULL, FALSE },
01923   { META_KEYBINDING_MOVE_TO_CORNER_NW, NULL, FALSE },
01924   { META_KEYBINDING_MOVE_TO_CORNER_NE, NULL, FALSE },
01925   { META_KEYBINDING_MOVE_TO_CORNER_SW, NULL, FALSE },
01926   { META_KEYBINDING_MOVE_TO_CORNER_SE, NULL, FALSE },
01927   { META_KEYBINDING_MOVE_TO_SIDE_N, NULL, FALSE },
01928   { META_KEYBINDING_MOVE_TO_SIDE_S, NULL, FALSE },
01929   { META_KEYBINDING_MOVE_TO_SIDE_E, NULL, FALSE },
01930   { META_KEYBINDING_MOVE_TO_SIDE_W, NULL, FALSE },
01931   { NULL, NULL, FALSE }
01932 };
01933 
01934 #ifndef HAVE_GCONF
01935 typedef struct
01936 {
01937   const char *name;
01938   const char *keybinding;
01939 } MetaSimpleKeyMapping;
01940 
01941 /* Name field must occur in the same order as screen_bindings, though entries
01942  * can be skipped
01943  */
01944 static MetaSimpleKeyMapping screen_string_bindings[] = {
01945   { META_KEYBINDING_WORKSPACE_LEFT,         "<Control><Alt>Left"         },
01946   { META_KEYBINDING_WORKSPACE_RIGHT,        "<Control><Alt>Right"        },
01947   { META_KEYBINDING_WORKSPACE_UP,           "<Control><Alt>Up"           },
01948   { META_KEYBINDING_WORKSPACE_DOWN,         "<Control><Alt>Down"         },
01949   { META_KEYBINDING_SWITCH_WINDOWS,         "<Alt>Tab"                   },
01950   { META_KEYBINDING_SWITCH_PANELS,          "<Control><Alt>Tab"          },
01951   { META_KEYBINDING_CYCLE_GROUP,            "<Alt>F6"                    },
01952   { META_KEYBINDING_CYCLE_WINDOWS,          "<Alt>Escape"                },
01953   { META_KEYBINDING_CYCLE_PANELS,           "<Control><Alt>Escape"       },
01954   { META_KEYBINDING_SHOW_DESKTOP,           "<Control><Alt>d"            },
01955   { META_KEYBINDING_PANEL_MAIN_MENU,        "<Alt>F1"                    },
01956   { META_KEYBINDING_PANEL_RUN_DIALOG,       "<Alt>F2"                    },
01957   { META_KEYBINDING_COMMAND_SCREENSHOT,     "Print"                      },
01958   { META_KEYBINDING_COMMAND_WIN_SCREENSHOT, "<Alt>Print"                 },
01959   { NULL,                                   NULL                         }
01960 };
01961 
01962 /* Name field must occur in the same order as window_bindings, though entries
01963  * can be skipped
01964  */
01965 static MetaSimpleKeyMapping window_string_bindings[] = {
01966   { META_KEYBINDING_WINDOW_MENU,            "<Alt>Print"                 },
01967   { META_KEYBINDING_MAXIMIZE,               "<Alt>F10"                   },
01968   { META_KEYBINDING_UNMAXIMIZE,             "<Alt>F5"                    },
01969   { META_KEYBINDING_MINIMIZE,               "<Alt>F9"                    },
01970   { META_KEYBINDING_CLOSE,                  "<Alt>F4"                    },
01971   { META_KEYBINDING_BEGIN_MOVE,             "<Alt>F7"                    },
01972   { META_KEYBINDING_BEGIN_RESIZE,           "<Alt>F8"                    },
01973   { META_KEYBINDING_MOVE_WORKSPACE_LEFT,    "<Control><Shift><Alt>Left"  },
01974   { META_KEYBINDING_MOVE_WORKSPACE_RIGHT,   "<Control><Shift><Alt>Right" },
01975   { META_KEYBINDING_MOVE_WORKSPACE_UP,      "<Control><Shift><Alt>Up"    },
01976   { META_KEYBINDING_MOVE_WORKSPACE_DOWN,    "<Control><Shift><Alt>Down"  },
01977   { NULL,                                   NULL                         }
01978 };
01979 #endif /* NOT HAVE_GCONF */
01980 
01981 static void
01982 init_bindings (void)
01983 {
01984 #ifdef HAVE_GCONF
01985   int i;
01986   GError *err;
01987   
01988   i = 0;
01989   while (window_bindings[i].name)
01990     {
01991       GSList *list_val, *tmp;
01992       char *str_val;
01993       char *key;
01994 
01995       key = g_strconcat (KEY_WINDOW_BINDINGS_PREFIX, "/",
01996                          window_bindings[i].name, NULL);
01997 
01998       err = NULL;
01999       str_val = gconf_client_get_string (default_client, key, &err);
02000       cleanup_error (&err);
02001 
02002       update_binding (&window_bindings[i], str_val);
02003 
02004       g_free (str_val);      
02005       g_free (key);
02006 
02007       key = g_strconcat (KEY_WINDOW_BINDINGS_PREFIX, "/",
02008                          window_bindings[i].name,
02009                          KEY_LIST_BINDINGS_SUFFIX, NULL);
02010 
02011       err = NULL;
02012 
02013       list_val = gconf_client_get_list (default_client, key, GCONF_VALUE_STRING, &err);
02014       cleanup_error (&err);
02015 
02016       update_list_binding (&window_bindings[i], list_val, META_LIST_OF_STRINGS);
02017 
02018       tmp = list_val;
02019       while (tmp)
02020         {
02021           g_free (tmp->data);
02022           tmp = tmp->next;
02023         }
02024       g_slist_free (list_val);
02025       g_free (key);
02026 
02027       ++i;
02028     }
02029 
02030   i = 0;
02031   while (screen_bindings[i].name)
02032     {
02033       GSList *list_val, *tmp;
02034       char *str_val;
02035       char *key;
02036 
02037       key = g_strconcat (KEY_SCREEN_BINDINGS_PREFIX, "/",
02038                          screen_bindings[i].name, NULL);
02039 
02040       err = NULL;
02041       str_val = gconf_client_get_string (default_client, key, &err);
02042       cleanup_error (&err);
02043 
02044       update_binding (&screen_bindings[i], str_val);
02045 
02046       g_free (str_val);      
02047       g_free (key);
02048 
02049       key = g_strconcat (KEY_SCREEN_BINDINGS_PREFIX, "/",
02050                          screen_bindings[i].name,
02051                          KEY_LIST_BINDINGS_SUFFIX, NULL);
02052 
02053       err = NULL;
02054 
02055       list_val = gconf_client_get_list (default_client, key, GCONF_VALUE_STRING, &err);
02056       cleanup_error (&err);
02057 
02058       update_list_binding (&screen_bindings[i], list_val, META_LIST_OF_STRINGS);
02059 
02060       tmp = list_val;
02061       while (tmp)
02062         {
02063           g_free (tmp->data);
02064           tmp = tmp->next;
02065         }
02066       g_slist_free (list_val);
02067       g_free (key);
02068 
02069       ++i;
02070     }
02071 #else /* HAVE_GCONF */
02072   int i = 0;
02073   int which = 0;
02074   while (window_string_bindings[i].name)
02075     {
02076       /* Find which window_bindings entry this window_string_bindings entry
02077        * corresponds to.
02078        */
02079       while (strcmp(window_bindings[which].name, 
02080                     window_string_bindings[i].name) != 0)
02081         which++;
02082 
02083       /* Set the binding */
02084       update_binding (&window_bindings[which],
02085                       window_string_bindings[i].keybinding);
02086 
02087       ++i;
02088     }
02089 
02090   i = 0;
02091   which = 0;
02092   while (screen_string_bindings[i].name)
02093     {
02094       /* Find which window_bindings entry this window_string_bindings entry
02095        * corresponds to.
02096        */
02097       while (strcmp(screen_bindings[which].name, 
02098                     screen_string_bindings[i].name) != 0)
02099         which++;
02100 
02101       /* Set the binding */
02102       update_binding (&screen_bindings[which], 
02103                       screen_string_bindings[i].keybinding);
02104 
02105       ++i;
02106     }
02107 #endif /* HAVE_GCONF */
02108 }
02109 
02110 static void
02111 init_commands (void)
02112 {
02113 #ifdef HAVE_GCONF
02114   int i;
02115   GError *err;
02116   
02117   i = 0;
02118   while (i < MAX_COMMANDS)
02119     {
02120       char *str_val;
02121       char *key;
02122 
02123       key = meta_prefs_get_gconf_key_for_command (i);
02124 
02125       err = NULL;
02126       str_val = gconf_client_get_string (default_client, key, &err);
02127       cleanup_error (&err);
02128 
02129       update_command (key, str_val);
02130 
02131       g_free (str_val);    
02132       g_free (key);
02133 
02134       ++i;
02135     }
02136 #else
02137   int i;
02138   for (i = 0; i < MAX_COMMANDS; i++)
02139     commands[i] = NULL;
02140 #endif /* HAVE_GCONF */
02141 }
02142 
02143 static void
02144 init_workspace_names (void)
02145 {
02146 #ifdef HAVE_GCONF
02147   int i;
02148   GError *err;
02149   
02150   i = 0;
02151   while (i < MAX_REASONABLE_WORKSPACES)
02152     {
02153       char *str_val;
02154       char *key;
02155 
02156       key = gconf_key_for_workspace_name (i);
02157 
02158       err = NULL;
02159       str_val = gconf_client_get_string (default_client, key, &err);
02160       cleanup_error (&err);
02161 
02162       update_workspace_name (key, str_val);
02163 
02164       g_assert (workspace_names[i] != NULL);
02165       
02166       g_free (str_val);    
02167       g_free (key);
02168 
02169       ++i;
02170     }
02171 #else
02172   int i;
02173   for (i = 0; i < MAX_REASONABLE_WORKSPACES; i++)
02174     workspace_names[i] = g_strdup_printf (_("Workspace %d"), i + 1);
02175 
02176   meta_topic (META_DEBUG_PREFS,
02177               "Initialized workspace names\n");
02178 #endif /* HAVE_GCONF */
02179 }
02180 
02181 static gboolean
02182 update_binding (MetaKeyPref *binding,
02183                 const char  *value)
02184 {
02185   unsigned int keysym;
02186   unsigned int keycode;
02187   MetaVirtualModifier mods;
02188   MetaKeyCombo *combo;
02189   gboolean changed;
02190   
02191   meta_topic (META_DEBUG_KEYBINDINGS,
02192               "Binding \"%s\" has new gconf value \"%s\"\n",
02193               binding->name, value ? value : "none");
02194   
02195   keysym = 0;
02196   keycode = 0;
02197   mods = 0;
02198   if (value)
02199     {
02200       if (!meta_ui_parse_accelerator (value, &keysym, &keycode, &mods))
02201         {
02202           meta_topic (META_DEBUG_KEYBINDINGS,
02203                       "Failed to parse new gconf value\n");
02204           meta_warning (_("\"%s\" found in configuration database is not a valid value for keybinding \"%s\"\n"),
02205                         value, binding->name);
02206 
02207           return FALSE;
02208         }
02209     }
02210 
02211   /* If there isn't already a first element, make one. */
02212   if (!binding->bindings)
02213     {
02214       MetaKeyCombo *blank = g_malloc0 (sizeof (MetaKeyCombo));
02215       binding->bindings = g_slist_alloc();
02216       binding->bindings->data = blank;
02217     }
02218   
02219    combo = binding->bindings->data;
02220 
02221 #ifdef HAVE_GCONF
02222    /* Bug 329676: Bindings which can be shifted must not have no modifiers,
02223    * nor only SHIFT as a modifier.
02224    */
02225 
02226   if (binding->add_shift &&
02227       0 != keysym &&
02228       (META_VIRTUAL_SHIFT_MASK == mods || 0 == mods))
02229     {
02230       gchar *old_setting;
02231       gchar *key;
02232       GError *err = NULL;
02233       
02234       meta_warning ("Cannot bind \"%s\" to %s: it needs a modifier "
02235                     "such as Ctrl or Alt.\n",
02236                     binding->name,
02237                     value);
02238 
02239       old_setting = meta_ui_accelerator_name (combo->keysym,
02240                                               combo->modifiers);
02241 
02242       if (!strcmp(old_setting, value))
02243         {
02244           /* We were about to set it to the same value
02245            * that it had originally! This must be caused
02246            * by getting an invalid string back from
02247            * meta_ui_accelerator_name. Bail out now
02248            * so we don't get into an infinite loop.
02249            */
02250            g_free (old_setting);
02251            return TRUE;
02252         }
02253 
02254       meta_warning ("Reverting \"%s\" to %s.\n",
02255                     binding->name,
02256                     old_setting);
02257 
02258       key = g_strconcat (KEY_SCREEN_BINDINGS_PREFIX, "/",
02259                          binding->name, NULL);
02260       
02261       gconf_client_set_string (gconf_client_get_default (),
02262                                key, old_setting, &err);
02263 
02264       if (err)
02265         {
02266           meta_warning ("Error while reverting keybinding: %s\n",
02267                         err->message);
02268           g_error_free (err);
02269           err = NULL;
02270         }
02271       
02272       g_free (old_setting);
02273       g_free (key);
02274 
02275       /* The call to gconf_client_set_string() will cause this function
02276        * to be called again with the new value, so there's no need to
02277        * carry on.
02278        */
02279       return TRUE;
02280     }
02281 #endif
02282   
02283   changed = FALSE;
02284   if (keysym != combo->keysym ||
02285       keycode != combo->keycode ||
02286       mods != combo->modifiers)
02287     {
02288       changed = TRUE;
02289       
02290       combo->keysym = keysym;
02291       combo->keycode = keycode;
02292       combo->modifiers = mods;
02293       
02294       meta_topic (META_DEBUG_KEYBINDINGS,
02295                   "New keybinding for \"%s\" is keysym = 0x%x keycode = 0x%x mods = 0x%x\n",
02296                   binding->name, combo->keysym, combo->keycode,
02297                   combo->modifiers);
02298     }
02299   else
02300     {
02301       meta_topic (META_DEBUG_KEYBINDINGS,
02302                   "Keybinding for \"%s\" is unchanged\n", binding->name);
02303     }
02304   
02305   return changed;
02306 }
02307 
02308 #ifdef HAVE_GCONF
02309 static gboolean
02310 update_list_binding (MetaKeyPref *binding,
02311                      GSList      *value,
02312                      MetaStringListType type_of_value)
02313 {
02314   unsigned int keysym;
02315   unsigned int keycode;
02316   MetaVirtualModifier mods;
02317   gboolean changed = FALSE;
02318   const gchar *pref_string;
02319   GSList *pref_iterator = value, *tmp;
02320   MetaKeyCombo *combo;
02321 
02322   meta_topic (META_DEBUG_KEYBINDINGS,
02323               "Binding \"%s\" has new gconf value\n",
02324               binding->name);
02325   
02326   if (binding->bindings == NULL)
02327     {
02328       /* We need to insert a dummy element into the list, because the first
02329        * element is the one governed by update_binding. We only handle the
02330        * subsequent elements.
02331        */
02332       MetaKeyCombo *blank = g_malloc0 (sizeof (MetaKeyCombo));
02333       binding->bindings = g_slist_alloc();
02334       binding->bindings->data = blank;
02335     }
02336        
02337   /* Okay, so, we're about to provide a new list of key combos for this
02338    * action. Delete any pre-existing list.
02339    */
02340   tmp = binding->bindings->next;
02341   while (tmp)
02342     {
02343       g_free (tmp->data);
02344       tmp = tmp->next;
02345     }
02346   g_slist_free (binding->bindings->next);
02347   binding->bindings->next = NULL;
02348   
02349   while (pref_iterator)
02350     {
02351       keysym = 0;
02352       keycode = 0;
02353       mods = 0;
02354 
02355       if (!pref_iterator->data)
02356         {
02357           pref_iterator = pref_iterator->next;
02358           continue;
02359         }
02360 
02361       switch (type_of_value)
02362         {
02363         case META_LIST_OF_STRINGS:
02364           pref_string = pref_iterator->data;
02365           break;
02366         case META_LIST_OF_GCONFVALUE_STRINGS:
02367           pref_string = gconf_value_get_string (pref_iterator->data);
02368           break;
02369         default:
02370           g_assert_not_reached ();
02371         }
02372       
02373       if (!meta_ui_parse_accelerator (pref_string, &keysym, &keycode, &mods))
02374         {
02375           meta_topic (META_DEBUG_KEYBINDINGS,
02376                       "Failed to parse new gconf value\n");
02377           meta_warning (_("\"%s\" found in configuration database is not a valid value for keybinding \"%s\"\n"),
02378                         pref_string, binding->name);
02379 
02380           /* Should we remove this value from the list in gconf? */
02381           pref_iterator = pref_iterator->next;
02382           continue;
02383         }
02384 
02385       /* Bug 329676: Bindings which can be shifted must not have no modifiers,
02386        * nor only SHIFT as a modifier.
02387        */
02388 
02389       if (binding->add_shift &&
02390           0 != keysym &&
02391           (META_VIRTUAL_SHIFT_MASK == mods || 0 == mods))
02392         {
02393           meta_warning ("Cannot bind \"%s\" to %s: it needs a modifier "
02394                         "such as Ctrl or Alt.\n",
02395                         binding->name,
02396                         pref_string);
02397 
02398           /* Should we remove this value from the list in gconf? */
02399 
02400           pref_iterator = pref_iterator->next;
02401           continue;
02402         }
02403   
02404       changed = TRUE;
02405 
02406       combo = g_malloc0 (sizeof (MetaKeyCombo));
02407       combo->keysym = keysym;
02408       combo->keycode = keycode;
02409       combo->modifiers = mods;
02410       binding->bindings->next = g_slist_prepend (binding->bindings->next, combo);
02411 
02412       meta_topic (META_DEBUG_KEYBINDINGS,
02413                       "New keybinding for \"%s\" is keysym = 0x%x keycode = 0x%x mods = 0x%x\n",
02414                       binding->name, keysym, keycode, mods);
02415 
02416       pref_iterator = pref_iterator->next;
02417     }  
02418   return changed;
02419 }
02420 
02421 static const gchar*
02422 relative_key (const gchar* key)
02423 {
02424   const gchar* end;
02425   
02426   end = strrchr (key, '/');
02427 
02428   ++end;
02429 
02430   return end;
02431 }
02432 
02433 /* Return value is TRUE if a preference changed and we need to
02434  * notify
02435  */
02436 static gboolean
02437 find_and_update_binding (MetaKeyPref *bindings, 
02438                          const char  *name,
02439                          const char  *value)
02440 {
02441   const char *key;
02442   int i;
02443   
02444   if (*name == '/')
02445     key = relative_key (name);
02446   else
02447     key = name;
02448 
02449   i = 0;
02450   while (bindings[i].name &&
02451          strcmp (key, bindings[i].name) != 0)
02452     ++i;
02453 
02454   if (bindings[i].name)
02455     return update_binding (&bindings[i], value);
02456   else
02457     return FALSE;
02458 }
02459 
02460 static gboolean
02461 update_window_binding (const char *name,
02462                        const char *value)
02463 {
02464   return find_and_update_binding (window_bindings, name, value);
02465 }
02466 
02467 static gboolean
02468 update_screen_binding (const char *name,
02469                        const char *value)
02470 {
02471   return find_and_update_binding (screen_bindings, name, value);
02472 }
02473 
02474 static gboolean
02475 find_and_update_list_binding (MetaKeyPref *bindings,
02476                               const char  *name,
02477                               GSList      *value)
02478 {
02479   const char *key;
02480   int i;
02481   gchar *name_without_suffix = g_strdup(name);
02482 
02483   name_without_suffix[strlen(name_without_suffix) - strlen(KEY_LIST_BINDINGS_SUFFIX)] = 0;
02484 
02485   if (*name_without_suffix == '/')
02486     key = relative_key (name_without_suffix);
02487   else
02488     key = name_without_suffix;
02489 
02490   i = 0;
02491   while (bindings[i].name &&
02492          strcmp (key, bindings[i].name) != 0)
02493     ++i;
02494 
02495   g_free (name_without_suffix);
02496 
02497   if (bindings[i].name)
02498     return update_list_binding (&bindings[i], value, META_LIST_OF_GCONFVALUE_STRINGS);
02499   else
02500     return FALSE;
02501 }
02502 
02503 static gboolean
02504 update_window_list_binding (const char *name,
02505                             GSList *value)
02506 {
02507   return find_and_update_list_binding (window_bindings, name, value);
02508 }
02509 
02510 static gboolean
02511 update_screen_list_binding (const char *name,
02512                             GSList *value)
02513 {
02514   return find_and_update_list_binding (screen_bindings, name, value);
02515 }
02516 
02517 static gboolean
02518 update_command (const char  *name,
02519                 const char  *value)
02520 {
02521   char *p;
02522   int i;
02523   
02524   p = strrchr (name, '_');
02525   if (p == NULL)
02526     {
02527       meta_topic (META_DEBUG_KEYBINDINGS,
02528                   "Command %s has no underscore?\n", name);
02529       return FALSE;
02530     }
02531   
02532   ++p;
02533 
02534   if (g_ascii_isdigit (*p))
02535     {
02536       i = atoi (p);
02537       i -= 1; /* count from 0 not 1 */
02538     }
02539   else
02540     {
02541       p = strrchr (name, '/');
02542       ++p;
02543 
02544       if (strcmp (p, "command_screenshot") == 0)
02545         {
02546           i = SCREENSHOT_COMMAND_IDX;
02547         }
02548       else if (strcmp (p, "command_window_screenshot") == 0)
02549         {
02550           i = WIN_SCREENSHOT_COMMAND_IDX;
02551         }
02552       else
02553         {
02554           meta_topic (META_DEBUG_KEYBINDINGS,
02555                       "Command %s doesn't end in number?\n", name);
02556           return FALSE;
02557         }
02558     }
02559   
02560   if (i >= MAX_COMMANDS)
02561     {
02562       meta_topic (META_DEBUG_KEYBINDINGS,
02563                   "Command %d is too highly numbered, ignoring\n", i);
02564       return FALSE;
02565     }
02566 
02567   if ((commands[i] == NULL && value == NULL) ||
02568       (commands[i] && value && strcmp (commands[i], value) == 0))
02569     {
02570       meta_topic (META_DEBUG_KEYBINDINGS,
02571                   "Command %d is unchanged\n", i);
02572       return FALSE;
02573     }
02574   
02575   g_free (commands[i]);
02576   commands[i] = g_strdup (value);
02577 
02578   meta_topic (META_DEBUG_KEYBINDINGS,
02579               "Updated command %d to \"%s\"\n",
02580               i, commands[i] ? commands[i] : "none");
02581   
02582   return TRUE;
02583 }
02584 
02585 #endif /* HAVE_GCONF */
02586 
02587 const char*
02588 meta_prefs_get_command (int i)
02589 {
02590   g_return_val_if_fail (i >= 0 && i < MAX_COMMANDS, NULL);
02591   
02592   return commands[i];
02593 }
02594 
02595 char*
02596 meta_prefs_get_gconf_key_for_command (int i)
02597 {
02598   char *key;
02599 
02600   switch (i)
02601     {
02602     case SCREENSHOT_COMMAND_IDX:
02603       key = g_strdup (KEY_COMMAND_PREFIX "screenshot");
02604       break;
02605     case WIN_SCREENSHOT_COMMAND_IDX:
02606       key = g_strdup (KEY_COMMAND_PREFIX "window_screenshot");
02607       break;
02608     default:
02609       key = g_strdup_printf (KEY_COMMAND_PREFIX"%d", i + 1);
02610       break;
02611     }
02612   
02613   return key;
02614 }
02615 
02616 const char*
02617 meta_prefs_get_terminal_command (void)
02618 {
02619   return terminal_command;
02620 }
02621 
02622 const char*
02623 meta_prefs_get_gconf_key_for_terminal_command (void)
02624 {
02625   return KEY_TERMINAL_COMMAND;
02626 }
02627 
02628 #ifdef HAVE_GCONF
02629 static gboolean
02630 update_workspace_name (const char  *name,
02631                        const char  *value)
02632 {
02633   char *p;
02634   int i;
02635   
02636   p = strrchr (name, '_');
02637   if (p == NULL)
02638     {
02639       meta_topic (META_DEBUG_PREFS,
02640                   "Workspace name %s has no underscore?\n", name);
02641       return FALSE;
02642     }
02643   
02644   ++p;
02645 
02646   if (!g_ascii_isdigit (*p))
02647     {
02648       meta_topic (META_DEBUG_PREFS,
02649                   "Workspace name %s doesn't end in number?\n", name);
02650       return FALSE;
02651     }
02652   
02653   i = atoi (p);
02654   i -= 1; /* count from 0 not 1 */
02655   
02656   if (i >= MAX_REASONABLE_WORKSPACES)
02657     {
02658       meta_topic (META_DEBUG_PREFS,
02659                   "Workspace name %d is too highly numbered, ignoring\n", i);
02660       return FALSE;
02661     }
02662 
02663   if (workspace_names[i] && value && strcmp (workspace_names[i], value) == 0)
02664     {
02665       meta_topic (META_DEBUG_PREFS,
02666                   "Workspace name %d is unchanged\n", i);
02667       return FALSE;
02668     }  
02669 
02670   /* This is a bad hack. We have to treat empty string as
02671    * "unset" because the root window property can't contain
02672    * null. So it gets empty string instead and we don't want
02673    * that to result in setting the empty string as a value that
02674    * overrides "unset".
02675    */
02676   if (value != NULL && *value != '\0')
02677     {
02678       g_free (workspace_names[i]);
02679       workspace_names[i] = g_strdup (value);
02680     }
02681   else
02682     {
02683       /* use a default name */
02684       char *d;
02685 
02686       d = g_strdup_printf (_("Workspace %d"), i + 1);
02687       if (workspace_names[i] && strcmp (workspace_names[i], d) == 0)
02688         {
02689           g_free (d);
02690           return FALSE;
02691         }
02692       else
02693         {
02694           g_free (workspace_names[i]);
02695           workspace_names[i] = d;
02696         }
02697     }
02698   
02699   meta_topic (META_DEBUG_PREFS,
02700               "Updated workspace name %d to \"%s\"\n",
02701               i, workspace_names[i] ? workspace_names[i] : "none");
02702   
02703   return TRUE;
02704 }
02705 #endif /* HAVE_GCONF */
02706 
02707 const char*
02708 meta_prefs_get_workspace_name (int i)
02709 {
02710   g_return_val_if_fail (i >= 0 && i < MAX_REASONABLE_WORKSPACES, NULL);
02711 
02712   g_assert (workspace_names[i] != NULL);
02713 
02714   meta_topic (META_DEBUG_PREFS,
02715               "Getting workspace name for %d: \"%s\"\n",
02716               i, workspace_names[i]);
02717   
02718   return workspace_names[i];
02719 }
02720 
02721 void
02722 meta_prefs_change_workspace_name (int         i,
02723                                   const char *name)
02724 {
02725 #ifdef HAVE_GCONF
02726   char *key;
02727   GError *err;
02728   
02729   g_return_if_fail (i >= 0 && i < MAX_REASONABLE_WORKSPACES);
02730 
02731   meta_topic (META_DEBUG_PREFS,
02732               "Changing name of workspace %d to %s\n",
02733               i, name ? name : "none");
02734 
02735   /* This is a bad hack. We have to treat empty string as
02736    * "unset" because the root window property can't contain
02737    * null. So it gets empty string instead and we don't want
02738    * that to result in setting the empty string as a value that
02739    * overrides "unset".
02740    */
02741   if (name && *name == '\0')
02742     name = NULL;
02743   
02744   if ((name == NULL && workspace_names[i] == NULL) ||
02745       (name && workspace_names[i] && strcmp (name, workspace_names[i]) == 0))
02746     {
02747       meta_topic (META_DEBUG_PREFS,
02748                   "Workspace %d already has name %s\n",
02749                   i, name ? name : "none");
02750       return;
02751     }
02752   
02753   key = gconf_key_for_workspace_name (i);
02754 
02755   err = NULL;
02756   if (name != NULL)
02757     gconf_client_set_string (default_client,
02758                              key, name,
02759                              &err);
02760   else
02761     gconf_client_unset (default_client,
02762                         key, &err);
02763 
02764   
02765   if (err)
02766     {
02767       meta_warning (_("Error setting name for workspace %d to \"%s\": %s\n"),
02768                     i, name ? name : "none",
02769                     err->message);
02770       g_error_free (err);
02771     }
02772   
02773   g_free (key);
02774 #else
02775   g_free (workspace_names[i]);
02776   workspace_names[i] = g_strdup (name);
02777 #endif /* HAVE_GCONF */
02778 }
02779 
02780 #ifdef HAVE_GCONF
02781 static char*
02782 gconf_key_for_workspace_name (int i)
02783 {
02784   char *key;
02785   
02786   key = g_strdup_printf (KEY_WORKSPACE_NAME_PREFIX"%d", i + 1);
02787   
02788   return key;
02789 }
02790 #endif /* HAVE_GCONF */
02791 
02792 void
02793 meta_prefs_get_button_layout (MetaButtonLayout *button_layout_p)
02794 {
02795   *button_layout_p = button_layout;
02796 }
02797 
02798 gboolean
02799 meta_prefs_get_visual_bell (void)
02800 {
02801   return provide_visual_bell;
02802 }
02803 
02804 gboolean
02805 meta_prefs_bell_is_audible (void)
02806 {
02807   return bell_is_audible;
02808 }
02809 
02810 MetaVisualBellType
02811 meta_prefs_get_visual_bell_type (void)
02812 {
02813   return visual_bell_type;
02814 }
02815 
02816 void
02817 meta_prefs_get_screen_bindings (const MetaKeyPref **bindings,
02818                                 int                *n_bindings)
02819 {
02820   
02821   *bindings = screen_bindings;
02822   *n_bindings = (int) G_N_ELEMENTS (screen_bindings) - 1;
02823 }
02824 
02825 void
02826 meta_prefs_get_window_bindings (const MetaKeyPref **bindings,
02827                                 int                *n_bindings)
02828 {
02829   *bindings = window_bindings;
02830   *n_bindings = (int) G_N_ELEMENTS (window_bindings) - 1;
02831 }
02832 
02833 MetaActionTitlebar
02834 meta_prefs_get_action_double_click_titlebar (void)
02835 {
02836   return action_double_click_titlebar;
02837 }
02838 
02839 MetaActionTitlebar
02840 meta_prefs_get_action_middle_click_titlebar (void)
02841 {
02842   return action_middle_click_titlebar;
02843 }
02844 
02845 MetaActionTitlebar
02846 meta_prefs_get_action_right_click_titlebar (void)
02847 {
02848   return action_right_click_titlebar;
02849 }
02850 
02851 gboolean
02852 meta_prefs_get_auto_raise (void)
02853 {
02854   return auto_raise;
02855 }
02856 
02857 int
02858 meta_prefs_get_auto_raise_delay (void)
02859 {
02860   return auto_raise_delay;
02861 }
02862 
02863 gboolean
02864 meta_prefs_get_reduced_resources (void)
02865 {
02866   return reduced_resources;
02867 }
02868 
02869 gboolean
02870 meta_prefs_get_gnome_accessibility ()
02871 {
02872   return gnome_accessibility;
02873 }
02874 
02875 gboolean
02876 meta_prefs_get_gnome_animations ()
02877 {
02878   return gnome_animations;
02879 }
02880 
02881 MetaKeyBindingAction
02882 meta_prefs_get_keybinding_action (const char *name)
02883 {
02884   int i;
02885 
02886   i = G_N_ELEMENTS (screen_bindings) - 2; /* -2 for dummy entry at end */
02887   while (i >= 0)
02888     {
02889       if (strcmp (screen_bindings[i].name, name) == 0)
02890         return (MetaKeyBindingAction) i;
02891       
02892       --i;
02893     }
02894 
02895   return META_KEYBINDING_ACTION_NONE;
02896 }
02897 
02898 /* This is used by the menu system to decide what key binding
02899  * to display next to an option. We return the first non-disabled
02900  * binding, if any.
02901  */
02902 void
02903 meta_prefs_get_window_binding (const char          *name,
02904                                unsigned int        *keysym,
02905                                MetaVirtualModifier *modifiers)
02906 {
02907   int i;
02908 
02909   i = G_N_ELEMENTS (window_bindings) - 2; /* -2 for dummy entry at end */
02910   while (i >= 0)
02911     {
02912       if (strcmp (window_bindings[i].name, name) == 0)
02913         {
02914           GSList *s = window_bindings[i].bindings;
02915 
02916           while (s)
02917             {
02918               MetaKeyCombo *c = s->data;
02919 
02920               if (c->keysym!=0 || c->modifiers!=0)
02921                 {
02922                   *keysym = c->keysym;
02923                   *modifiers = c->modifiers;
02924                   return;
02925                 }
02926 
02927               s = s->next;
02928             }
02929 
02930           /* Not found; return the disabled value */
02931           *keysym = *modifiers = 0;
02932           return;
02933         }
02934       
02935       --i;
02936     }
02937 
02938   g_assert_not_reached ();
02939 }
02940 
02941 gboolean
02942 meta_prefs_get_compositing_manager (void)
02943 {
02944   return compositing_manager;
02945 }
02946 
02947 #ifndef HAVE_GCONF
02948 static void
02949 init_button_layout(void)
02950 {
02951   MetaButtonLayout button_layout_ltr = {
02952     {    
02953       /* buttons in the group on the left side */
02954       META_BUTTON_FUNCTION_MENU,
02955       META_BUTTON_FUNCTION_LAST
02956     },
02957     {
02958       /* buttons in the group on the right side */
02959       META_BUTTON_FUNCTION_MINIMIZE,
02960       META_BUTTON_FUNCTION_MAXIMIZE,
02961       META_BUTTON_FUNCTION_CLOSE,
02962       META_BUTTON_FUNCTION_LAST
02963     }
02964   };
02965   MetaButtonLayout button_layout_rtl = {
02966     {    
02967       /* buttons in the group on the left side */
02968       META_BUTTON_FUNCTION_CLOSE,
02969       META_BUTTON_FUNCTION_MAXIMIZE,
02970       META_BUTTON_FUNCTION_MINIMIZE,
02971       META_BUTTON_FUNCTION_LAST
02972     },
02973     {
02974       /* buttons in the group on the right side */
02975       META_BUTTON_FUNCTION_MENU,
02976       META_BUTTON_FUNCTION_LAST
02977     }
02978   };
02979 
02980   button_layout = meta_ui_get_direction() == META_UI_DIRECTION_LTR ?
02981     button_layout_ltr : button_layout_rtl;
02982 };
02983 
02984 #endif

Generated on Sat Aug 23 22:04:17 2008 for metacity by  doxygen 1.5.5