00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
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
00044
00045
00046
00047
00048
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
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
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
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
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
00313
00314
00315
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,
00361 &use_system_font,
00362 TRUE,
00363 },
00364 { "/apps/metacity/general/application_based",
00365 META_PREF_APPLICATION_BASED,
00366 NULL,
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,
00382 FALSE,
00383 },
00384 { "/apps/metacity/general/audible_bell",
00385 META_PREF_AUDIBLE_BELL,
00386 &bell_is_audible,
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
00453
00454
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
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
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
00586
00587
00588
00589
00590
00591
00592
00593
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
00614 return FALSE;
00615
00616
00617
00618
00619
00620 if (value==NULL)
00621 return TRUE;
00622
00623
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
00630 return TRUE;
00631 }
00632
00633
00634
00635
00636
00637 old_value = * ((gint *) cursor->target);
00638
00639
00640
00641 if (!gconf_string_to_enum (cursor->symtab,
00642 gconf_value_get_string (value),
00643 (gint *) cursor->target))
00644 {
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654 meta_warning (_("GConf key '%s' is set to an invalid value\n"),
00655 key);
00656 return TRUE;
00657 }
00658
00659
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
00678 return FALSE;
00679
00680 if (cursor->target==NULL)
00681
00682 return TRUE;
00683
00684 if (value==NULL)
00685 {
00686
00687
00688 if (cursor->becomes_true_on_destruction)
00689
00690
00691
00692 *((gboolean *)cursor->target) = TRUE;
00693
00694 return TRUE;
00695 }
00696
00697
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
00704 return TRUE;
00705 }
00706
00707
00708
00709
00710
00711 old_value = * ((gboolean *) cursor->target);
00712
00713
00714
00715 *((gboolean *) cursor->target) = gconf_value_get_bool (value);
00716
00717
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
00740 return FALSE;
00741
00742 if (value==NULL)
00743 return TRUE;
00744
00745
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
00752 return TRUE;
00753 }
00754
00755
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
00793 return FALSE;
00794
00795 if (cursor->target==NULL)
00796
00797 return TRUE;
00798
00799 if (value==NULL)
00800 {
00801
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
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
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
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
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);
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
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
00957
00958 void
00959 meta_prefs_add_listener (MetaPrefsChangedFunc func,
00960 gpointer data)
00961 {
00962
00963 }
00964
00965 void
00966 meta_prefs_remove_listener (MetaPrefsChangedFunc func,
00967 gpointer data)
00968 {
00969
00970 }
00971
00972 #endif
00973
00974
00975
00976
00977
00978
00979
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
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
01014
01015 handle_preference_init_enum ();
01016 handle_preference_init_bool ();
01017 handle_preference_init_string ();
01018 handle_preference_init_int ();
01019
01020
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
01035
01036
01037
01038
01039
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
01046
01047 init_bindings ();
01048 init_commands ();
01049 init_workspace_names ();
01050 }
01051
01052
01053
01054
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
01081
01082
01083
01084
01085
01086
01087 while (preference_update_handler[i]!=NULL)
01088 {
01089 if (preference_update_handler[i] (key, value))
01090 goto out;
01091
01092 i++;
01093 }
01094
01095
01096
01097
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
01210 return;
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
01226
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
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
01291
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
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
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
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
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
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
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
01482
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
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
01644 *inform_listeners = FALSE;
01645 }
01646 else
01647 {
01648 button_layout = new_layout;
01649 }
01650 }
01651
01652 #endif
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;
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
01687
01688 #ifdef WITH_VERBOSE_MODE
01689 const char*
01690 meta_preference_to_string (MetaPreference pref)
01691 {
01692
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
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
01815 }
01816
01817
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
01942
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
01963
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
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
02072 int i = 0;
02073 int which = 0;
02074 while (window_string_bindings[i].name)
02075 {
02076
02077
02078
02079 while (strcmp(window_bindings[which].name,
02080 window_string_bindings[i].name) != 0)
02081 which++;
02082
02083
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
02095
02096
02097 while (strcmp(screen_bindings[which].name,
02098 screen_string_bindings[i].name) != 0)
02099 which++;
02100
02101
02102 update_binding (&screen_bindings[which],
02103 screen_string_bindings[i].keybinding);
02104
02105 ++i;
02106 }
02107 #endif
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
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
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
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
02223
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
02245
02246
02247
02248
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
02276
02277
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
02329
02330
02331
02332 MetaKeyCombo *blank = g_malloc0 (sizeof (MetaKeyCombo));
02333 binding->bindings = g_slist_alloc();
02334 binding->bindings->data = blank;
02335 }
02336
02337
02338
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
02381 pref_iterator = pref_iterator->next;
02382 continue;
02383 }
02384
02385
02386
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
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
02434
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;
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
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;
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
02671
02672
02673
02674
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
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
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
02736
02737
02738
02739
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
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
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;
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
02899
02900
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;
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
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
02954 META_BUTTON_FUNCTION_MENU,
02955 META_BUTTON_FUNCTION_LAST
02956 },
02957 {
02958
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
02968 META_BUTTON_FUNCTION_CLOSE,
02969 META_BUTTON_FUNCTION_MAXIMIZE,
02970 META_BUTTON_FUNCTION_MINIMIZE,
02971 META_BUTTON_FUNCTION_LAST
02972 },
02973 {
02974
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