prefs.c 46 KB
Newer Older
1 2
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */

3 4
/* Metacity preferences */

5
/*
6
 * Copyright (C) 2001 Havoc Pennington, Copyright (C) 2002 Red Hat Inc.
7
 * Copyright (C) 2006 Elijah Newren
Thomas Thurman's avatar
Thomas Thurman committed
8
 * Copyright (C) 2008 Thomas Thurman
9 10
 * Copyright (C) 2010 Milan Bouchet-Valat, Copyright (C) 2011 Red Hat Inc.
 *
11 12 13 14 15 16 17 18 19
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
20
 *
21
 * You should have received a copy of the GNU General Public License
22
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
23 24 25 26
 */

#include <config.h>
#include "prefs.h"
27
#include "ui.h"
28
#include "util.h"
29 30
#include <glib.h>
#include <gio/gio.h>
31
#include <string.h>
32
#include <stdlib.h>
33

34
/* If you add a key, it needs updating in init() and in the gsettings
35 36 37 38 39
 * notify listener and of course in the .schemas file.
 *
 * Keys which are handled by one of the unified handlers below are
 * not given a name here, because the purpose of the unified handlers
 * is that keys should be referred to exactly once.
40
 */
41 42 43 44
#define KEY_TITLEBAR_FONT "titlebar-font"
#define KEY_NUM_WORKSPACES "num-workspaces"
#define KEY_WORKSPACE_NAMES "workspace-names"
#define KEY_COMPOSITOR "compositing-manager"
45
#define KEY_PLACEMENT_MODE "placement-mode"
46 47 48 49 50 51 52 53 54 55 56 57

/* Keys from "foreign" schemas */
#define KEY_GNOME_ACCESSIBILITY "toolkit-accessibility"
#define KEY_GNOME_ANIMATIONS "enable-animations"
#define KEY_GNOME_CURSOR_THEME "cursor-theme"
#define KEY_GNOME_CURSOR_SIZE "cursor-size"

/* These are the different schemas we are keeping
 * a GSettings instance for */
#define SCHEMA_GENERAL         "org.gnome.desktop.wm.preferences"
#define SCHEMA_METACITY        "org.gnome.metacity"
#define SCHEMA_INTERFACE       "org.gnome.desktop.interface"
58
#define SCHEMA_BINDINGS        "org.gnome.desktop.wm.keybindings"
59 60

#define SETTINGS(s) g_hash_table_lookup (settings_schemas, (s))
61

62 63
static GList *changes = NULL;
static guint changed_idle;
64
static GList *listeners = NULL;
65
static GHashTable *settings_schemas;
66

67
static gboolean use_system_font = FALSE;
68
static PangoFontDescription *titlebar_font = NULL;
69
static MetaVirtualModifier mouse_button_mods = Mod1Mask;
70 71
static GDesktopFocusMode focus_mode = G_DESKTOP_FOCUS_MODE_CLICK;
static GDesktopFocusNewWindows focus_new_windows = G_DESKTOP_FOCUS_NEW_WINDOWS_SMART;
72
static gboolean raise_on_click = TRUE;
73
static gboolean attach_modal_dialogs = FALSE;
74
static char* current_theme = NULL;
75
static int num_workspaces = 4;
76 77 78
static GDesktopTitlebarAction action_double_click_titlebar = G_DESKTOP_TITLEBAR_ACTION_TOGGLE_MAXIMIZE;
static GDesktopTitlebarAction action_middle_click_titlebar = G_DESKTOP_TITLEBAR_ACTION_LOWER;
static GDesktopTitlebarAction action_right_click_titlebar = G_DESKTOP_TITLEBAR_ACTION_MENU;
79
static gboolean disable_workarounds = FALSE;
Havoc Pennington's avatar
Havoc Pennington committed
80 81
static gboolean auto_raise = FALSE;
static gboolean auto_raise_delay = 500;
82
static gboolean bell_is_visible = FALSE;
83
static gboolean bell_is_audible = TRUE;
84
static gboolean reduced_resources = FALSE;
85
static gboolean gnome_accessibility = FALSE;
86
static gboolean gnome_animations = TRUE;
87 88
static char *cursor_theme = NULL;
static int   cursor_size = 24;
Søren Sandmann's avatar
Søren Sandmann committed
89
static gboolean compositing_manager = FALSE;
90
static gboolean resize_with_right_button = FALSE;
Alberts Muktupāvels's avatar
Alberts Muktupāvels committed
91
static gboolean edge_tiling = FALSE;
92
static gboolean force_fullscreen = TRUE;
93
static gboolean alt_tab_thumbnails = FALSE;
94

95
static GDesktopVisualBellType visual_bell_type = G_DESKTOP_VISUAL_BELL_FULLSCREEN_FLASH;
96
static MetaButtonLayout button_layout;
97

98 99
static MetaPlacementMode placement_mode = META_PLACEMENT_MODE_SMART;

100 101
/* NULL-terminated array */
static char **workspace_names = NULL;
102

103 104
static void handle_preference_update_enum (GSettings *settings,
                                           gchar     *key);
105

106 107 108 109 110
static gboolean update_binding         (MetaKeyPref *binding,
                                        gchar      **strokes);
static gboolean update_key_binding     (const char  *key,
                                        gchar      **strokes);
static gboolean update_workspace_names (void);
111

112 113 114 115 116 117
static void settings_changed (GSettings      *settings,
                              gchar          *key,
                              gpointer        data);
static void bindings_changed (GSettings      *settings,
                              gchar          *key,
                              gpointer        data);
118 119


120 121
static void queue_changed (MetaPreference  pref);

122 123
static void maybe_give_disable_workarounds_warning (void);

124 125 126 127
static gboolean titlebar_handler (GVariant*, gpointer*, gpointer);
static gboolean theme_name_handler (GVariant*, gpointer*, gpointer);
static gboolean mouse_button_mods_handler (GVariant*, gpointer*, gpointer);
static gboolean button_layout_handler (GVariant*, gpointer*, gpointer);
128

129 130
static void     init_bindings             (void);
static void     init_workspace_names      (void);
131 132


133 134 135 136 137 138
typedef struct
{
  MetaPrefsChangedFunc func;
  gpointer data;
} MetaPrefsListener;

139 140 141 142

typedef struct
{
  gchar *key;
143
  gchar *schema;
Thomas Thurman's avatar
Thomas Thurman committed
144
  MetaPreference pref;
145 146 147 148 149 150
} MetaBasePreference;


typedef struct
{
  MetaBasePreference base;
151 152 153
  gpointer target;
} MetaEnumPreference;

154 155
typedef struct
{
156
  MetaBasePreference base;
Thomas Thurman's avatar
Thomas Thurman committed
157
  gboolean *target;
158 159 160
  gboolean becomes_true_on_destruction;
} MetaBoolPreference;

161 162
typedef struct
{
163
  MetaBasePreference base;
164 165 166 167 168

  /**
   * A handler.  Many of the string preferences aren't stored as
   * strings and need parsing; others of them have default values
   * which can't be solved in the general case.  If you include a
169 170
   * function pointer here, it will be called instead of writing
   * the string value out to the target variable.
171
   *
172 173 174 175 176 177
   * The function will be passed to g_settings_get_mapped() and should
   * return %TRUE if the mapping was successful and %FALSE otherwise.
   * In the former case the function is expected to handle the result
   * of the conversion itself and call queue_changed() appropriately;
   * in particular the @result (out) parameter as returned by
   * g_settings_get_mapped() will be ignored in all cases.
178 179 180
   *
   * This may be NULL.  If it is, see "target", below.
   */
181
  GSettingsGetMapping handler;
182 183 184 185

  /**
   * Where to write the incoming string.
   *
Thomas Thurman's avatar
Thomas Thurman committed
186
   * This must be NULL if the handler is non-NULL.
187 188 189 190 191 192
   * If the incoming string is NULL, no change will be made.
   */
  gchar **target;

} MetaStringPreference;

Thomas Thurman's avatar
Thomas Thurman committed
193 194
typedef struct
{
195
  MetaBasePreference base;
Thomas Thurman's avatar
Thomas Thurman committed
196 197 198
  gint *target;
} MetaIntPreference;

199 200 201 202 203

/* All preferences that are not keybindings must be listed here,
 * plus in the GSettings schemas and the MetaPreference enum.
 */

Thomas Thurman's avatar
Thomas Thurman committed
204 205
/* FIXMEs: */
/* @@@ Don't use NULL lines at the end; glib can tell you how big it is */
206 207
static MetaEnumPreference preferences_enum[] =
  {
208 209 210 211 212
    {
      { "focus-new-windows",
        SCHEMA_GENERAL,
        META_PREF_FOCUS_NEW_WINDOWS,
      },
213 214
      &focus_new_windows,
    },
215 216 217 218 219
    {
      { "focus-mode",
        SCHEMA_GENERAL,
        META_PREF_FOCUS_MODE,
      },
220 221
      &focus_mode,
    },
222 223 224 225 226
    {
      { "visual-bell-type",
        SCHEMA_GENERAL,
        META_PREF_VISUAL_BELL_TYPE,
      },
227 228
      &visual_bell_type,
    },
229 230 231 232 233
    {
      { "action-double-click-titlebar",
        SCHEMA_GENERAL,
        META_PREF_ACTION_DOUBLE_CLICK_TITLEBAR,
      },
234 235
      &action_double_click_titlebar,
    },
236 237 238 239 240
    {
      { "action-middle-click-titlebar",
        SCHEMA_GENERAL,
        META_PREF_ACTION_MIDDLE_CLICK_TITLEBAR,
      },
241 242
      &action_middle_click_titlebar,
    },
243 244 245 246 247
    {
      { "action-right-click-titlebar",
        SCHEMA_GENERAL,
        META_PREF_ACTION_RIGHT_CLICK_TITLEBAR,
      },
248 249
      &action_right_click_titlebar,
    },
250 251 252 253 254 255 256
    {
      { "placement-mode",
        SCHEMA_METACITY,
        META_PREF_PLACEMENT_MODE,
      },
      &placement_mode,
    },
257
    { { NULL, 0, 0 }, NULL },
258 259
  };

260 261
static MetaBoolPreference preferences_bool[] =
  {
262 263 264 265 266
    {
      { "raise-on-click",
        SCHEMA_GENERAL,
        META_PREF_RAISE_ON_CLICK,
      },
Thomas Thurman's avatar
Thomas Thurman committed
267
      &raise_on_click,
268 269
      TRUE,
    },
270 271 272 273 274
    {
      { "titlebar-uses-system-font",
        SCHEMA_GENERAL,
        META_PREF_TITLEBAR_FONT, /* note! shares a pref */
      },
Thomas Thurman's avatar
Thomas Thurman committed
275
      &use_system_font,
276 277
      TRUE,
    },
278 279 280 281 282
    {
      { "disable-workarounds",
        SCHEMA_GENERAL,
        META_PREF_DISABLE_WORKAROUNDS,
      },
Thomas Thurman's avatar
Thomas Thurman committed
283
      &disable_workarounds,
284 285
      FALSE,
    },
286 287 288 289 290
    {
      { "auto-raise",
        SCHEMA_GENERAL,
        META_PREF_AUTO_RAISE,
      },
Thomas Thurman's avatar
Thomas Thurman committed
291
      &auto_raise,
292 293
      FALSE,
    },
294 295 296 297 298 299 300 301
    {
      { "visual-bell",
        SCHEMA_GENERAL,
        META_PREF_VISUAL_BELL,
      },
      &bell_is_visible, /* FIXME: change the name: it's confusing */
      FALSE,
    },
302 303 304 305 306
    {
      { "audible-bell",
        SCHEMA_GENERAL,
        META_PREF_AUDIBLE_BELL,
      },
Thomas Thurman's avatar
Thomas Thurman committed
307
      &bell_is_audible, /* FIXME: change the name: it's confusing */
308 309
      FALSE,
    },
310 311 312 313 314
    {
      { "reduced-resources",
        SCHEMA_METACITY,
        META_PREF_REDUCED_RESOURCES,
      },
Thomas Thurman's avatar
Thomas Thurman committed
315
      &reduced_resources,
316 317
      FALSE,
    },
318 319 320 321 322
    {
      { KEY_GNOME_ACCESSIBILITY,
        SCHEMA_INTERFACE,
        META_PREF_GNOME_ACCESSIBILITY,
      },
Thomas Thurman's avatar
Thomas Thurman committed
323
      &gnome_accessibility,
324 325
      FALSE,
    },
326 327 328 329 330
    {
      { KEY_GNOME_ANIMATIONS,
        SCHEMA_INTERFACE,
        META_PREF_GNOME_ANIMATIONS,
      },
331 332 333
      &gnome_animations,
      TRUE,
    },
334 335 336 337 338
    {
      { "compositing-manager",
        SCHEMA_METACITY,
        META_PREF_COMPOSITING_MANAGER,
      },
Thomas Thurman's avatar
Thomas Thurman committed
339
      &compositing_manager,
340 341
      FALSE,
    },
342 343 344 345 346
    {
      { "resize-with-right-button",
        SCHEMA_GENERAL,
        META_PREF_RESIZE_WITH_RIGHT_BUTTON,
      },
347 348 349
      &resize_with_right_button,
      FALSE,
    },
Alberts Muktupāvels's avatar
Alberts Muktupāvels committed
350 351 352 353 354 355 356 357
    {
      { "edge-tiling",
        SCHEMA_METACITY,
        META_PREF_EDGE_TILING,
      },
      &edge_tiling,
      FALSE,
    },
358 359 360 361 362 363 364 365
    {
      { "alt-tab-thumbnails",
        SCHEMA_METACITY,
        META_PREF_ALT_TAB_THUMBNAILS,
      },
      &alt_tab_thumbnails,
      FALSE,
    },
366
    { { NULL, 0, 0 }, NULL, FALSE },
367
  };
368

369 370
static MetaStringPreference preferences_string[] =
  {
371 372 373 374 375
    {
      { "mouse-button-modifier",
        SCHEMA_GENERAL,
        META_PREF_MOUSE_BUTTON_MODS,
      },
376 377 378
      mouse_button_mods_handler,
      NULL,
    },
379 380
    {
      { "theme",
381
        SCHEMA_METACITY,
382 383
        META_PREF_THEME,
      },
384 385 386
      theme_name_handler,
      NULL,
    },
387 388 389 390 391
    {
      { KEY_TITLEBAR_FONT,
        SCHEMA_GENERAL,
        META_PREF_TITLEBAR_FONT,
      },
392 393 394
      titlebar_handler,
      NULL,
    },
395 396 397 398 399
    {
      { "button-layout",
        SCHEMA_GENERAL,
        META_PREF_BUTTON_LAYOUT,
      },
400 401 402
      button_layout_handler,
      NULL,
    },
403 404 405 406 407
    {
      { KEY_GNOME_CURSOR_THEME,
        SCHEMA_INTERFACE,
        META_PREF_CURSOR_THEME,
      },
408 409 410
      NULL,
      &cursor_theme,
    },
411
    { { NULL, 0, 0 }, NULL },
412 413
  };

Thomas Thurman's avatar
Thomas Thurman committed
414 415
static MetaIntPreference preferences_int[] =
  {
416 417 418 419 420 421
    {
      { "num-workspaces",
        SCHEMA_GENERAL,
        META_PREF_NUM_WORKSPACES,
      },
      &num_workspaces
Thomas Thurman's avatar
Thomas Thurman committed
422
    },
423 424 425 426 427 428
    {
      { "auto-raise-delay",
        SCHEMA_GENERAL,
        META_PREF_AUTO_RAISE_DELAY,
      },
      &auto_raise_delay
Thomas Thurman's avatar
Thomas Thurman committed
429
    },
430 431 432 433 434 435
    {
      { KEY_GNOME_CURSOR_SIZE,
        SCHEMA_INTERFACE,
        META_PREF_CURSOR_SIZE,
      },
      &cursor_size
Thomas Thurman's avatar
Thomas Thurman committed
436
    },
437
    { { NULL, 0, 0 }, NULL },
Thomas Thurman's avatar
Thomas Thurman committed
438 439
  };

440 441 442 443 444
static void
handle_preference_init_enum (void)
{
  MetaEnumPreference *cursor = preferences_enum;

445
  while (cursor->base.key != NULL)
446
    {
447 448
      if (cursor->target==NULL)
          continue;
449

450 451
      *((gint *) cursor->target) =
        g_settings_get_enum (SETTINGS (cursor->base.schema), cursor->base.key);
452 453 454 455 456

      ++cursor;
    }
}

457 458 459 460 461
static void
handle_preference_init_bool (void)
{
  MetaBoolPreference *cursor = preferences_bool;

462
  while (cursor->base.key != NULL)
463 464
    {
      if (cursor->target!=NULL)
465 466 467
        *cursor->target =
          g_settings_get_boolean (SETTINGS (cursor->base.schema),
                                  cursor->base.key);
468 469 470 471 472 473 474

      ++cursor;
    }

  maybe_give_disable_workarounds_warning ();
}

475 476 477 478 479
static void
handle_preference_init_string (void)
{
  MetaStringPreference *cursor = preferences_string;

480
  while (cursor->base.key != NULL)
481 482 483
    {
      char *value;

484
      /* Complex keys have a mapping function to check validity */
485 486 487
      if (cursor->handler)
        {
          if (cursor->target)
488
            meta_bug ("%s has both a target and a handler\n", cursor->base.key);
489

490 491
          g_settings_get_mapped (SETTINGS (cursor->base.schema),
                                 cursor->base.key, cursor->handler, NULL);
492
        }
493
      else
494
        {
495 496 497
          if (!cursor->target)
            meta_bug ("%s must have handler or target\n", cursor->base.key);

498 499 500
          if (*(cursor->target))
            g_free (*(cursor->target));

501 502 503
          value = g_settings_get_string (SETTINGS (cursor->base.schema),
                                         cursor->base.key);

504 505 506 507 508 509 510
          *(cursor->target) = value;
        }

      ++cursor;
    }
}

Thomas Thurman's avatar
Thomas Thurman committed
511 512 513 514 515
static void
handle_preference_init_int (void)
{
  MetaIntPreference *cursor = preferences_int;

516

517
  while (cursor->base.key != NULL)
Thomas Thurman's avatar
Thomas Thurman committed
518
    {
519 520 521
      if (cursor->target)
        *cursor->target = g_settings_get_int (SETTINGS (cursor->base.schema),
                                              cursor->base.key);
Thomas Thurman's avatar
Thomas Thurman committed
522 523 524 525 526

      ++cursor;
    }
}

527 528 529
static void
handle_preference_update_enum (GSettings *settings,
                               gchar *key)
530 531 532 533
{
  MetaEnumPreference *cursor = preferences_enum;
  gint old_value;

534
  while (cursor->base.key != NULL && strcmp (key, cursor->base.key) != 0)
535 536
    ++cursor;

537
  if (cursor->base.key==NULL)
538
    /* Didn't recognise that key. */
539
    return;
540 541

  /* We need to know whether the value changes, so
542
   * store the current value away. */
543
  old_value = * ((gint *) cursor->target);
544

545 546
  *((gint *) cursor->target) =
    g_settings_get_enum (SETTINGS (cursor->base.schema), key);
547 548 549

  /* Did it change?  If so, tell the listeners about it. */
  if (old_value != *((gint *) cursor->target))
550
    queue_changed (cursor->base.pref);
551 552
}

553 554 555
static void
handle_preference_update_bool (GSettings *settings,
                               gchar *key)
556 557 558 559
{
  MetaBoolPreference *cursor = preferences_bool;
  gboolean old_value;

560
  while (cursor->base.key != NULL && strcmp (key, cursor->base.key) != 0)
561 562
    ++cursor;

563 564 565
  if (cursor->base.key==NULL || cursor->target==NULL)
    /* Unknown key or no work for us to do. */
    return;
566 567

  /* We need to know whether the value changes, so
568 569
   * store the current value away. */
  old_value = *((gboolean *) cursor->target);
570

571 572
  *((gboolean *) cursor->target) =
    g_settings_get_boolean (SETTINGS (cursor->base.schema), key);
573 574 575

  /* Did it change?  If so, tell the listeners about it. */
  if (old_value != *((gboolean *) cursor->target))
576
    queue_changed (cursor->base.pref);
577

578
  if (cursor->base.pref==META_PREF_DISABLE_WORKAROUNDS)
579 580 581
    maybe_give_disable_workarounds_warning ();
}

582 583 584
static void
handle_preference_update_string (GSettings *settings,
                                 gchar *key)
585 586
{
  MetaStringPreference *cursor = preferences_string;
587 588
  char *value;
  gboolean inform_listeners = FALSE;
589

590
  while (cursor->base.key != NULL && strcmp (key, cursor->base.key) != 0)
591 592
    ++cursor;

593
  if (cursor->base.key==NULL)
594
    /* Didn't recognise that key. */
595
    return;
596

597 598
  /* Complex keys have a mapping function to check validity */
  if (cursor->handler)
599
    {
600 601 602 603 604
      if (cursor->target)
        meta_bug ("%s has both a target and a handler\n", cursor->base.key);

      g_settings_get_mapped (SETTINGS (cursor->base.schema),
                             cursor->base.key, cursor->handler, NULL);
605
    }
606 607 608 609
  else
    {
      if (!cursor->target)
        meta_bug ("%s must have handler or target\n", cursor->base.key);
610

611 612 613
      value = g_settings_get_string (SETTINGS (cursor->base.schema),
                                     cursor->base.key);
      inform_listeners = (g_strcmp0 (value, *(cursor->target)) != 0);
614 615

      if (*(cursor->target))
616
        g_free (*(cursor->target));
617

618
      *(cursor->target) = value;
619 620 621
    }

  if (inform_listeners)
622
    queue_changed (cursor->base.pref);
623 624
}

625 626 627
static void
handle_preference_update_int (GSettings *settings,
                              gchar *key)
Thomas Thurman's avatar
Thomas Thurman committed
628 629 630 631
{
  MetaIntPreference *cursor = preferences_int;
  gint new_value;

632
  while (cursor->base.key != NULL && strcmp (key, cursor->base.key) != 0)
Thomas Thurman's avatar
Thomas Thurman committed
633 634
    ++cursor;

635 636 637
  if (cursor->base.key==NULL || cursor->target==NULL)
    /* Unknown key or no work for us to do. */
    return;
Thomas Thurman's avatar
Thomas Thurman committed
638

639
  new_value = g_settings_get_int (SETTINGS (cursor->base.schema), key);
Thomas Thurman's avatar
Thomas Thurman committed
640 641 642 643 644

  /* Did it change?  If so, tell the listeners about it. */
  if (*cursor->target != new_value)
    {
      *cursor->target = new_value;
645
      queue_changed (cursor->base.pref);
Thomas Thurman's avatar
Thomas Thurman committed
646 647 648 649 650 651 652
    }
}

/****************************************************************************/
/* Listeners.                                                               */
/****************************************************************************/

653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684
void
meta_prefs_add_listener (MetaPrefsChangedFunc func,
                         gpointer             data)
{
  MetaPrefsListener *l;

  l = g_new (MetaPrefsListener, 1);
  l->func = func;
  l->data = data;

  listeners = g_list_prepend (listeners, l);
}

void
meta_prefs_remove_listener (MetaPrefsChangedFunc func,
                            gpointer             data)
{
  GList *tmp;

  tmp = listeners;
  while (tmp != NULL)
    {
      MetaPrefsListener *l = tmp->data;

      if (l->func == func &&
          l->data == data)
        {
          g_free (l);
          listeners = g_list_delete_link (listeners, tmp);

          return;
        }
685

686 687 688 689 690 691 692 693 694 695 696 697
      tmp = tmp->next;
    }

  meta_bug ("Did not find listener to remove\n");
}

static void
emit_changed (MetaPreference pref)
{
  GList *tmp;
  GList *copy;

698 699
  meta_topic (META_DEBUG_PREFS, "Notifying listeners that pref %s changed\n",
              meta_preference_to_string (pref));
700

701
  copy = g_list_copy (listeners);
702

703
  tmp = copy;
704

705 706 707 708 709
  while (tmp != NULL)
    {
      MetaPrefsListener *l = tmp->data;

      (* l->func) (pref, l->data);
710

711 712 713 714 715 716 717 718 719 720 721 722 723
      tmp = tmp->next;
    }

  g_list_free (copy);
}

static gboolean
changed_idle_handler (gpointer data)
{
  GList *tmp;
  GList *copy;

  changed_idle = 0;
724

725 726 727 728
  copy = g_list_copy (changes); /* reentrancy paranoia */

  g_list_free (changes);
  changes = NULL;
729

730 731 732 733 734 735
  tmp = copy;
  while (tmp != NULL)
    {
      MetaPreference pref = GPOINTER_TO_INT (tmp->data);

      emit_changed (pref);
736

737 738 739 740
      tmp = tmp->next;
    }

  g_list_free (copy);
741

742 743 744 745 746 747
  return FALSE;
}

static void
queue_changed (MetaPreference pref)
{
748
  meta_topic (META_DEBUG_PREFS, "Queueing change of pref %s\n",
749
              meta_preference_to_string (pref));
750

751 752 753
  if (g_list_find (changes, GINT_TO_POINTER (pref)) == NULL)
    changes = g_list_prepend (changes, GINT_TO_POINTER (pref));
  else
754 755
    meta_topic (META_DEBUG_PREFS, "Change of pref %s was already pending\n",
                meta_preference_to_string (pref));
756

757
  if (changed_idle == 0)
758
    changed_idle = g_idle_add_full (META_PRIORITY_PREFS_NOTIFY,
759
                                    changed_idle_handler, NULL, NULL);
760
}
761

Thomas Thurman's avatar
Thomas Thurman committed
762 763 764
/****************************************************************************/
/* Initialisation.                                                          */
/****************************************************************************/
765

766 767 768
void
meta_prefs_init (void)
{
769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798
  GSettings *settings;

  settings_schemas = g_hash_table_new_full (g_str_hash, g_str_equal,
                                            NULL, g_object_unref);

  settings = g_settings_new (SCHEMA_GENERAL);
  g_signal_connect (settings, "changed", G_CALLBACK (settings_changed), NULL);
  g_hash_table_insert (settings_schemas, SCHEMA_GENERAL, settings);

  settings = g_settings_new (SCHEMA_METACITY);
  g_signal_connect (settings, "changed", G_CALLBACK (settings_changed), NULL);
  g_hash_table_insert (settings_schemas, SCHEMA_METACITY, settings);

  /* Individual keys we watch outside of our schemas */
  settings = g_settings_new (SCHEMA_INTERFACE);
  g_signal_connect (settings, "changed::" KEY_GNOME_ACCESSIBILITY,
                    G_CALLBACK (settings_changed), NULL);
  g_signal_connect (settings, "changed::" KEY_GNOME_ANIMATIONS,
                    G_CALLBACK (settings_changed), NULL);
  g_signal_connect (settings, "changed::" KEY_GNOME_CURSOR_THEME,
                    G_CALLBACK (settings_changed), NULL);
  g_signal_connect (settings, "changed::" KEY_GNOME_CURSOR_SIZE,
                    G_CALLBACK (settings_changed), NULL);
  g_hash_table_insert (settings_schemas, SCHEMA_INTERFACE, settings);

  /* Bindings have a separate handler, since they are in separate schemas
   * and work differently */
  settings = g_settings_new (SCHEMA_BINDINGS);
  g_signal_connect (settings, "changed", G_CALLBACK (bindings_changed), NULL);
  g_hash_table_insert (settings_schemas, SCHEMA_BINDINGS, settings);
799

800

801
  /* Pick up initial values. */
802 803

  handle_preference_init_enum ();
804
  handle_preference_init_bool ();
805
  handle_preference_init_string ();
Thomas Thurman's avatar
Thomas Thurman committed
806
  handle_preference_init_int ();
807

808
  init_bindings ();
809
  init_workspace_names ();
810 811
}

Thomas Thurman's avatar
Thomas Thurman committed
812 813 814 815
/****************************************************************************/
/* Updates.                                                                 */
/****************************************************************************/

816
static void
817 818 819 820 821 822 823 824
settings_changed (GSettings *settings,
                  gchar *key,
                  gpointer data)
{
  GVariant *value;
  const GVariantType *type;
  MetaEnumPreference *cursor;
  gboolean found_enum;
825

826 827
  /* String array, handled separately */
  if (strcmp (key, KEY_WORKSPACE_NAMES) == 0)
828
    {
829 830
      if (update_workspace_names ());
        queue_changed (META_PREF_WORKSPACE_NAMES);
831

832
      return;
833
    }
834

835 836
  value = g_settings_get_value (settings, key);
  type = g_variant_get_type (value);
837

838 839 840 841 842
  if (g_variant_type_equal (type, G_VARIANT_TYPE_BOOLEAN))
    handle_preference_update_bool (settings, key);
  else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT32))
    handle_preference_update_int (settings, key);
  else if (g_variant_type_equal (type, G_VARIANT_TYPE_STRING))
843
    {
844 845
      cursor = preferences_enum;
      found_enum = FALSE;
846

847
      while (cursor->base.key != NULL)
848
        {
849 850
          if (strcmp (key, cursor->base.key) == 0)
            found_enum = TRUE;
851

852
          cursor++;
853 854
        }

855 856 857 858
      if (found_enum)
        handle_preference_update_enum (settings, key);
      else
        handle_preference_update_string (settings, key);
859
    }
860
  else
861 862 863 864
    /* Someone added a preference of an unhandled type */
    g_assert_not_reached ();

  g_variant_unref (value);
865
}
866 867

static void
868 869 870
bindings_changed (GSettings *settings,
                  gchar *key,
                  gpointer data)
871
{
872
  gchar **strokes;
873

874
  strokes = g_settings_get_strv (settings, key);
875

876 877
   if (update_key_binding (key, strokes))
     queue_changed (META_PREF_KEYBINDINGS);
878

879
  g_strfreev (strokes);
880 881 882 883 884 885 886 887 888 889
}

/**
 * Special case: give a warning the first time disable_workarounds
 * is turned on.
 */
static void
maybe_give_disable_workarounds_warning (void)
{
  static gboolean first_disable = TRUE;
890

891 892 893 894 895 896 897 898 899
  if (first_disable && disable_workarounds)
    {
      first_disable = FALSE;

      meta_warning (_("Workarounds for broken applications disabled. "
                      "Some applications may not behave properly.\n"));
    }
}

900 901 902 903 904 905
MetaVirtualModifier
meta_prefs_get_mouse_button_mods  (void)
{
  return mouse_button_mods;
}

906
GDesktopFocusMode
907 908 909 910 911
meta_prefs_get_focus_mode (void)
{
  return focus_mode;
}

912
GDesktopFocusNewWindows
913 914 915 916 917
meta_prefs_get_focus_new_windows (void)
{
  return focus_new_windows;
}

918 919 920 921 922 923
gboolean
meta_prefs_get_attach_modal_dialogs (void)
{
  return attach_modal_dialogs;
}

924 925 926
gboolean
meta_prefs_get_raise_on_click (void)
{
927
  return raise_on_click;
928 929
}

930 931 932 933 934 935
const char*
meta_prefs_get_theme (void)
{
  return current_theme;
}

936 937 938 939 940 941 942 943 944 945 946 947
const char*
meta_prefs_get_cursor_theme (void)
{
  return cursor_theme;
}

int
meta_prefs_get_cursor_size (void)
{
  return cursor_size;
}

Thomas Thurman's avatar
Thomas Thurman committed
948 949 950 951
/****************************************************************************/
/* Handlers for string preferences.                                         */
/****************************************************************************/

952 953 954 955
static gboolean
titlebar_handler (GVariant *value,
                  gpointer *result,
                  gpointer  data)
956
{
957 958
  PangoFontDescription *desc;
  const gchar *string_value;
959

960 961 962
  *result = NULL; /* ignored */
  string_value = g_variant_get_string (value, NULL);
  desc = pango_font_description_from_string (string_value);
963

964
  if (desc == NULL)
965
    {
966
      meta_warning (_("Could not parse font description "
967
                      "\"%s\" from GSettings key %s\n"),
968
                    string_value ? string_value : "(null)",
969 970
                    KEY_TITLEBAR_FONT);

971
      return FALSE;
972 973
    }