1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3 /* Marco preferences */
4
5 /*
6 * Copyright (C) 2001 Havoc Pennington, Copyright (C) 2002 Red Hat Inc.
7 * Copyright (C) 2006 Elijah Newren
8 * Copyright (C) 2008 Thomas Thurman
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License as
12 * published by the Free Software Foundation; either version 2 of the
13 * License, or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
23 * 02110-1301, USA.
24 */
25
26 #include <config.h>
27 #include <glib/gi18n-lib.h>
28
29 #include "prefs.h"
30 #include "ui.h"
31 #include "util.h"
32 #include <gdk/gdk.h>
33 #include <gio/gio.h>
34 #include <string.h>
35 #include <stdlib.h>
36
37 #define MAX_REASONABLE_WORKSPACES 36
38
39 #define MAX_COMMANDS (32 + NUM_EXTRA_COMMANDS)
40 #define NUM_EXTRA_COMMANDS 2
41 #define SCREENSHOT_COMMAND_IDX (MAX_COMMANDS - 2)
42 #define WIN_SCREENSHOT_COMMAND_IDX (MAX_COMMANDS - 1)
43
44 /* If you add a key, it needs updating in init() and in the GSettings
45 * notify listener and of course in the .gschema file.
46 *
47 * Keys which are handled by one of the unified handlers below are
48 * not given a name here, because the purpose of the unified handlers
49 * is that keys should be referred to exactly once.
50 */
51 #define KEY_GENERAL_SCHEMA "org.mate.Marco.general"
52 #define KEY_GENERAL_TITLEBAR_FONT "titlebar-font"
53 #define KEY_GENERAL_NUM_WORKSPACES "num-workspaces"
54 #define KEY_GENERAL_COMPOSITOR "compositing-manager"
55 #define KEY_GENERAL_COMPOSITOR_FAST_ALT_TAB "compositing-fast-alt-tab"
56 #define KEY_GENERAL_CENTER_NEW_WINDOWS "center-new-windows"
57 #define KEY_GENERAL_ICON_SIZE "icon-size"
58 #define KEY_GENERAL_ALT_TAB_MAX_COLUMNS "alt-tab-max-columns"
59 #define KEY_GENERAL_ALT_TAB_EXPAND_TO_FIT_TITLE "alt-tab-expand-to-fit-title"
60
61 #define KEY_COMMAND_SCHEMA "org.mate.Marco.keybinding-commands"
62 #define KEY_COMMAND_PREFIX "command-"
63
64 #define KEY_SCREEN_BINDINGS_SCHEMA "org.mate.Marco.global-keybindings"
65
66 #define KEY_WINDOW_BINDINGS_SCHEMA "org.mate.Marco.window-keybindings"
67
68 #define KEY_WORKSPACE_NAME_SCHEMA "org.mate.Marco.workspace-names"
69 #define KEY_WORKSPACE_NAME_PREFIX "name-"
70
71 #define KEY_MATE_INTERFACE_SCHEMA "org.mate.interface"
72 #define KEY_MATE_INTERFACE_ACCESSIBILITY "accessibility"
73 #define KEY_MATE_INTERFACE_ENABLE_ANIMATIONS "enable-animations"
74
75 #define KEY_MATE_TERMINAL_SCHEMA "org.mate.applications-terminal"
76 #define KEY_MATE_TERMINAL_COMMAND "exec"
77
78 #define KEY_MATE_MOUSE_SCHEMA "org.mate.peripherals-mouse"
79 #define KEY_MATE_MOUSE_CURSOR_THEME "cursor-theme"
80 #define KEY_MATE_MOUSE_CURSOR_SIZE "cursor-size"
81
82 #define SETTINGS(s) g_hash_table_lookup (settings_schemas, (s))
83
84 static GSettings *settings_general;
85 static GSettings *settings_command;
86 static GSettings *settings_screen_bindings;
87 static GSettings *settings_window_bindings;
88 static GSettings *settings_workspace_names;
89 static GSettings *settings_mate_interface;
90 static GSettings *settings_mate_terminal;
91 static GSettings *settings_mate_mouse;
92 static GHashTable *settings_schemas;
93
94 static GList *changes = NULL;
95 static guint changed_idle;
96 static GList *listeners = NULL;
97
98 static gboolean use_system_font = FALSE;
99 static PangoFontDescription *titlebar_font = NULL;
100 static MetaVirtualModifier mouse_button_mods = Mod1Mask;
101 static MetaFocusMode focus_mode = META_FOCUS_MODE_CLICK;
102 static MetaFocusNewWindows focus_new_windows = META_FOCUS_NEW_WINDOWS_SMART;
103 static gboolean raise_on_click = TRUE;
104 static gboolean attach_modal_dialogs = FALSE;
105 static char* current_theme = NULL;
106 static int num_workspaces = 4;
107 static MetaWrapStyle wrap_style = META_WRAP_NONE;
108 static MetaActionTitlebar action_double_click_titlebar = META_ACTION_TITLEBAR_TOGGLE_MAXIMIZE;
109 static MetaActionTitlebar action_middle_click_titlebar = META_ACTION_TITLEBAR_LOWER;
110 static MetaActionTitlebar action_right_click_titlebar = META_ACTION_TITLEBAR_MENU;
111 static gboolean application_based = FALSE;
112 static gboolean disable_workarounds = FALSE;
113 static gboolean auto_raise = FALSE;
114 static gboolean auto_raise_delay = 500;
115 static gboolean provide_visual_bell = FALSE;
116 static gboolean bell_is_audible = TRUE;
117 static gboolean reduced_resources = FALSE;
118 static gboolean mate_accessibility = FALSE;
119 static gboolean mate_animations = TRUE;
120 static char *cursor_theme = NULL;
121 static int cursor_size = 24;
122 static int icon_size = META_DEFAULT_ICON_SIZE;
123 static int alt_tab_max_columns = META_DEFAULT_ALT_TAB_MAX_COLUMNS;
124 static gboolean alt_tab_expand_to_fit_title = META_DEFAULT_ALT_TAB_EXPAND_TO_FIT_TITLE;
125 static gboolean use_force_compositor_manager = FALSE;
126 static gboolean force_compositor_manager = FALSE;
127 static gboolean compositing_manager = FALSE;
128 static gboolean compositing_fast_alt_tab = FALSE;
129 static gboolean resize_with_right_button = FALSE;
130 static gboolean show_tab_border = FALSE;
131 static gboolean center_new_windows = FALSE;
132 static gboolean force_fullscreen = TRUE;
133 static gboolean allow_tiling = FALSE;
134 static gboolean allow_top_tiling = TRUE;
135 static gboolean allow_tile_cycling = TRUE;
136 static GList *show_desktop_skip_list = NULL;
137
138 static MetaVisualBellType visual_bell_type = META_VISUAL_BELL_FULLSCREEN_FLASH;
139 static MetaButtonLayout button_layout;
140
141 /* The screenshot commands are at the end */
142 static char *commands[MAX_COMMANDS] = { NULL, };
143
144 static char *terminal_command = NULL;
145
146 static char *workspace_names[MAX_REASONABLE_WORKSPACES] = { NULL, };
147
148 static gboolean handle_preference_update_enum (const gchar *key, GSettings *settings);
149
150 static gboolean update_key_binding (const char *name,
151 gchar *value);
152 static gboolean update_command (const char *name,
153 const char *value);
154 static gboolean update_workspace_name (const char *name,
155 const char *value);
156
157 static void change_notify (GSettings *settings,
158 gchar *key,
159 gpointer user_data);
160
161 static char* settings_key_for_workspace_name (int i);
162
163 static void queue_changed (MetaPreference pref);
164
165 #if 0
166 static void cleanup_error (GError **error);
167 #endif
168
169 static void maybe_give_disable_workarounds_warning (void);
170
171 static void titlebar_handler (MetaPreference, const gchar*, gboolean*);
172 static void theme_name_handler (MetaPreference, const gchar*, gboolean*);
173 static void mouse_button_mods_handler (MetaPreference, const gchar*, gboolean*);
174 static void button_layout_handler (MetaPreference, const gchar*, gboolean*);
175 static void show_desktop_skip_list_handler (MetaPreference, const gchar*, gboolean*);
176
177 static gboolean update_binding (MetaKeyPref *binding,
178 gchar *value);
179
180 static void init_bindings (GSettings *);
181 static void init_screen_bindings (void);
182 static void init_window_bindings (void);
183 static void init_commands (void);
184 static void init_workspace_names (void);
185
186 static MetaPlacementMode placement_mode = META_PLACEMENT_MODE_AUTOMATIC;
187
188 typedef struct
189 {
190 MetaPrefsChangedFunc func;
191 gpointer data;
192 } MetaPrefsListener;
193
194 /**
195 * The details of one preference which is constrained to be
196 * one of a small number of string values-- in other words,
197 * an enumeration.
198 *
199 * We could have done this other ways. One particularly attractive
200 * possibility would have been to represent the entire symbol table
201 * as a space-separated string literal in the list of symtabs, so
202 * the focus mode enums could have been represented simply by
203 * "click sloppy mouse". However, the simplicity gained would have
204 * been outweighed by the bugs caused when the ordering of the enum
205 * strings got out of sync with the actual enum statement. Also,
206 * there is existing library code to use this kind of symbol tables.
207 *
208 * Other things we might consider doing to clean this up in the
209 * future include:
210 *
211 * - most of the keys begin with the same prefix, and perhaps we
212 * could assume it if they don't start with a slash
213 *
214 * - there are several cases where a single identifier could be used
215 * to generate an entire entry, and perhaps this could be done
216 * with a macro. (This would reduce clarity, however, and is
217 * probably a bad thing.)
218 *
219 * - these types all begin with a gchar* (and contain a MetaPreference)
220 * and we can factor out the repeated code in the handlers by taking
221 * advantage of this using some kind of union arrangement.
222 */
223 typedef struct
224 {
225 gchar *key;
226 gchar *schema;
227 MetaPreference pref;
228 gint *target;
229 } MetaEnumPreference;
230
231 typedef struct
232 {
233 gchar *key;
234 gchar *schema;
235 MetaPreference pref;
236 gboolean *target;
237 gboolean becomes_true_on_destruction;
238 } MetaBoolPreference;
239
240 typedef struct
241 {
242 gchar *key;
243 gchar *schema;
244 MetaPreference pref;
245
246 /**
247 * A handler. Many of the string preferences aren't stored as
248 * strings and need parsing; others of them have default values
249 * which can't be solved in the general case. If you include a
250 * function pointer here, it will be called before the string
251 * value is written out to the target variable.
252 *
253 * The function is passed two arguments: the preference, and
254 * the new string as a gchar*. It returns a gboolean;
255 * only if this is true, the listeners will be informed that
256 * the preference has changed.
257 *
258 * This may be NULL. If it is, see "target", below.
259 */
260 void (*handler) (MetaPreference pref,
261 const gchar *string_value,
262 gboolean *inform_listeners);
263
264 /**
265 * Where to write the incoming string.
266 *
267 * This must be NULL if the handler is non-NULL.
268 * If the incoming string is NULL, no change will be made.
269 */
270 gchar **target;
271
272 } MetaStringPreference;
273
274 #define METAINTPREFERENCE_NO_CHANGE_ON_DESTROY G_MININT
275
276 typedef struct
277 {
278 gchar *key;
279 gchar *schema;
280 MetaPreference pref;
281 gint *target;
282 /**
283 * Minimum and maximum values of the integer.
284 * If the new value is out of bounds, it will be discarded with a warning.
285 */
286 gint minimum, maximum;
287 /**
288 * Value to use if the key is destroyed.
289 * If this is METAINTPREFERENCE_NO_CHANGE_ON_DESTROY, it will
290 * not be changed when the key is destroyed.
291 */
292 gint value_if_destroyed;
293 } MetaIntPreference;
294
295 /* FIXMEs: */
296 /* @@@ Don't use NULL lines at the end; glib can tell you how big it is */
297 /* @@@ /apps/marco/general should be assumed if first char is not / */
298 /* @@@ Will it ever be possible to merge init and update? If not, why not? */
299
300 static MetaEnumPreference preferences_enum[] =
301 {
302 { "focus-new-windows",
303 KEY_GENERAL_SCHEMA,
304 META_PREF_FOCUS_NEW_WINDOWS,
305 (gint *) &focus_new_windows,
306 },
307 { "focus-mode",
308 KEY_GENERAL_SCHEMA,
309 META_PREF_FOCUS_MODE,
310 (gint *) &focus_mode,
311 },
312 { "wrap-style",
313 KEY_GENERAL_SCHEMA,
314 META_PREF_WRAP_STYLE,
315 (gint *) &wrap_style,
316 },
317 { "visual-bell-type",
318 KEY_GENERAL_SCHEMA,
319 META_PREF_VISUAL_BELL_TYPE,
320 (gint *) &visual_bell_type,
321 },
322 { "action-double-click-titlebar",
323 KEY_GENERAL_SCHEMA,
324 META_PREF_ACTION_DOUBLE_CLICK_TITLEBAR,
325 (gint *) &action_double_click_titlebar,
326 },
327 { "action-middle-click-titlebar",
328 KEY_GENERAL_SCHEMA,
329 META_PREF_ACTION_MIDDLE_CLICK_TITLEBAR,
330 (gint *) &action_middle_click_titlebar,
331 },
332 { "action-right-click-titlebar",
333 KEY_GENERAL_SCHEMA,
334 META_PREF_ACTION_RIGHT_CLICK_TITLEBAR,
335 (gint *) &action_right_click_titlebar,
336 },
337 { "placement-mode",
338 KEY_GENERAL_SCHEMA,
339 META_PREF_PLACEMENT_MODE,
340 (gint *) &placement_mode,
341 },
342 { NULL, NULL, 0, NULL },
343 };
344
345 static MetaBoolPreference preferences_bool[] =
346 {
347 { "raise-on-click",
348 KEY_GENERAL_SCHEMA,
349 META_PREF_RAISE_ON_CLICK,
350 &raise_on_click,
351 TRUE,
352 },
353 { "titlebar-uses-system-font",
354 KEY_GENERAL_SCHEMA,
355 META_PREF_TITLEBAR_FONT, /* note! shares a pref */
356 &use_system_font,
357 TRUE,
358 },
359 { "application-based",
360 KEY_GENERAL_SCHEMA,
361 META_PREF_APPLICATION_BASED,
362 NULL, /* feature is known but disabled */
363 FALSE,
364 },
365 { "disable-workarounds",
366 KEY_GENERAL_SCHEMA,
367 META_PREF_DISABLE_WORKAROUNDS,
368 &disable_workarounds,
369 FALSE,
370 },
371 { "auto-raise",
372 KEY_GENERAL_SCHEMA,
373 META_PREF_AUTO_RAISE,
374 &auto_raise,
375 FALSE,
376 },
377 { "visual-bell",
378 KEY_GENERAL_SCHEMA,
379 META_PREF_VISUAL_BELL,
380 &provide_visual_bell, /* FIXME: change the name: it's confusing */
381 FALSE,
382 },
383 { "audible-bell",
384 KEY_GENERAL_SCHEMA,
385 META_PREF_AUDIBLE_BELL,
386 &bell_is_audible, /* FIXME: change the name: it's confusing */
387 FALSE,
388 },
389 { "reduced-resources",
390 KEY_GENERAL_SCHEMA,
391 META_PREF_REDUCED_RESOURCES,
392 &reduced_resources,
393 FALSE,
394 },
395 { "accessibility",
396 KEY_MATE_INTERFACE_SCHEMA,
397 META_PREF_MATE_ACCESSIBILITY,
398 &mate_accessibility,
399 FALSE,
400 },
401 { "enable-animations",
402 KEY_MATE_INTERFACE_SCHEMA,
403 META_PREF_MATE_ANIMATIONS,
404 &mate_animations,
405 TRUE,
406 },
407 { KEY_GENERAL_COMPOSITOR,
408 KEY_GENERAL_SCHEMA,
409 META_PREF_COMPOSITING_MANAGER,
410 &compositing_manager,
411 FALSE,
412 },
413 { "compositing-fast-alt-tab",
414 KEY_GENERAL_SCHEMA,
415 META_PREF_COMPOSITING_FAST_ALT_TAB,
416 &compositing_fast_alt_tab,
417 FALSE,
418 },
419 { "resize-with-right-button",
420 KEY_GENERAL_SCHEMA,
421 META_PREF_RESIZE_WITH_RIGHT_BUTTON,
422 &resize_with_right_button,
423 FALSE,
424 },
425 { "show-tab-border",
426 KEY_GENERAL_SCHEMA,
427 META_PREF_SHOW_TAB_BORDER,
428 &show_tab_border,
429 FALSE,
430 },
431 { "center-new-windows",
432 KEY_GENERAL_SCHEMA,
433 META_PREF_CENTER_NEW_WINDOWS,
434 ¢er_new_windows,
435 FALSE,
436 },
437 { "allow-tiling",
438 KEY_GENERAL_SCHEMA,
439 META_PREF_ALLOW_TILING,
440 &allow_tiling,
441 FALSE,
442 },
443 { "allow-top-tiling",
444 KEY_GENERAL_SCHEMA,
445 META_PREF_ALLOW_TOP_TILING,
446 &allow_top_tiling,
447 FALSE,
448 },
449 { "allow-tile-cycling",
450 KEY_GENERAL_SCHEMA,
451 META_PREF_ALLOW_TILE_CYCLING,
452 &allow_tile_cycling,
453 FALSE,
454 },
455 { "alt-tab-expand-to-fit-title",
456 KEY_GENERAL_SCHEMA,
457 META_PREF_ALT_TAB_EXPAND_TO_FIT_TITLE,
458 &alt_tab_expand_to_fit_title,
459 META_DEFAULT_ALT_TAB_EXPAND_TO_FIT_TITLE,
460 },
461 { NULL, NULL, 0, NULL, FALSE },
462 };
463
464 static MetaStringPreference preferences_string[] =
465 {
466 { "mouse-button-modifier",
467 KEY_GENERAL_SCHEMA,
468 META_PREF_MOUSE_BUTTON_MODS,
469 mouse_button_mods_handler,
470 NULL,
471 },
472 { "theme",
473 KEY_GENERAL_SCHEMA,
474 META_PREF_THEME,
475 theme_name_handler,
476 NULL,
477 },
478 { KEY_GENERAL_TITLEBAR_FONT,
479 KEY_GENERAL_SCHEMA,
480 META_PREF_TITLEBAR_FONT,
481 titlebar_handler,
482 NULL,
483 },
484 { KEY_MATE_TERMINAL_COMMAND,
485 KEY_MATE_TERMINAL_SCHEMA,
486 META_PREF_TERMINAL_COMMAND,
487 NULL,
488 &terminal_command,
489 },
490 { "button-layout",
491 KEY_GENERAL_SCHEMA,
492 META_PREF_BUTTON_LAYOUT,
493 button_layout_handler,
494 NULL,
495 },
496 { "cursor-theme",
497 KEY_MATE_MOUSE_SCHEMA,
498 META_PREF_CURSOR_THEME,
499 NULL,
500 &cursor_theme,
501 },
502 { "show-desktop-skip-list",
503 KEY_GENERAL_SCHEMA,
504 META_PREF_SHOW_DESKTOP_SKIP_LIST,
505 &show_desktop_skip_list_handler,
506 NULL,
507 },
508 { NULL, NULL, 0, NULL, NULL },
509 };
510
511 static MetaIntPreference preferences_int[] =
512 {
513 { "num-workspaces",
514 KEY_GENERAL_SCHEMA,
515 META_PREF_NUM_WORKSPACES,
516 &num_workspaces,
517 /* I would actually recommend we change the destroy value to 4
518 * and get rid of METAINTPREFERENCE_NO_CHANGE_ON_DESTROY entirely.
519 * -- tthurman
520 */
521 1, MAX_REASONABLE_WORKSPACES, METAINTPREFERENCE_NO_CHANGE_ON_DESTROY,
522 },
523 { "auto-raise-delay",
524 KEY_GENERAL_SCHEMA,
525 META_PREF_AUTO_RAISE_DELAY,
526 &auto_raise_delay,
527 0, 10000, 0,
528 /* @@@ Get rid of MAX_REASONABLE_AUTO_RAISE_DELAY */
529 },
530 { "cursor-size",
531 KEY_MATE_MOUSE_SCHEMA,
532 META_PREF_CURSOR_SIZE,
533 &cursor_size,
534 1, 128, 24,
535 },
536 { "icon-size",
537 KEY_GENERAL_SCHEMA,
538 META_PREF_ICON_SIZE,
539 &icon_size,
540 META_MIN_ICON_SIZE, META_MAX_ICON_SIZE, META_DEFAULT_ICON_SIZE,
541 },
542 { "alt-tab-max-columns",
543 KEY_GENERAL_SCHEMA,
544 META_PREF_ALT_TAB_MAX_COLUMNS,
545 &alt_tab_max_columns,
546 META_MIN_ALT_TAB_MAX_COLUMNS,
547 META_MAX_ALT_TAB_MAX_COLUMNS,
548 META_DEFAULT_ALT_TAB_MAX_COLUMNS,
549 },
550 { NULL, NULL, 0, NULL, 0, 0, 0, },
551 };
552
553 static void
handle_preference_init_enum(void)554 handle_preference_init_enum (void)
555 {
556 MetaEnumPreference *cursor = preferences_enum;
557
558 while (cursor->key!=NULL)
559 {
560 gint value;
561
562 if (cursor->target==NULL)
563 {
564 ++cursor;
565 continue;
566 }
567
568 value = g_settings_get_enum (SETTINGS (cursor->schema),
569 cursor->key);
570 *cursor->target = value;
571
572 ++cursor;
573 }
574 }
575
576 static void
handle_preference_init_bool(void)577 handle_preference_init_bool (void)
578 {
579 MetaBoolPreference *cursor = preferences_bool;
580
581 while (cursor->key!=NULL)
582 {
583 if (cursor->target!=NULL)
584 *cursor->target = g_settings_get_boolean (SETTINGS (cursor->schema), cursor->key);
585
586 ++cursor;
587 }
588
589 maybe_give_disable_workarounds_warning ();
590 }
591
592 static void
handle_preference_init_string(void)593 handle_preference_init_string (void)
594 {
595 MetaStringPreference *cursor = preferences_string;
596
597 while (cursor->key!=NULL)
598 {
599 gchar *value;
600 gboolean dummy = TRUE;
601
602 /* the string "value" will be newly allocated */
603 value = g_settings_get_string (SETTINGS (cursor->schema),
604 cursor->key);
605
606 if (cursor->handler)
607 {
608 if (cursor->target)
609 meta_bug ("%s has both a target and a handler\n", cursor->key);
610
611 cursor->handler (cursor->pref, value, &dummy);
612
613 g_free (value);
614 }
615 else if (cursor->target)
616 {
617 if (*(cursor->target))
618 g_free (*(cursor->target));
619
620 *(cursor->target) = value;
621 }
622
623 ++cursor;
624 }
625 }
626
627 static void
handle_preference_init_int(void)628 handle_preference_init_int (void)
629 {
630 MetaIntPreference *cursor = preferences_int;
631
632 while (cursor->key!=NULL)
633 {
634 gint value;
635
636 value = g_settings_get_int (SETTINGS (cursor->schema),
637 cursor->key);
638
639 if (value < cursor->minimum || value > cursor->maximum)
640 {
641 /* FIXME: check if this can be avoided by GSettings */
642 meta_warning (_("%d stored in GSettings key %s is out of range %d to %d\n"),
643 value, cursor->key, cursor->minimum, cursor->maximum);
644 /* Former behaviour for out-of-range values was:
645 * - number of workspaces was clamped;
646 * - auto raise delay was always reset to zero even if too high!;
647 * - cursor size was ignored.
648 *
649 * These seem to be meaningless variations. If they did
650 * have meaning we could have put them into MetaIntPreference.
651 * The last of these is the closest to how we behave for
652 * other types, so I think we should standardise on that.
653 */
654 }
655 else if (cursor->target)
656 *cursor->target = value;
657
658 ++cursor;
659 }
660 }
661
662 static gboolean
handle_preference_update_enum(const gchar * key,GSettings * settings)663 handle_preference_update_enum (const gchar *key, GSettings *settings)
664 {
665 MetaEnumPreference *cursor = preferences_enum;
666 gint old_value;
667
668 while (cursor->key!=NULL && strcmp (key, cursor->key)!=0)
669 ++cursor;
670
671 if (cursor->key==NULL)
672 /* Didn't recognise that key. */
673 return FALSE;
674
675 /* We need to know whether the value changes, so
676 * store the current value away.
677 */
678
679 old_value = * ((gint *) cursor->target);
680
681 /* Now look it up... */
682 *cursor->target = g_settings_get_enum (settings, key);
683
684 /* Did it change? If so, tell the listeners about it. */
685
686 if (old_value != *((gint *) cursor->target))
687 queue_changed (cursor->pref);
688
689 return TRUE;
690 }
691
692 static gboolean
handle_preference_update_bool(const gchar * key,GSettings * settings)693 handle_preference_update_bool (const gchar *key, GSettings *settings)
694 {
695 MetaBoolPreference *cursor = preferences_bool;
696 gboolean old_value;
697
698 while (cursor->key!=NULL && strcmp (key, cursor->key)!=0)
699 ++cursor;
700
701 if (cursor->key==NULL)
702 /* Didn't recognise that key. */
703 return FALSE;
704
705 if (cursor->target==NULL)
706 /* No work for us to do. */
707 return TRUE;
708
709 /* We need to know whether the value changes, so
710 * store the current value away.
711 */
712
713 old_value = * ((gboolean *) cursor->target);
714
715 /* Now look it up... */
716
717 *((gboolean *) cursor->target) = g_settings_get_boolean (settings, key);
718
719 /* Did it change? If so, tell the listeners about it. */
720
721 if (old_value != *((gboolean *) cursor->target))
722 queue_changed (cursor->pref);
723
724 if (cursor->pref==META_PREF_DISABLE_WORKAROUNDS)
725 maybe_give_disable_workarounds_warning ();
726
727 return TRUE;
728 }
729
730 static gboolean
handle_preference_update_string(const gchar * key,GSettings * settings)731 handle_preference_update_string (const gchar *key, GSettings *settings)
732 {
733 MetaStringPreference *cursor = preferences_string;
734 gchar *value;
735 gboolean inform_listeners = TRUE;
736
737 while (cursor->key!=NULL && strcmp (key, cursor->key)!=0)
738 ++cursor;
739
740 if (cursor->key==NULL)
741 /* Didn't recognise that key. */
742 return FALSE;
743
744 value = g_settings_get_string (settings, key);
745
746 if (cursor->handler)
747 cursor->handler (cursor->pref, value, &inform_listeners);
748 else if (cursor->target)
749 {
750 if (*(cursor->target))
751 g_free(*(cursor->target));
752
753 if (value!=NULL)
754 *(cursor->target) = g_strdup (value);
755 else
756 *(cursor->target) = NULL;
757
758 inform_listeners =
759 (value==NULL && *(cursor->target)==NULL) ||
760 (value!=NULL && *(cursor->target)!=NULL &&
761 strcmp (value, *(cursor->target))==0);
762 }
763
764 if (inform_listeners)
765 queue_changed (cursor->pref);
766
767 g_free (value);
768
769 return TRUE;
770 }
771
772 static gboolean
handle_preference_update_int(const gchar * key,GSettings * settings)773 handle_preference_update_int (const gchar *key, GSettings *settings)
774 {
775 MetaIntPreference *cursor = preferences_int;
776 gint value;
777
778 while (cursor->key!=NULL && strcmp (key, cursor->key)!=0)
779 ++cursor;
780
781 if (cursor->key==NULL)
782 /* Didn't recognise that key. */
783 return FALSE;
784
785 if (cursor->target==NULL)
786 /* No work for us to do. */
787 return TRUE;
788
789 value = g_settings_get_int (settings, key);
790
791 if (value < cursor->minimum || value > cursor->maximum)
792 {
793 /* FIXME! GSettings, instead of MateConf, has Minimum/Maximun in schema!
794 * But some preferences depends on costants for minimum/maximum values */
795 meta_warning (_("%d stored in GSettings key %s is out of range %d to %d\n"),
796 value, cursor->key,
797 cursor->minimum, cursor->maximum);
798 return TRUE;
799 }
800
801 /* Did it change? If so, tell the listeners about it. */
802
803 if (*cursor->target != value)
804 {
805 *cursor->target = value;
806 queue_changed (cursor->pref);
807 }
808
809 return TRUE;
810
811 }
812
813 /****************************************************************************/
814 /* Listeners. */
815 /****************************************************************************/
816
817 void
meta_prefs_add_listener(MetaPrefsChangedFunc func,gpointer data)818 meta_prefs_add_listener (MetaPrefsChangedFunc func,
819 gpointer data)
820 {
821 MetaPrefsListener *l;
822
823 l = g_new (MetaPrefsListener, 1);
824 l->func = func;
825 l->data = data;
826
827 listeners = g_list_prepend (listeners, l);
828 }
829
830 void
meta_prefs_remove_listener(MetaPrefsChangedFunc func,gpointer data)831 meta_prefs_remove_listener (MetaPrefsChangedFunc func,
832 gpointer data)
833 {
834 GList *tmp;
835
836 tmp = listeners;
837 while (tmp != NULL)
838 {
839 MetaPrefsListener *l = tmp->data;
840
841 if (l->func == func &&
842 l->data == data)
843 {
844 g_free (l);
845 listeners = g_list_delete_link (listeners, tmp);
846
847 return;
848 }
849
850 tmp = tmp->next;
851 }
852
853 meta_bug ("Did not find listener to remove\n");
854 }
855
856 static void
emit_changed(MetaPreference pref)857 emit_changed (MetaPreference pref)
858 {
859 GList *tmp;
860 GList *copy;
861
862 meta_topic (META_DEBUG_PREFS, "Notifying listeners that pref %s changed\n",
863 meta_preference_to_string (pref));
864
865 copy = g_list_copy (listeners);
866
867 tmp = copy;
868
869 while (tmp != NULL)
870 {
871 MetaPrefsListener *l = tmp->data;
872
873 (* l->func) (pref, l->data);
874
875 tmp = tmp->next;
876 }
877
878 g_list_free (copy);
879 }
880
881 static gboolean
changed_idle_handler(gpointer data)882 changed_idle_handler (gpointer data)
883 {
884 GList *tmp;
885 GList *copy;
886
887 changed_idle = 0;
888
889 copy = g_list_copy (changes); /* reentrancy paranoia */
890
891 g_list_free (changes);
892 changes = NULL;
893
894 tmp = copy;
895 while (tmp != NULL)
896 {
897 MetaPreference pref = GPOINTER_TO_INT (tmp->data);
898
899 emit_changed (pref);
900
901 tmp = tmp->next;
902 }
903
904 g_list_free (copy);
905
906 return FALSE;
907 }
908
909 static void
queue_changed(MetaPreference pref)910 queue_changed (MetaPreference pref)
911 {
912 meta_topic (META_DEBUG_PREFS, "Queueing change of pref %s\n",
913 meta_preference_to_string (pref));
914
915 if (g_list_find (changes, GINT_TO_POINTER (pref)) == NULL)
916 changes = g_list_prepend (changes, GINT_TO_POINTER (pref));
917 else
918 meta_topic (META_DEBUG_PREFS, "Change of pref %s was already pending\n",
919 meta_preference_to_string (pref));
920
921 /* add idle at priority below the GSettings notify idle */
922 /* FIXME is this needed for GSettings too? */
923 if (changed_idle == 0)
924 changed_idle = g_idle_add_full (META_PRIORITY_PREFS_NOTIFY,
925 changed_idle_handler, NULL, NULL);
926 }
927
928 /****************************************************************************/
929 /* Initialisation. */
930 /****************************************************************************/
931
932 void
meta_prefs_init(void)933 meta_prefs_init (void)
934 {
935 if (settings_general != NULL)
936 return;
937
938 /* returns references which we hold forever */
939 settings_general = g_settings_new (KEY_GENERAL_SCHEMA);
940 settings_command = g_settings_new (KEY_COMMAND_SCHEMA);
941 settings_screen_bindings = g_settings_new (KEY_SCREEN_BINDINGS_SCHEMA);
942 settings_window_bindings = g_settings_new (KEY_WINDOW_BINDINGS_SCHEMA);
943 settings_workspace_names = g_settings_new (KEY_WORKSPACE_NAME_SCHEMA);
944 settings_mate_interface = g_settings_new (KEY_MATE_INTERFACE_SCHEMA);
945 settings_mate_terminal = g_settings_new (KEY_MATE_TERMINAL_SCHEMA);
946 settings_mate_mouse = g_settings_new (KEY_MATE_MOUSE_SCHEMA);
947
948 settings_schemas = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref);
949 g_hash_table_insert (settings_schemas, KEY_GENERAL_SCHEMA, settings_general);
950 g_hash_table_insert (settings_schemas, KEY_COMMAND_SCHEMA, settings_command);
951 g_hash_table_insert (settings_schemas, KEY_SCREEN_BINDINGS_SCHEMA, settings_screen_bindings);
952 g_hash_table_insert (settings_schemas, KEY_WINDOW_BINDINGS_SCHEMA, settings_window_bindings);
953 g_hash_table_insert (settings_schemas, KEY_WORKSPACE_NAME_SCHEMA, settings_workspace_names);
954 g_hash_table_insert (settings_schemas, KEY_MATE_INTERFACE_SCHEMA, settings_mate_interface);
955 g_hash_table_insert (settings_schemas, KEY_MATE_TERMINAL_SCHEMA, settings_mate_terminal);
956 g_hash_table_insert (settings_schemas, KEY_MATE_MOUSE_SCHEMA, settings_mate_mouse);
957
958 g_signal_connect (settings_general, "changed", G_CALLBACK (change_notify), NULL);
959 g_signal_connect (settings_command, "changed", G_CALLBACK (change_notify), NULL);
960 g_signal_connect (settings_screen_bindings, "changed", G_CALLBACK (change_notify), NULL);
961 g_signal_connect (settings_window_bindings, "changed", G_CALLBACK (change_notify), NULL);
962 g_signal_connect (settings_workspace_names, "changed", G_CALLBACK (change_notify), NULL);
963
964 g_signal_connect (settings_mate_interface, "changed::" KEY_MATE_INTERFACE_ACCESSIBILITY, G_CALLBACK (change_notify), NULL);
965 g_signal_connect (settings_mate_interface, "changed::" KEY_MATE_INTERFACE_ENABLE_ANIMATIONS, G_CALLBACK (change_notify), NULL);
966 g_signal_connect (settings_mate_terminal, "changed::" KEY_MATE_TERMINAL_COMMAND, G_CALLBACK (change_notify), NULL);
967 g_signal_connect (settings_mate_mouse, "changed::" KEY_MATE_MOUSE_CURSOR_THEME, G_CALLBACK (change_notify), NULL);
968 g_signal_connect (settings_mate_mouse, "changed::" KEY_MATE_MOUSE_CURSOR_SIZE, G_CALLBACK (change_notify), NULL);
969
970 /* Pick up initial values. */
971
972 handle_preference_init_enum ();
973 handle_preference_init_bool ();
974 handle_preference_init_string ();
975 handle_preference_init_int ();
976
977 init_screen_bindings ();
978 init_window_bindings ();
979 init_commands ();
980 init_workspace_names ();
981 }
982
983 /****************************************************************************/
984 /* Updates. */
985 /****************************************************************************/
986
987 gboolean (*preference_update_handler[]) (const gchar*, GSettings*) = {
988 handle_preference_update_enum,
989 handle_preference_update_bool,
990 handle_preference_update_string,
991 handle_preference_update_int,
992 NULL
993 };
994
995 static void
change_notify(GSettings * settings,gchar * key,gpointer user_data)996 change_notify (GSettings *settings,
997 gchar *key,
998 gpointer user_data)
999 {
1000 gint i=0;
1001
1002 /* First, search for a handler that might know what to do. */
1003
1004 /* FIXME: When this is all working, since the first item in every
1005 * array is the gchar* of the key, there's no reason we can't
1006 * find the correct record for that key here and save code duplication.
1007 */
1008
1009 while (preference_update_handler[i]!=NULL)
1010 {
1011 if (preference_update_handler[i] (key, settings))
1012 return; /* Get rid of this eventually */
1013
1014 i++;
1015 }
1016
1017 gchar *schema_name = NULL;
1018 g_object_get (settings, "schema-id", &schema_name, NULL);
1019
1020 if (g_strcmp0 (schema_name, KEY_WINDOW_BINDINGS_SCHEMA) == 0 ||
1021 g_strcmp0 (schema_name, KEY_SCREEN_BINDINGS_SCHEMA) == 0)
1022 {
1023 gchar *str;
1024 str = g_settings_get_string (settings, key);
1025
1026 if (update_key_binding (key, str))
1027 queue_changed (META_PREF_KEYBINDINGS);
1028
1029 g_free(str);
1030 }
1031 else if (g_strcmp0 (schema_name, KEY_COMMAND_SCHEMA) == 0)
1032 {
1033 gchar *str;
1034 str = g_settings_get_string (settings, key);
1035
1036 if (update_command (key, str))
1037 queue_changed (META_PREF_COMMANDS);
1038
1039 g_free(str);
1040 }
1041 else if (g_strcmp0 (schema_name, KEY_WORKSPACE_NAME_SCHEMA) == 0)
1042 {
1043 gchar *str;
1044 str = g_settings_get_string (settings, key);
1045
1046 if (update_workspace_name (key, str))
1047 queue_changed (META_PREF_WORKSPACE_NAMES);
1048
1049 g_free(str);
1050 }
1051 else
1052 {
1053 /* Is this possible with GSettings? I dont think so! */
1054 meta_topic (META_DEBUG_PREFS, "Key %s doesn't mean anything to Marco\n",
1055 key);
1056 }
1057 g_free (schema_name);
1058 }
1059
1060 #if 0
1061 static void
1062 cleanup_error (GError **error)
1063 {
1064 if (*error)
1065 {
1066 meta_warning ("%s\n", (*error)->message);
1067
1068 g_error_free (*error);
1069 *error = NULL;
1070 }
1071 }
1072 #endif
1073
1074 /**
1075 * Special case: give a warning the first time disable_workarounds
1076 * is turned on.
1077 */
1078 static void
maybe_give_disable_workarounds_warning(void)1079 maybe_give_disable_workarounds_warning (void)
1080 {
1081 static gboolean first_disable = TRUE;
1082
1083 if (first_disable && disable_workarounds)
1084 {
1085 first_disable = FALSE;
1086
1087 meta_warning (_("Workarounds for broken applications disabled. "
1088 "Some applications may not behave properly.\n"));
1089 }
1090 }
1091
1092 MetaVirtualModifier
meta_prefs_get_mouse_button_mods(void)1093 meta_prefs_get_mouse_button_mods (void)
1094 {
1095 return mouse_button_mods;
1096 }
1097
1098 MetaFocusMode
meta_prefs_get_focus_mode(void)1099 meta_prefs_get_focus_mode (void)
1100 {
1101 return focus_mode;
1102 }
1103
1104 MetaFocusNewWindows
meta_prefs_get_focus_new_windows(void)1105 meta_prefs_get_focus_new_windows (void)
1106 {
1107 return focus_new_windows;
1108 }
1109
1110 gboolean
meta_prefs_get_attach_modal_dialogs(void)1111 meta_prefs_get_attach_modal_dialogs (void)
1112 {
1113 return attach_modal_dialogs;
1114 }
1115
1116 gboolean
meta_prefs_get_raise_on_click(void)1117 meta_prefs_get_raise_on_click (void)
1118 {
1119 return raise_on_click;
1120 }
1121
1122 const char*
meta_prefs_get_theme(void)1123 meta_prefs_get_theme (void)
1124 {
1125 return current_theme;
1126 }
1127
1128 const char*
meta_prefs_get_cursor_theme(void)1129 meta_prefs_get_cursor_theme (void)
1130 {
1131 return cursor_theme;
1132 }
1133
1134 int
meta_prefs_get_cursor_size(void)1135 meta_prefs_get_cursor_size (void)
1136 {
1137 GdkWindow *window = gdk_get_default_root_window ();
1138 gint scale = gdk_window_get_scale_factor (window);
1139
1140 return cursor_size * scale;
1141 }
1142
1143 int
meta_prefs_get_icon_size(void)1144 meta_prefs_get_icon_size (void)
1145 {
1146 GdkWindow *window = gdk_get_default_root_window ();
1147 gint scale = gdk_window_get_scale_factor (window);
1148
1149 return icon_size * scale;
1150 }
1151
1152 int
meta_prefs_get_alt_tab_max_columns(void)1153 meta_prefs_get_alt_tab_max_columns (void)
1154 {
1155 return alt_tab_max_columns;
1156 }
1157
1158 gboolean
meta_prefs_get_alt_tab_expand_to_fit_title(void)1159 meta_prefs_get_alt_tab_expand_to_fit_title (void)
1160 {
1161 return alt_tab_expand_to_fit_title;
1162 }
1163
1164 gboolean
meta_prefs_is_in_skip_list(char * class)1165 meta_prefs_is_in_skip_list (char *class)
1166 {
1167 GList *item;
1168
1169 for (item = show_desktop_skip_list; item; item = item->next)
1170 {
1171 if (!g_ascii_strcasecmp (class, item->data))
1172 return TRUE;
1173 }
1174 return FALSE;
1175 }
1176
1177 /****************************************************************************/
1178 /* Handlers for string preferences. */
1179 /****************************************************************************/
1180
1181 static void
titlebar_handler(MetaPreference pref,const gchar * string_value,gboolean * inform_listeners)1182 titlebar_handler (MetaPreference pref,
1183 const gchar *string_value,
1184 gboolean *inform_listeners)
1185 {
1186 PangoFontDescription *new_desc = NULL;
1187
1188 if (string_value)
1189 new_desc = pango_font_description_from_string (string_value);
1190
1191 if (new_desc == NULL)
1192 {
1193 meta_warning (_("Could not parse font description "
1194 "\"%s\" from GSettings key %s\n"),
1195 string_value ? string_value : "(null)",
1196 KEY_GENERAL_TITLEBAR_FONT);
1197
1198 *inform_listeners = FALSE;
1199
1200 return;
1201 }
1202
1203 /* Is the new description the same as the old? */
1204
1205 if (titlebar_font &&
1206 pango_font_description_equal (new_desc, titlebar_font))
1207 {
1208 pango_font_description_free (new_desc);
1209 *inform_listeners = FALSE;
1210 return;
1211 }
1212
1213 /* No, so free the old one and put ours in instead. */
1214
1215 if (titlebar_font)
1216 pango_font_description_free (titlebar_font);
1217
1218 titlebar_font = new_desc;
1219
1220 }
1221
1222 static void
theme_name_handler(MetaPreference pref,const gchar * string_value,gboolean * inform_listeners)1223 theme_name_handler (MetaPreference pref,
1224 const gchar *string_value,
1225 gboolean *inform_listeners)
1226 {
1227 g_free (current_theme);
1228
1229 /* Fallback crackrock */
1230 if (string_value == NULL)
1231 current_theme = g_strdup ("ClearlooksRe");
1232 else
1233 current_theme = g_strdup (string_value);
1234 }
1235
1236 static void
mouse_button_mods_handler(MetaPreference pref,const gchar * string_value,gboolean * inform_listeners)1237 mouse_button_mods_handler (MetaPreference pref,
1238 const gchar *string_value,
1239 gboolean *inform_listeners)
1240 {
1241 MetaVirtualModifier mods;
1242
1243 meta_topic (META_DEBUG_KEYBINDINGS,
1244 "Mouse button modifier has new GSettings value \"%s\"\n",
1245 string_value);
1246 if (string_value && meta_ui_parse_modifier (string_value, &mods))
1247 {
1248 mouse_button_mods = mods;
1249 }
1250 else
1251 {
1252 meta_topic (META_DEBUG_KEYBINDINGS,
1253 "Failed to parse new GSettings value\n");
1254
1255 meta_warning (_("\"%s\" found in configuration database is "
1256 "not a valid value for mouse button modifier\n"),
1257 string_value);
1258
1259 *inform_listeners = FALSE;
1260 }
1261 }
1262
1263 static void
show_desktop_skip_list_handler(MetaPreference pref,const gchar * string_value,gboolean * inform_listeners)1264 show_desktop_skip_list_handler (MetaPreference pref,
1265 const gchar *string_value,
1266 gboolean *inform_listeners)
1267 {
1268 gchar **tokens;
1269 gchar **tok;
1270 GList *item;
1271
1272 if (show_desktop_skip_list)
1273 {
1274 for (item = show_desktop_skip_list; item; item = item->next)
1275 g_free (item->data);
1276 g_list_free (show_desktop_skip_list);
1277 show_desktop_skip_list = NULL;
1278 }
1279
1280 if (!(tokens = g_strsplit (string_value, ",", -1)))
1281 return;
1282 for (tok = tokens; tok && *tok; tok++)
1283 {
1284 gchar *stripped = g_strstrip (g_strdup (*tok));
1285 show_desktop_skip_list = g_list_prepend (show_desktop_skip_list, stripped);
1286 }
1287 g_strfreev (tokens);
1288 }
1289
1290 static gboolean
button_layout_equal(const MetaButtonLayout * a,const MetaButtonLayout * b)1291 button_layout_equal (const MetaButtonLayout *a,
1292 const MetaButtonLayout *b)
1293 {
1294 int i;
1295
1296 i = 0;
1297 while (i < MAX_BUTTONS_PER_CORNER)
1298 {
1299 if (a->left_buttons[i] != b->left_buttons[i])
1300 return FALSE;
1301 if (a->right_buttons[i] != b->right_buttons[i])
1302 return FALSE;
1303 if (a->left_buttons_has_spacer[i] != b->left_buttons_has_spacer[i])
1304 return FALSE;
1305 if (a->right_buttons_has_spacer[i] != b->right_buttons_has_spacer[i])
1306 return FALSE;
1307 ++i;
1308 }
1309
1310 return TRUE;
1311 }
1312
1313 static MetaButtonFunction
button_function_from_string(const char * str)1314 button_function_from_string (const char *str)
1315 {
1316 /* FIXME: g_settings_get_enum is the obvious way to do this */
1317
1318 if (strcmp (str, "menu") == 0)
1319 return META_BUTTON_FUNCTION_MENU;
1320 else if (strcmp (str, "appmenu") == 0)
1321 return META_BUTTON_FUNCTION_APPMENU;
1322 else if (strcmp (str, "minimize") == 0)
1323 return META_BUTTON_FUNCTION_MINIMIZE;
1324 else if (strcmp (str, "maximize") == 0)
1325 return META_BUTTON_FUNCTION_MAXIMIZE;
1326 else if (strcmp (str, "close") == 0)
1327 return META_BUTTON_FUNCTION_CLOSE;
1328 else if (strcmp (str, "shade") == 0)
1329 return META_BUTTON_FUNCTION_SHADE;
1330 else if (strcmp (str, "above") == 0)
1331 return META_BUTTON_FUNCTION_ABOVE;
1332 else if (strcmp (str, "stick") == 0)
1333 return META_BUTTON_FUNCTION_STICK;
1334 else
1335 /* don't know; give up */
1336 return META_BUTTON_FUNCTION_LAST;
1337 }
1338
1339 static MetaButtonFunction
button_opposite_function(MetaButtonFunction ofwhat)1340 button_opposite_function (MetaButtonFunction ofwhat)
1341 {
1342 switch (ofwhat)
1343 {
1344 case META_BUTTON_FUNCTION_SHADE:
1345 return META_BUTTON_FUNCTION_UNSHADE;
1346 case META_BUTTON_FUNCTION_UNSHADE:
1347 return META_BUTTON_FUNCTION_SHADE;
1348
1349 case META_BUTTON_FUNCTION_ABOVE:
1350 return META_BUTTON_FUNCTION_UNABOVE;
1351 case META_BUTTON_FUNCTION_UNABOVE:
1352 return META_BUTTON_FUNCTION_ABOVE;
1353
1354 case META_BUTTON_FUNCTION_STICK:
1355 return META_BUTTON_FUNCTION_UNSTICK;
1356 case META_BUTTON_FUNCTION_UNSTICK:
1357 return META_BUTTON_FUNCTION_STICK;
1358
1359 default:
1360 return META_BUTTON_FUNCTION_LAST;
1361 }
1362 }
1363
1364 static void
button_layout_handler(MetaPreference pref,const gchar * string_value,gboolean * inform_listeners)1365 button_layout_handler (MetaPreference pref,
1366 const gchar *string_value,
1367 gboolean *inform_listeners)
1368 {
1369 MetaButtonLayout new_layout;
1370 char **sides = NULL;
1371 int i;
1372
1373 /* We need to ignore unknown button functions, for
1374 * compat with future versions
1375 */
1376
1377 if (string_value)
1378 sides = g_strsplit (string_value, ":", 2);
1379
1380 if (sides != NULL && sides[0] != NULL)
1381 {
1382 char **buttons;
1383 int b;
1384 gboolean used[META_BUTTON_FUNCTION_LAST];
1385
1386 i = 0;
1387 while (i < META_BUTTON_FUNCTION_LAST)
1388 {
1389 used[i] = FALSE;
1390 new_layout.left_buttons_has_spacer[i] = FALSE;
1391 ++i;
1392 }
1393
1394 buttons = g_strsplit (sides[0], ",", -1);
1395 i = 0;
1396 b = 0;
1397 while (buttons[b] != NULL)
1398 {
1399 MetaButtonFunction f = button_function_from_string (buttons[b]);
1400 if (i > 0 && strcmp("spacer", buttons[b]) == 0)
1401 {
1402 new_layout.left_buttons_has_spacer[i-1] = TRUE;
1403 f = button_opposite_function (f);
1404
1405 if (f != META_BUTTON_FUNCTION_LAST)
1406 {
1407 new_layout.left_buttons_has_spacer[i-2] = TRUE;
1408 }
1409 }
1410 else
1411 {
1412 if (f != META_BUTTON_FUNCTION_LAST && !used[f])
1413 {
1414 new_layout.left_buttons[i] = f;
1415 used[f] = TRUE;
1416 ++i;
1417
1418 f = button_opposite_function (f);
1419
1420 if (f != META_BUTTON_FUNCTION_LAST)
1421 new_layout.left_buttons[i++] = f;
1422
1423 }
1424 else
1425 {
1426 meta_topic (META_DEBUG_PREFS, "Ignoring unknown or already-used button name \"%s\"\n",
1427 buttons[b]);
1428 }
1429 }
1430
1431 ++b;
1432 }
1433
1434 new_layout.left_buttons[i] = META_BUTTON_FUNCTION_LAST;
1435 new_layout.left_buttons_has_spacer[i] = FALSE;
1436
1437 g_strfreev (buttons);
1438 }
1439
1440 if (sides != NULL && sides[0] != NULL && sides[1] != NULL)
1441 {
1442 char **buttons;
1443 int b;
1444 gboolean used[META_BUTTON_FUNCTION_LAST];
1445
1446 i = 0;
1447 while (i < META_BUTTON_FUNCTION_LAST)
1448 {
1449 used[i] = FALSE;
1450 new_layout.right_buttons_has_spacer[i] = FALSE;
1451 ++i;
1452 }
1453
1454 buttons = g_strsplit (sides[1], ",", -1);
1455 i = 0;
1456 b = 0;
1457 while (buttons[b] != NULL)
1458 {
1459 MetaButtonFunction f = button_function_from_string (buttons[b]);
1460 if (i > 0 && strcmp("spacer", buttons[b]) == 0)
1461 {
1462 new_layout.right_buttons_has_spacer[i-1] = TRUE;
1463 f = button_opposite_function (f);
1464 if (f != META_BUTTON_FUNCTION_LAST)
1465 {
1466 new_layout.right_buttons_has_spacer[i-2] = TRUE;
1467 }
1468 }
1469 else
1470 {
1471 if (f != META_BUTTON_FUNCTION_LAST && !used[f])
1472 {
1473 new_layout.right_buttons[i] = f;
1474 used[f] = TRUE;
1475 ++i;
1476
1477 f = button_opposite_function (f);
1478
1479 if (f != META_BUTTON_FUNCTION_LAST)
1480 new_layout.right_buttons[i++] = f;
1481
1482 }
1483 else
1484 {
1485 meta_topic (META_DEBUG_PREFS, "Ignoring unknown or already-used button name \"%s\"\n",
1486 buttons[b]);
1487 }
1488 }
1489
1490 ++b;
1491 }
1492
1493 new_layout.right_buttons[i] = META_BUTTON_FUNCTION_LAST;
1494 new_layout.right_buttons_has_spacer[i] = FALSE;
1495
1496 g_strfreev (buttons);
1497 }
1498
1499 g_strfreev (sides);
1500
1501 /* Invert the button layout for RTL languages */
1502 if (meta_ui_get_direction() == META_UI_DIRECTION_RTL)
1503 {
1504 MetaButtonLayout rtl_layout;
1505 int j;
1506
1507 for (i = 0; new_layout.left_buttons[i] != META_BUTTON_FUNCTION_LAST; i++);
1508 for (j = 0; j < i; j++)
1509 {
1510 rtl_layout.right_buttons[j] = new_layout.left_buttons[i - j - 1];
1511 if (j == 0)
1512 rtl_layout.right_buttons_has_spacer[i - 1] = new_layout.left_buttons_has_spacer[i - j - 1];
1513 else
1514 rtl_layout.right_buttons_has_spacer[j - 1] = new_layout.left_buttons_has_spacer[i - j - 1];
1515 }
1516 rtl_layout.right_buttons[j] = META_BUTTON_FUNCTION_LAST;
1517 rtl_layout.right_buttons_has_spacer[j] = FALSE;
1518
1519 for (i = 0; new_layout.right_buttons[i] != META_BUTTON_FUNCTION_LAST; i++);
1520 for (j = 0; j < i; j++)
1521 {
1522 rtl_layout.left_buttons[j] = new_layout.right_buttons[i - j - 1];
1523 if (j == 0)
1524 rtl_layout.left_buttons_has_spacer[i - 1] = new_layout.right_buttons_has_spacer[i - j - 1];
1525 else
1526 rtl_layout.left_buttons_has_spacer[j - 1] = new_layout.right_buttons_has_spacer[i - j - 1];
1527 }
1528 rtl_layout.left_buttons[j] = META_BUTTON_FUNCTION_LAST;
1529 rtl_layout.left_buttons_has_spacer[j] = FALSE;
1530
1531 new_layout = rtl_layout;
1532 }
1533
1534 if (button_layout_equal (&button_layout, &new_layout))
1535 {
1536 /* Same as before, so duck out */
1537 *inform_listeners = FALSE;
1538 }
1539 else
1540 {
1541 button_layout = new_layout;
1542 }
1543 }
1544
1545 const PangoFontDescription*
meta_prefs_get_titlebar_font(void)1546 meta_prefs_get_titlebar_font (void)
1547 {
1548 if (use_system_font)
1549 return NULL;
1550 else
1551 return titlebar_font;
1552 }
1553
1554 int
meta_prefs_get_num_workspaces(void)1555 meta_prefs_get_num_workspaces (void)
1556 {
1557 return num_workspaces;
1558 }
1559
1560 MetaWrapStyle
meta_prefs_get_wrap_style(void)1561 meta_prefs_get_wrap_style (void)
1562 {
1563 return wrap_style;
1564 }
1565
1566 gboolean
meta_prefs_get_application_based(void)1567 meta_prefs_get_application_based (void)
1568 {
1569 return FALSE; /* For now, we never want this to do anything */
1570
1571 return application_based;
1572 }
1573
1574 gboolean
meta_prefs_get_disable_workarounds(void)1575 meta_prefs_get_disable_workarounds (void)
1576 {
1577 return disable_workarounds;
1578 }
1579
1580 #define MAX_REASONABLE_AUTO_RAISE_DELAY 10000
1581
1582 #ifdef WITH_VERBOSE_MODE
1583 const char*
meta_preference_to_string(MetaPreference pref)1584 meta_preference_to_string (MetaPreference pref)
1585 {
1586 /* FIXME: another case for g_settings_get_enum */
1587 switch (pref)
1588 {
1589 case META_PREF_MOUSE_BUTTON_MODS:
1590 return "MOUSE_BUTTON_MODS";
1591
1592 case META_PREF_FOCUS_MODE:
1593 return "FOCUS_MODE";
1594
1595 case META_PREF_FOCUS_NEW_WINDOWS:
1596 return "FOCUS_NEW_WINDOWS";
1597
1598 case META_PREF_ATTACH_MODAL_DIALOGS:
1599 return "ATTACH_MODAL_DIALOGS";
1600
1601 case META_PREF_RAISE_ON_CLICK:
1602 return "RAISE_ON_CLICK";
1603
1604 case META_PREF_THEME:
1605 return "THEME";
1606
1607 case META_PREF_TITLEBAR_FONT:
1608 return "TITLEBAR_FONT";
1609
1610 case META_PREF_NUM_WORKSPACES:
1611 return "NUM_WORKSPACES";
1612
1613 case META_PREF_WRAP_STYLE:
1614 return "WRAP_STYLE";
1615
1616 case META_PREF_APPLICATION_BASED:
1617 return "APPLICATION_BASED";
1618
1619 case META_PREF_KEYBINDINGS:
1620 return "KEYBINDINGS";
1621
1622 case META_PREF_DISABLE_WORKAROUNDS:
1623 return "DISABLE_WORKAROUNDS";
1624
1625 case META_PREF_ACTION_DOUBLE_CLICK_TITLEBAR:
1626 return "ACTION_DOUBLE_CLICK_TITLEBAR";
1627
1628 case META_PREF_ACTION_MIDDLE_CLICK_TITLEBAR:
1629 return "ACTION_MIDDLE_CLICK_TITLEBAR";
1630
1631 case META_PREF_ACTION_RIGHT_CLICK_TITLEBAR:
1632 return "ACTION_RIGHT_CLICK_TITLEBAR";
1633
1634 case META_PREF_AUTO_RAISE:
1635 return "AUTO_RAISE";
1636
1637 case META_PREF_AUTO_RAISE_DELAY:
1638 return "AUTO_RAISE_DELAY";
1639
1640 case META_PREF_COMMANDS:
1641 return "COMMANDS";
1642
1643 case META_PREF_TERMINAL_COMMAND:
1644 return "TERMINAL_COMMAND";
1645
1646 case META_PREF_BUTTON_LAYOUT:
1647 return "BUTTON_LAYOUT";
1648
1649 case META_PREF_WORKSPACE_NAMES:
1650 return "WORKSPACE_NAMES";
1651
1652 case META_PREF_VISUAL_BELL:
1653 return "VISUAL_BELL";
1654
1655 case META_PREF_AUDIBLE_BELL:
1656 return "AUDIBLE_BELL";
1657
1658 case META_PREF_VISUAL_BELL_TYPE:
1659 return "VISUAL_BELL_TYPE";
1660
1661 case META_PREF_REDUCED_RESOURCES:
1662 return "REDUCED_RESOURCES";
1663
1664 case META_PREF_MATE_ACCESSIBILITY:
1665 return "MATE_ACCESSIBILTY";
1666
1667 case META_PREF_MATE_ANIMATIONS:
1668 return "MATE_ANIMATIONS";
1669
1670 case META_PREF_CURSOR_THEME:
1671 return "CURSOR_THEME";
1672
1673 case META_PREF_CURSOR_SIZE:
1674 return "CURSOR_SIZE";
1675
1676 case META_PREF_ICON_SIZE:
1677 return "ICON_SIZE";
1678
1679 case META_PREF_ALT_TAB_MAX_COLUMNS:
1680 return "ALT_TAB_MAX_COLUMNS";
1681
1682 case META_PREF_ALT_TAB_EXPAND_TO_FIT_TITLE:
1683 return "ALT_TAB_EXPAND_TO_FIT_TITLE";
1684
1685 case META_PREF_COMPOSITING_MANAGER:
1686 return "COMPOSITING_MANAGER";
1687
1688 case META_PREF_COMPOSITING_FAST_ALT_TAB:
1689 return "COMPOSITING_FAST_ALT_TAB";
1690
1691 case META_PREF_CENTER_NEW_WINDOWS:
1692 return "CENTER_NEW_WINDOWS";
1693
1694 case META_PREF_RESIZE_WITH_RIGHT_BUTTON:
1695 return "RESIZE_WITH_RIGHT_BUTTON";
1696
1697 case META_PREF_SHOW_TAB_BORDER:
1698 return "SHOW_TAB_BORDER";
1699
1700 case META_PREF_FORCE_FULLSCREEN:
1701 return "FORCE_FULLSCREEN";
1702
1703 case META_PREF_ALLOW_TILING:
1704 return "ALLOW_TILING";
1705
1706 case META_PREF_ALLOW_TOP_TILING:
1707 return "ALLOW_TOP_TILING";
1708
1709 case META_PREF_ALLOW_TILE_CYCLING:
1710 return "ALLOW_TILE_CYCLING";
1711
1712 case META_PREF_PLACEMENT_MODE:
1713 return "PLACEMENT_MODE";
1714
1715 case META_PREF_SHOW_DESKTOP_SKIP_LIST:
1716 return "SHOW_DESKTOP_SKIP_LIST";
1717 }
1718
1719 return "(unknown)";
1720 }
1721 #endif /* WITH_VERBOSE_MODE */
1722
1723 void
meta_prefs_set_num_workspaces(int n_workspaces)1724 meta_prefs_set_num_workspaces (int n_workspaces)
1725 {
1726 if (n_workspaces < 1)
1727 n_workspaces = 1;
1728 if (n_workspaces > MAX_REASONABLE_WORKSPACES)
1729 n_workspaces = MAX_REASONABLE_WORKSPACES;
1730
1731 g_settings_set_int (settings_general,
1732 KEY_GENERAL_NUM_WORKSPACES,
1733 n_workspaces);
1734
1735 }
1736
1737 #define keybind(name, handler, param, flags) \
1738 { #name, NULL, !!(flags & BINDING_REVERSES), !!(flags & BINDING_PER_WINDOW) },
1739 static MetaKeyPref key_bindings[] = {
1740 #include "all-keybindings.h"
1741 { NULL, NULL, FALSE }
1742 };
1743 #undef keybind
1744
1745 static void
init_bindings(GSettings * settings)1746 init_bindings (GSettings *settings)
1747 {
1748 GSettingsSchema *schema;
1749 gchar **list = NULL;
1750 gchar *str_val = NULL;
1751
1752 g_object_get (settings, "settings-schema", &schema, NULL);
1753 list = g_settings_schema_list_keys (schema);
1754 g_settings_schema_unref (schema);
1755
1756 while (*list != NULL)
1757 {
1758 str_val = g_settings_get_string (settings, *list);
1759 update_key_binding (*list, str_val);
1760 list++;
1761 }
1762
1763 g_free (str_val);
1764 }
1765
1766 static void
init_screen_bindings(void)1767 init_screen_bindings (void)
1768 {
1769 init_bindings (settings_screen_bindings);
1770 }
1771
1772 static void
init_window_bindings(void)1773 init_window_bindings (void)
1774 {
1775 init_bindings (settings_window_bindings);
1776 }
1777
1778 static void
init_commands(void)1779 init_commands (void)
1780 {
1781 GSettingsSchema *schema;
1782 gchar **list = NULL;
1783 gchar *str_val = NULL;
1784
1785 g_object_get (settings_command, "settings-schema", &schema, NULL);
1786 list = g_settings_schema_list_keys (schema);
1787 g_settings_schema_unref (schema);
1788
1789 while (*list != NULL)
1790 {
1791 str_val = g_settings_get_string (settings_command, *list);
1792 update_command (*list, str_val);
1793 list++;
1794 }
1795
1796 g_free (str_val);
1797 }
1798
1799 static void
init_workspace_names(void)1800 init_workspace_names (void)
1801 {
1802 GSettingsSchema *schema;
1803 gchar **list = NULL;
1804 gchar *str_val = NULL;
1805
1806 g_object_get (settings_workspace_names, "settings-schema", &schema, NULL);
1807 list = g_settings_schema_list_keys (schema);
1808 g_settings_schema_unref (schema);
1809
1810 while (*list != NULL)
1811 {
1812 str_val = g_settings_get_string (settings_workspace_names, *list);
1813 update_workspace_name (*list, str_val);
1814 list++;
1815 }
1816
1817 g_free (str_val);
1818 }
1819
1820 static gboolean
update_binding(MetaKeyPref * binding,gchar * value)1821 update_binding (MetaKeyPref *binding,
1822 gchar *value)
1823 {
1824 unsigned int keysym;
1825 unsigned int keycode;
1826 MetaVirtualModifier mods;
1827 MetaKeyCombo *combo;
1828 gboolean changed;
1829
1830 meta_topic (META_DEBUG_KEYBINDINGS,
1831 "Binding \"%s\" has new GSettings value \"%s\"\n",
1832 binding->name, value ? value : "none");
1833
1834 keysym = 0;
1835 keycode = 0;
1836 mods = 0;
1837 if (value)
1838 {
1839 if (!meta_ui_parse_accelerator (value, &keysym, &keycode, &mods))
1840 {
1841 meta_topic (META_DEBUG_KEYBINDINGS,
1842 "Failed to parse new GSettings value\n");
1843 meta_warning (_("\"%s\" found in configuration database is not a valid value for keybinding \"%s\"\n"),
1844 value, binding->name);
1845
1846 return FALSE;
1847 }
1848 }
1849
1850 /* If there isn't already a first element, make one. */
1851 if (!binding->bindings)
1852 {
1853 MetaKeyCombo *blank = g_malloc0 (sizeof (MetaKeyCombo));
1854 binding->bindings = g_slist_alloc();
1855 binding->bindings->data = blank;
1856 }
1857
1858 combo = binding->bindings->data;
1859
1860 /* Bug 329676: Bindings which can be shifted must not have no modifiers,
1861 * nor only SHIFT as a modifier.
1862 */
1863
1864 if (binding->add_shift &&
1865 0 != keysym &&
1866 (META_VIRTUAL_SHIFT_MASK == mods || 0 == mods))
1867 {
1868 gchar *old_setting;
1869
1870 meta_warning ("Cannot bind \"%s\" to %s: it needs a modifier "
1871 "such as Ctrl or Alt.\n",
1872 binding->name,
1873 value);
1874
1875 old_setting = meta_ui_accelerator_name (combo->keysym,
1876 combo->modifiers);
1877
1878 if (!strcmp(old_setting, value))
1879 {
1880 /* We were about to set it to the same value
1881 * that it had originally! This must be caused
1882 * by getting an invalid string back from
1883 * meta_ui_accelerator_name. Bail out now
1884 * so we don't get into an infinite loop.
1885 */
1886 g_free (old_setting);
1887 return TRUE;
1888 }
1889
1890 meta_warning ("Reverting \"%s\" to %s.\n",
1891 binding->name,
1892 old_setting);
1893
1894 /* FIXME: add_shift is currently screen_bindings only, but
1895 * there's no really good reason it should always be.
1896 * So we shouldn't blindly add KEY_SCREEN_BINDINGS_PREFIX
1897 * onto here.
1898 */
1899 g_settings_set_string(settings_screen_bindings,
1900 binding->name,
1901 old_setting);
1902
1903 g_free (old_setting);
1904
1905 /* The call to g_settings_set_string() will cause this function
1906 * to be called again with the new value, so there's no need to
1907 * carry on.
1908 */
1909 return TRUE;
1910 }
1911
1912 changed = FALSE;
1913 if (keysym != combo->keysym ||
1914 keycode != combo->keycode ||
1915 mods != combo->modifiers)
1916 {
1917 changed = TRUE;
1918
1919 combo->keysym = keysym;
1920 combo->keycode = keycode;
1921 combo->modifiers = mods;
1922
1923 meta_topic (META_DEBUG_KEYBINDINGS,
1924 "New keybinding for \"%s\" is keysym = 0x%x keycode = 0x%x mods = 0x%x\n",
1925 binding->name, combo->keysym, combo->keycode,
1926 combo->modifiers);
1927 }
1928 else
1929 {
1930 meta_topic (META_DEBUG_KEYBINDINGS,
1931 "Keybinding for \"%s\" is unchanged\n", binding->name);
1932 }
1933
1934 return changed;
1935 }
1936
1937 static const gchar*
relative_key(const gchar * key)1938 relative_key (const gchar* key)
1939 {
1940 const gchar* end;
1941
1942 end = strrchr (key, '/');
1943
1944 ++end;
1945
1946 return end;
1947 }
1948
1949 /* Return value is TRUE if a preference changed and we need to
1950 * notify
1951 */
1952 static gboolean
find_and_update_binding(MetaKeyPref * bindings,const char * name,gchar * value)1953 find_and_update_binding (MetaKeyPref *bindings,
1954 const char *name,
1955 gchar *value)
1956 {
1957 const char *key;
1958 int i;
1959
1960 if (*name == '/')
1961 key = relative_key (name);
1962 else
1963 key = name;
1964
1965 i = 0;
1966 while (bindings[i].name &&
1967 strcmp (key, bindings[i].name) != 0)
1968 ++i;
1969
1970 if (bindings[i].name)
1971 return update_binding (&bindings[i], value);
1972 else
1973 return FALSE;
1974 }
1975
1976 static gboolean
update_key_binding(const char * name,gchar * value)1977 update_key_binding (const char *name,
1978 gchar *value)
1979 {
1980 return find_and_update_binding (key_bindings, name, value);
1981 }
1982
1983 static gboolean
update_command(const char * name,const char * value)1984 update_command (const char *name,
1985 const char *value)
1986 {
1987 char *p;
1988 int i;
1989
1990 p = strrchr (name, '-');
1991 if (p == NULL)
1992 {
1993 meta_topic (META_DEBUG_KEYBINDINGS,
1994 "Command %s has no dash?\n", name);
1995 return FALSE;
1996 }
1997
1998 ++p;
1999
2000 if (g_ascii_isdigit (*p))
2001 {
2002 i = atoi (p);
2003 i -= 1; /* count from 0 not 1 */
2004 }
2005 else
2006 {
2007 if (strcmp (name, "command-screenshot") == 0)
2008 {
2009 i = SCREENSHOT_COMMAND_IDX;
2010 }
2011 else if (strcmp (name, "command-window-screenshot") == 0)
2012 {
2013 i = WIN_SCREENSHOT_COMMAND_IDX;
2014 }
2015 else
2016 {
2017 meta_topic (META_DEBUG_KEYBINDINGS,
2018 "Command %s doesn't end in number?\n", name);
2019 return FALSE;
2020 }
2021 }
2022
2023 if (i >= MAX_COMMANDS)
2024 {
2025 meta_topic (META_DEBUG_KEYBINDINGS,
2026 "Command %d is too highly numbered, ignoring\n", i);
2027 return FALSE;
2028 }
2029
2030 if ((commands[i] == NULL && value == NULL) ||
2031 (commands[i] && value && strcmp (commands[i], value) == 0))
2032 {
2033 meta_topic (META_DEBUG_KEYBINDINGS,
2034 "Command %d is unchanged\n", i);
2035 return FALSE;
2036 }
2037
2038 g_free (commands[i]);
2039 commands[i] = g_strdup (value);
2040
2041 meta_topic (META_DEBUG_KEYBINDINGS,
2042 "Updated command %d to \"%s\"\n",
2043 i, commands[i] ? commands[i] : "none");
2044
2045 return TRUE;
2046 }
2047
2048 const char*
meta_prefs_get_command(int i)2049 meta_prefs_get_command (int i)
2050 {
2051 g_return_val_if_fail (i >= 0 && i < MAX_COMMANDS, NULL);
2052
2053 return commands[i];
2054 }
2055
2056 char*
meta_prefs_get_settings_key_for_command(int i)2057 meta_prefs_get_settings_key_for_command (int i)
2058 {
2059 char *key;
2060
2061 switch (i)
2062 {
2063 case SCREENSHOT_COMMAND_IDX:
2064 key = g_strdup (KEY_COMMAND_PREFIX "screenshot");
2065 break;
2066 case WIN_SCREENSHOT_COMMAND_IDX:
2067 key = g_strdup (KEY_COMMAND_PREFIX "window-screenshot");
2068 break;
2069 default:
2070 key = g_strdup_printf (KEY_COMMAND_PREFIX"%d", i + 1);
2071 break;
2072 }
2073
2074 return key;
2075 }
2076
2077 const char*
meta_prefs_get_terminal_command(void)2078 meta_prefs_get_terminal_command (void)
2079 {
2080 return terminal_command;
2081 }
2082
2083 const char*
meta_prefs_get_settings_key_for_terminal_command(void)2084 meta_prefs_get_settings_key_for_terminal_command (void)
2085 {
2086 return KEY_MATE_TERMINAL_COMMAND;
2087 }
2088
2089 static gboolean
update_workspace_name(const char * name,const char * value)2090 update_workspace_name (const char *name,
2091 const char *value)
2092 {
2093 char *p;
2094 int i;
2095
2096 p = strrchr (name, '-');
2097 if (p == NULL)
2098 {
2099 meta_topic (META_DEBUG_PREFS,
2100 "Workspace name %s has no dash?\n", name);
2101 return FALSE;
2102 }
2103
2104 ++p;
2105
2106 if (!g_ascii_isdigit (*p))
2107 {
2108 meta_topic (META_DEBUG_PREFS,
2109 "Workspace name %s doesn't end in number?\n", name);
2110 return FALSE;
2111 }
2112
2113 i = atoi (p);
2114 i -= 1; /* count from 0 not 1 */
2115
2116 if (i >= MAX_REASONABLE_WORKSPACES)
2117 {
2118 meta_topic (META_DEBUG_PREFS,
2119 "Workspace name %d is too highly numbered, ignoring\n", i);
2120 return FALSE;
2121 }
2122
2123 if (workspace_names[i] && value && strcmp (workspace_names[i], value) == 0)
2124 {
2125 meta_topic (META_DEBUG_PREFS,
2126 "Workspace name %d is unchanged\n", i);
2127 return FALSE;
2128 }
2129
2130 /* This is a bad hack. We have to treat empty string as
2131 * "unset" because the root window property can't contain
2132 * null. So it gets empty string instead and we don't want
2133 * that to result in setting the empty string as a value that
2134 * overrides "unset".
2135 */
2136 if (value != NULL && *value != '\0')
2137 {
2138 g_free (workspace_names[i]);
2139 workspace_names[i] = g_strdup (value);
2140 }
2141 else
2142 {
2143 /* use a default name */
2144 char *d;
2145
2146 d = g_strdup_printf (_("Workspace %d"), i + 1);
2147 if (workspace_names[i] && strcmp (workspace_names[i], d) == 0)
2148 {
2149 g_free (d);
2150 return FALSE;
2151 }
2152 else
2153 {
2154 g_free (workspace_names[i]);
2155 workspace_names[i] = d;
2156 }
2157 }
2158
2159 meta_topic (META_DEBUG_PREFS,
2160 "Updated workspace name %d to \"%s\"\n",
2161 i, workspace_names[i] ? workspace_names[i] : "none");
2162
2163 return TRUE;
2164 }
2165
2166 const char*
meta_prefs_get_workspace_name(int i)2167 meta_prefs_get_workspace_name (int i)
2168 {
2169 g_return_val_if_fail (i >= 0 && i < MAX_REASONABLE_WORKSPACES, NULL);
2170
2171 g_assert (workspace_names[i] != NULL);
2172
2173 meta_topic (META_DEBUG_PREFS,
2174 "Getting workspace name for %d: \"%s\"\n",
2175 i, workspace_names[i]);
2176
2177 return workspace_names[i];
2178 }
2179
2180 void
meta_prefs_change_workspace_name(int i,const char * name)2181 meta_prefs_change_workspace_name (int i,
2182 const char *name)
2183 {
2184 char *key;
2185
2186 g_return_if_fail (i >= 0 && i < MAX_REASONABLE_WORKSPACES);
2187
2188 meta_topic (META_DEBUG_PREFS,
2189 "Changing name of workspace %d to %s\n",
2190 i, name ? name : "none");
2191
2192 if (name && *name == '\0')
2193 name = NULL;
2194
2195 if ((name == NULL && workspace_names[i] == NULL) ||
2196 (name && workspace_names[i] && strcmp (name, workspace_names[i]) == 0))
2197 {
2198 meta_topic (META_DEBUG_PREFS,
2199 "Workspace %d already has name %s\n",
2200 i, name ? name : "none");
2201 return;
2202 }
2203
2204 key = settings_key_for_workspace_name (i);
2205
2206 if (name != NULL)
2207 g_settings_set_string (settings_workspace_names,
2208 key,
2209 name);
2210 else
2211 g_settings_set_string (settings_workspace_names,
2212 key,
2213 "");
2214
2215 g_free (key);
2216 }
2217
2218 static char*
settings_key_for_workspace_name(int i)2219 settings_key_for_workspace_name (int i)
2220 {
2221 char *key;
2222
2223 key = g_strdup_printf (KEY_WORKSPACE_NAME_PREFIX"%d", i + 1);
2224
2225 return key;
2226 }
2227
2228 void
meta_prefs_get_button_layout(MetaButtonLayout * button_layout_p)2229 meta_prefs_get_button_layout (MetaButtonLayout *button_layout_p)
2230 {
2231 *button_layout_p = button_layout;
2232 }
2233
2234 gboolean
meta_prefs_get_visual_bell(void)2235 meta_prefs_get_visual_bell (void)
2236 {
2237 return provide_visual_bell;
2238 }
2239
2240 gboolean
meta_prefs_bell_is_audible(void)2241 meta_prefs_bell_is_audible (void)
2242 {
2243 return bell_is_audible;
2244 }
2245
2246 MetaVisualBellType
meta_prefs_get_visual_bell_type(void)2247 meta_prefs_get_visual_bell_type (void)
2248 {
2249 return visual_bell_type;
2250 }
2251
2252 void
meta_prefs_get_key_bindings(const MetaKeyPref ** bindings,int * n_bindings)2253 meta_prefs_get_key_bindings (const MetaKeyPref **bindings,
2254 int *n_bindings)
2255 {
2256
2257 *bindings = key_bindings;
2258 *n_bindings = (int) G_N_ELEMENTS (key_bindings) - 1;
2259 }
2260
2261 MetaActionTitlebar
meta_prefs_get_action_double_click_titlebar(void)2262 meta_prefs_get_action_double_click_titlebar (void)
2263 {
2264 return action_double_click_titlebar;
2265 }
2266
2267 MetaActionTitlebar
meta_prefs_get_action_middle_click_titlebar(void)2268 meta_prefs_get_action_middle_click_titlebar (void)
2269 {
2270 return action_middle_click_titlebar;
2271 }
2272
2273 MetaActionTitlebar
meta_prefs_get_action_right_click_titlebar(void)2274 meta_prefs_get_action_right_click_titlebar (void)
2275 {
2276 return action_right_click_titlebar;
2277 }
2278
2279 gboolean
meta_prefs_get_auto_raise(void)2280 meta_prefs_get_auto_raise (void)
2281 {
2282 return auto_raise;
2283 }
2284
2285 int
meta_prefs_get_auto_raise_delay(void)2286 meta_prefs_get_auto_raise_delay (void)
2287 {
2288 return auto_raise_delay;
2289 }
2290
2291 gboolean
meta_prefs_get_reduced_resources(void)2292 meta_prefs_get_reduced_resources (void)
2293 {
2294 return reduced_resources;
2295 }
2296
2297 gboolean
meta_prefs_get_mate_accessibility()2298 meta_prefs_get_mate_accessibility ()
2299 {
2300 return mate_accessibility;
2301 }
2302
2303 gboolean
meta_prefs_get_mate_animations()2304 meta_prefs_get_mate_animations ()
2305 {
2306 return mate_animations;
2307 }
2308
2309 MetaKeyBindingAction
meta_prefs_get_keybinding_action(const char * name)2310 meta_prefs_get_keybinding_action (const char *name)
2311 {
2312 int i;
2313
2314 i = G_N_ELEMENTS (key_bindings) - 2; /* -2 for dummy entry at end */
2315 while (i >= 0)
2316 {
2317 if (strcmp (key_bindings[i].name, name) == 0)
2318 return (MetaKeyBindingAction) i;
2319
2320 --i;
2321 }
2322
2323 return META_KEYBINDING_ACTION_NONE;
2324 }
2325
2326 /* This is used by the menu system to decide what key binding
2327 * to display next to an option. We return the first non-disabled
2328 * binding, if any.
2329 */
2330 void
meta_prefs_get_window_binding(const char * name,unsigned int * keysym,MetaVirtualModifier * modifiers)2331 meta_prefs_get_window_binding (const char *name,
2332 unsigned int *keysym,
2333 MetaVirtualModifier *modifiers)
2334 {
2335 int i;
2336
2337 i = G_N_ELEMENTS (key_bindings) - 2; /* -2 for dummy entry at end */
2338 while (i >= 0)
2339 {
2340 if (key_bindings[i].per_window &&
2341 strcmp (key_bindings[i].name, name) == 0)
2342 {
2343 GSList *s = key_bindings[i].bindings;
2344
2345 while (s)
2346 {
2347 MetaKeyCombo *c = s->data;
2348
2349 if (c->keysym!=0 || c->modifiers!=0)
2350 {
2351 *keysym = c->keysym;
2352 *modifiers = c->modifiers;
2353 return;
2354 }
2355
2356 s = s->next;
2357 }
2358
2359 /* Not found; return the disabled value */
2360 *keysym = *modifiers = 0;
2361 return;
2362 }
2363
2364 --i;
2365 }
2366
2367 g_assert_not_reached ();
2368 }
2369
2370 gboolean
meta_prefs_get_compositing_manager(void)2371 meta_prefs_get_compositing_manager (void)
2372 {
2373 if (use_force_compositor_manager)
2374 return force_compositor_manager;
2375 return compositing_manager;
2376 }
2377
2378 gboolean
meta_prefs_get_compositing_fast_alt_tab(void)2379 meta_prefs_get_compositing_fast_alt_tab (void)
2380 {
2381 return compositing_fast_alt_tab;
2382 }
2383
2384 gboolean
meta_prefs_get_center_new_windows(void)2385 meta_prefs_get_center_new_windows (void)
2386 {
2387 return center_new_windows;
2388 }
2389
2390 gboolean
meta_prefs_get_allow_tiling()2391 meta_prefs_get_allow_tiling ()
2392 {
2393 return allow_tiling;
2394 }
2395
2396 gboolean
meta_prefs_get_allow_top_tiling()2397 meta_prefs_get_allow_top_tiling ()
2398 {
2399 return allow_top_tiling;
2400 }
2401
2402 gboolean
meta_prefs_get_allow_tile_cycling()2403 meta_prefs_get_allow_tile_cycling ()
2404 {
2405 return allow_tile_cycling;
2406 }
2407
2408 guint
meta_prefs_get_mouse_button_resize(void)2409 meta_prefs_get_mouse_button_resize (void)
2410 {
2411 return resize_with_right_button ? 3: 2;
2412 }
2413
2414 guint
meta_prefs_get_mouse_button_menu(void)2415 meta_prefs_get_mouse_button_menu (void)
2416 {
2417 return resize_with_right_button ? 2: 3;
2418 }
2419
2420 gboolean
meta_prefs_show_tab_border(void)2421 meta_prefs_show_tab_border(void)
2422 {
2423 return show_tab_border;
2424 }
2425
2426 gboolean
meta_prefs_get_force_fullscreen(void)2427 meta_prefs_get_force_fullscreen (void)
2428 {
2429 return force_fullscreen;
2430 }
2431
2432 MetaPlacementMode
meta_prefs_get_placement_mode(void)2433 meta_prefs_get_placement_mode (void)
2434 {
2435 return placement_mode;
2436 }
2437
2438 void
meta_prefs_set_force_compositing_manager(gboolean whether)2439 meta_prefs_set_force_compositing_manager (gboolean whether)
2440 {
2441 use_force_compositor_manager = TRUE;
2442 force_compositor_manager = whether;
2443 }
2444
2445 void
meta_prefs_set_compositing_fast_alt_tab(gboolean whether)2446 meta_prefs_set_compositing_fast_alt_tab (gboolean whether)
2447 {
2448 g_settings_set_boolean (settings_general,
2449 KEY_GENERAL_COMPOSITOR_FAST_ALT_TAB,
2450 whether);
2451 }
2452
2453 void
meta_prefs_set_center_new_windows(gboolean whether)2454 meta_prefs_set_center_new_windows (gboolean whether)
2455 {
2456 g_settings_set_boolean (settings_general,
2457 KEY_GENERAL_CENTER_NEW_WINDOWS,
2458 whether);
2459 }
2460
2461 void
meta_prefs_set_force_fullscreen(gboolean whether)2462 meta_prefs_set_force_fullscreen (gboolean whether)
2463 {
2464 force_fullscreen = whether;
2465 }
2466
2467