prefs.c 41.3 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
#include "keybindings.h"
34

35
/* If you add a key, it needs updating in init() and in the gsettings
36 37 38 39 40
 * 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.
41
 */
42 43 44
#define KEY_TITLEBAR_FONT "titlebar-font"
#define KEY_NUM_WORKSPACES "num-workspaces"
#define KEY_WORKSPACE_NAMES "workspace-names"
45
#define KEY_COMPOSITING_MANAGER "compositing-manager"
46
#define KEY_PLACEMENT_MODE "placement-mode"
47 48 49 50 51 52 53 54 55 56

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

/* 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"
57
#define SCHEMA_METACITY_THEME  "org.gnome.metacity.theme"
58 59 60
#define SCHEMA_INTERFACE       "org.gnome.desktop.interface"

#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 75
static gchar *current_theme_name = NULL;
static MetaThemeType current_theme_type = META_THEME_TYPE_GTK;
76
static int num_workspaces = 4;
77 78 79
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;
80
static gboolean disable_workarounds = FALSE;
Havoc Pennington's avatar
Havoc Pennington committed
81 82
static gboolean auto_raise = FALSE;
static gboolean auto_raise_delay = 500;
83
static gboolean bell_is_visible = FALSE;
84
static gboolean bell_is_audible = TRUE;
85
static gboolean gnome_accessibility = FALSE;
86
static gboolean gnome_animations = TRUE;
87 88
static char *cursor_theme = NULL;
static int   cursor_size = 24;
89
static MetaCompositorType compositor = META_COMPOSITOR_TYPE_XRENDER;
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 gchar *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
static void update_button_layout (const gchar *string_value);
133

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

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

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

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

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

  /**
   * 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
168 169
   * function pointer here, it will be called instead of writing
   * the string value out to the target variable.
170
   *
171 172 173 174 175 176
   * 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.
177 178 179
   *
   * This may be NULL.  If it is, see "target", below.
   */
180
  GSettingsGetMapping handler;
181 182 183 184

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

} MetaStringPreference;

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

198 199 200 201 202

/* 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
203 204
/* FIXMEs: */
/* @@@ Don't use NULL lines at the end; glib can tell you how big it is */
205 206
static MetaEnumPreference preferences_enum[] =
  {
207 208 209 210 211
    {
      { "focus-new-windows",
        SCHEMA_GENERAL,
        META_PREF_FOCUS_NEW_WINDOWS,
      },
212 213
      &focus_new_windows,
    },
214 215 216 217 218
    {
      { "focus-mode",
        SCHEMA_GENERAL,
        META_PREF_FOCUS_MODE,
      },
219 220
      &focus_mode,
    },
221 222 223 224 225
    {
      { "visual-bell-type",
        SCHEMA_GENERAL,
        META_PREF_VISUAL_BELL_TYPE,
      },
226 227
      &visual_bell_type,
    },
228 229 230 231 232
    {
      { "action-double-click-titlebar",
        SCHEMA_GENERAL,
        META_PREF_ACTION_DOUBLE_CLICK_TITLEBAR,
      },
233 234
      &action_double_click_titlebar,
    },
235 236 237 238 239
    {
      { "action-middle-click-titlebar",
        SCHEMA_GENERAL,
        META_PREF_ACTION_MIDDLE_CLICK_TITLEBAR,
      },
240 241
      &action_middle_click_titlebar,
    },
242 243 244 245 246
    {
      { "action-right-click-titlebar",
        SCHEMA_GENERAL,
        META_PREF_ACTION_RIGHT_CLICK_TITLEBAR,
      },
247 248
      &action_right_click_titlebar,
    },
249 250 251 252 253 254 255
    {
      { "placement-mode",
        SCHEMA_METACITY,
        META_PREF_PLACEMENT_MODE,
      },
      &placement_mode,
    },
256 257 258 259 260 261 262
    {
      { "type",
        SCHEMA_METACITY_THEME,
        META_PREF_THEME_TYPE,
      },
      &current_theme_type,
    },
263 264 265 266 267 268 269
    {
      { "compositor",
        SCHEMA_METACITY,
        META_PREF_COMPOSITOR,
      },
      &compositor,
    },
270
    { { NULL, 0, 0 }, NULL },
271 272
  };

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

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

Thomas Thurman's avatar
Thomas Thurman committed
411 412
static MetaIntPreference preferences_int[] =
  {
413 414 415 416 417 418
    {
      { "num-workspaces",
        SCHEMA_GENERAL,
        META_PREF_NUM_WORKSPACES,
      },
      &num_workspaces
Thomas Thurman's avatar
Thomas Thurman committed
419
    },
420 421 422 423 424 425
    {
      { "auto-raise-delay",
        SCHEMA_GENERAL,
        META_PREF_AUTO_RAISE_DELAY,
      },
      &auto_raise_delay
Thomas Thurman's avatar
Thomas Thurman committed
426
    },
427
    { { NULL, 0, 0 }, NULL },
Thomas Thurman's avatar
Thomas Thurman committed
428 429
  };

430 431 432 433 434
static void
handle_preference_init_enum (void)
{
  MetaEnumPreference *cursor = preferences_enum;

435
  while (cursor->base.key != NULL)
436
    {
437 438
      if (cursor->target==NULL)
          continue;
439

440 441
      *((gint *) cursor->target) =
        g_settings_get_enum (SETTINGS (cursor->base.schema), cursor->base.key);
442 443 444 445 446

      ++cursor;
    }
}

447 448 449 450 451
static void
handle_preference_init_bool (void)
{
  MetaBoolPreference *cursor = preferences_bool;

452
  while (cursor->base.key != NULL)
453 454
    {
      if (cursor->target!=NULL)
455 456 457
        *cursor->target =
          g_settings_get_boolean (SETTINGS (cursor->base.schema),
                                  cursor->base.key);
458 459 460 461 462 463 464

      ++cursor;
    }

  maybe_give_disable_workarounds_warning ();
}

465 466 467 468 469
static void
handle_preference_init_string (void)
{
  MetaStringPreference *cursor = preferences_string;

470
  while (cursor->base.key != NULL)
471 472 473
    {
      char *value;

474
      /* Complex keys have a mapping function to check validity */
475 476 477
      if (cursor->handler)
        {
          if (cursor->target)
478
            g_error ("%s has both a target and a handler", cursor->base.key);
479

480 481
          g_settings_get_mapped (SETTINGS (cursor->base.schema),
                                 cursor->base.key, cursor->handler, NULL);
482
        }
483
      else
484
        {
485
          if (!cursor->target)
486
            g_error ("%s must have handler or target", cursor->base.key);
487

488 489 490
          if (*(cursor->target))
            g_free (*(cursor->target));

491 492 493
          value = g_settings_get_string (SETTINGS (cursor->base.schema),
                                         cursor->base.key);

494 495 496 497 498 499 500
          *(cursor->target) = value;
        }

      ++cursor;
    }
}

Thomas Thurman's avatar
Thomas Thurman committed
501 502 503 504 505
static void
handle_preference_init_int (void)
{
  MetaIntPreference *cursor = preferences_int;

506

507
  while (cursor->base.key != NULL)
Thomas Thurman's avatar
Thomas Thurman committed
508
    {
509 510 511
      if (cursor->target)
        *cursor->target = g_settings_get_int (SETTINGS (cursor->base.schema),
                                              cursor->base.key);
Thomas Thurman's avatar
Thomas Thurman committed
512 513 514 515 516

      ++cursor;
    }
}

517 518 519
static void
handle_preference_update_enum (GSettings *settings,
                               gchar *key)
520 521 522 523
{
  MetaEnumPreference *cursor = preferences_enum;
  gint old_value;

524
  while (cursor->base.key != NULL && strcmp (key, cursor->base.key) != 0)
525 526
    ++cursor;

527
  if (cursor->base.key==NULL)
528
    /* Didn't recognise that key. */
529
    return;
530 531

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

535 536
  *((gint *) cursor->target) =
    g_settings_get_enum (SETTINGS (cursor->base.schema), key);
537 538 539

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

543 544 545
static void
handle_preference_update_bool (GSettings *settings,
                               gchar *key)
546 547 548 549
{
  MetaBoolPreference *cursor = preferences_bool;
  gboolean old_value;

550
  while (cursor->base.key != NULL && strcmp (key, cursor->base.key) != 0)
551 552
    ++cursor;

553 554 555
  if (cursor->base.key==NULL || cursor->target==NULL)
    /* Unknown key or no work for us to do. */
    return;
556 557

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

561 562
  *((gboolean *) cursor->target) =
    g_settings_get_boolean (SETTINGS (cursor->base.schema), key);
563 564 565

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

568
  if (cursor->base.pref==META_PREF_DISABLE_WORKAROUNDS)
569 570 571
    maybe_give_disable_workarounds_warning ();
}

572 573 574
static void
handle_preference_update_string (GSettings *settings,
                                 gchar *key)
575 576
{
  MetaStringPreference *cursor = preferences_string;
577 578
  char *value;
  gboolean inform_listeners = FALSE;
579

580
  while (cursor->base.key != NULL && strcmp (key, cursor->base.key) != 0)
581 582
    ++cursor;

583
  if (cursor->base.key==NULL)
584
    /* Didn't recognise that key. */
585
    return;
586

587 588
  /* Complex keys have a mapping function to check validity */
  if (cursor->handler)
589
    {
590
      if (cursor->target)
591
        g_error ("%s has both a target and a handler", cursor->base.key);
592 593 594

      g_settings_get_mapped (SETTINGS (cursor->base.schema),
                             cursor->base.key, cursor->handler, NULL);
595
    }
596 597 598
  else
    {
      if (!cursor->target)
599
        g_error ("%s must have handler or target", cursor->base.key);
600

601 602 603
      value = g_settings_get_string (SETTINGS (cursor->base.schema),
                                     cursor->base.key);
      inform_listeners = (g_strcmp0 (value, *(cursor->target)) != 0);
604 605

      if (*(cursor->target))
606
        g_free (*(cursor->target));
607

608
      *(cursor->target) = value;
609 610 611
    }

  if (inform_listeners)
612
    queue_changed (cursor->base.pref);
613 614
}

615 616 617
static void
handle_preference_update_int (GSettings *settings,
                              gchar *key)
Thomas Thurman's avatar
Thomas Thurman committed
618 619 620 621
{
  MetaIntPreference *cursor = preferences_int;
  gint new_value;

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

625 626 627
  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
628

629
  new_value = g_settings_get_int (SETTINGS (cursor->base.schema), key);
Thomas Thurman's avatar
Thomas Thurman committed
630 631 632 633 634

  /* Did it change?  If so, tell the listeners about it. */
  if (*cursor->target != new_value)
    {
      *cursor->target = new_value;
635
      queue_changed (cursor->base.pref);
Thomas Thurman's avatar
Thomas Thurman committed
636 637 638 639 640 641 642
    }
}

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

643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674
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;
        }
675

676 677 678
      tmp = tmp->next;
    }

679
  g_error ("Did not find listener to remove");
680 681 682 683 684 685 686 687
}

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

688 689
  meta_topic (META_DEBUG_PREFS, "Notifying listeners that pref %s changed\n",
              meta_preference_to_string (pref));
690

691
  copy = g_list_copy (listeners);
692

693
  tmp = copy;
694

695 696 697 698 699
  while (tmp != NULL)
    {
      MetaPrefsListener *l = tmp->data;

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

701 702 703 704 705 706 707 708 709 710 711 712 713
      tmp = tmp->next;
    }

  g_list_free (copy);
}

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

  changed_idle = 0;
714

715 716 717 718
  copy = g_list_copy (changes); /* reentrancy paranoia */

  g_list_free (changes);
  changes = NULL;
719

720 721 722 723 724 725
  tmp = copy;
  while (tmp != NULL)
    {
      MetaPreference pref = GPOINTER_TO_INT (tmp->data);

      emit_changed (pref);
726

727 728 729 730
      tmp = tmp->next;
    }

  g_list_free (copy);
731

732 733 734 735 736 737
  return FALSE;
}

static void
queue_changed (MetaPreference pref)
{
738
  meta_topic (META_DEBUG_PREFS, "Queueing change of pref %s\n",
739
              meta_preference_to_string (pref));
740

741 742 743
  if (g_list_find (changes, GINT_TO_POINTER (pref)) == NULL)
    changes = g_list_prepend (changes, GINT_TO_POINTER (pref));
  else
744 745
    meta_topic (META_DEBUG_PREFS, "Change of pref %s was already pending\n",
                meta_preference_to_string (pref));
746

747
  if (changed_idle == 0)
748
    changed_idle = g_idle_add_full (META_PRIORITY_PREFS_NOTIFY,
749
                                    changed_idle_handler, NULL, NULL);
750
}
751

752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783
static void
gtk_cursor_theme_size_changed (GtkSettings *settings,
                               GParamSpec  *pspec,
                               gpointer     user_data)
{
  gint size;

  g_object_get (settings, "gtk-cursor-theme-size", &size, NULL);

  if (size == 0)
    size = 24;

  if (size != cursor_size)
    {
      cursor_size = size;
      queue_changed (META_PREF_CURSOR_SIZE);
    }
}

static void
init_gtk_cursor_theme_size (void)
{
  GtkSettings *settings;

  settings = gtk_settings_get_default ();

  g_signal_connect (settings, "notify::gtk-cursor-theme-size",
                    G_CALLBACK (gtk_cursor_theme_size_changed), NULL);

  gtk_cursor_theme_size_changed (settings, NULL, NULL);
}

784 785 786 787 788
static void
gtk_theme_name_changed (GtkSettings *settings,
                        GParamSpec  *pspec,
                        gpointer     user_data)
{
789 790
  if (current_theme_type == META_THEME_TYPE_GTK)
    queue_changed (META_PREF_THEME_NAME);
791 792 793 794 795 796 797 798 799 800 801 802 803
}

static void
init_gtk_theme_name (void)
{
  GtkSettings *settings;

  settings = gtk_settings_get_default ();

  g_signal_connect (settings, "notify::gtk-theme-name",
                    G_CALLBACK (gtk_theme_name_changed), NULL);
}

804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832
static void
update_compositing_manager (void)
{
  GVariant *user_value;
  gboolean compositing_manager;

  user_value = g_settings_get_user_value (SETTINGS (SCHEMA_METACITY),
                                          KEY_COMPOSITING_MANAGER);

  if (user_value == NULL)
    return;

  compositing_manager = g_variant_get_boolean (user_value);
  g_variant_unref (user_value);

  if (compositing_manager)
    meta_prefs_set_compositor (META_COMPOSITOR_TYPE_XRENDER);
  else
    meta_prefs_set_compositor (META_COMPOSITOR_TYPE_NONE);

  g_settings_reset (SETTINGS (SCHEMA_METACITY), KEY_COMPOSITING_MANAGER);
}

static void
init_compositing_manager (void)
{
  update_compositing_manager ();
}

Thomas Thurman's avatar
Thomas Thurman committed
833 834 835
/****************************************************************************/
/* Initialisation.                                                          */
/****************************************************************************/
836

837 838 839
void
meta_prefs_init (void)
{
840 841 842
  GSettings *settings;

  settings_schemas = g_hash_table_new_full (g_str_hash, g_str_equal,
843
                                            g_free, g_object_unref);
844 845 846

  settings = g_settings_new (SCHEMA_GENERAL);
  g_signal_connect (settings, "changed", G_CALLBACK (settings_changed), NULL);
847
  g_hash_table_insert (settings_schemas, g_strdup (SCHEMA_GENERAL), settings);
848 849 850

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

853 854 855 856
  settings = g_settings_new (SCHEMA_METACITY_THEME);
  g_signal_connect (settings, "changed", G_CALLBACK (settings_changed), NULL);
  g_hash_table_insert (settings_schemas, g_strdup (SCHEMA_METACITY_THEME), settings);

857 858 859 860 861 862 863 864
  /* 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);
865
  g_hash_table_insert (settings_schemas, g_strdup (SCHEMA_INTERFACE), settings);
866

867
  /* Pick up initial values. */
868
  handle_preference_init_enum ();
869
  handle_preference_init_bool ();
870
  handle_preference_init_string ();
Thomas Thurman's avatar
Thomas Thurman committed
871
  handle_preference_init_int ();
872

873
  init_bindings ();
874
  init_workspace_names ();
875
  init_compositing_manager ();
876

877
  init_gtk_cursor_theme_size ();
878
  init_gtk_theme_name ();
879 880
}

Thomas Thurman's avatar
Thomas Thurman committed
881 882 883 884
/****************************************************************************/
/* Updates.                                                                 */
/****************************************************************************/

885
static void
886 887 888 889 890 891 892 893
settings_changed (GSettings *settings,
                  gchar *key,
                  gpointer data)
{
  GVariant *value;
  const GVariantType *type;
  MetaEnumPreference *cursor;
  gboolean found_enum;
894

895 896
  /* String array, handled separately */
  if (strcmp (key, KEY_WORKSPACE_NAMES) == 0)
897
    {
898
      if (update_workspace_names ())
899
        queue_changed (META_PREF_WORKSPACE_NAMES);
900

901
      return;
902
    }
903 904
  else if (strcmp (key, KEY_COMPOSITING_MANAGER) == 0)
    {
905
      g_warning (_("Setting “compositing-manager” is deprecated, "
906 907 908 909 910
                   "use the “compositor” instead."));

      update_compositing_manager ();
      return;
    }
911

912 913
  value = g_settings_get_value (settings, key);
  type = g_variant_get_type (value);
914

915 916 917 918 919
  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))
920
    {
921 922
      cursor = preferences_enum;
      found_enum = FALSE;
923

924
      while (cursor->base.key != NULL)
925
        {
926 927
          if (strcmp (key, cursor->base.key) == 0)
            found_enum = TRUE;
928

929
          cursor++;
930 931
        }

932 933 934 935
      if (found_enum)
        handle_preference_update_enum (settings, key);
      else
        handle_preference_update_string (settings, key);
936
    }
937
  else
938 939 940 941
    /* Someone added a preference of an unhandled type */
    g_assert_not_reached ();

  g_variant_unref (value);
942
}
943 944

static void
945 946 947
bindings_changed (GSettings *settings,
                  gchar *key,
                  gpointer data)
948
{
949
  gchar **strokes;
950

951
  strokes = g_settings_get_strv (settings, key);
952

953 954
   if (update_key_binding (key, strokes))
     queue_changed (META_PREF_KEYBINDINGS);
955

956
  g_strfreev (strokes);
957 958 959 960 961 962 963 964 965 966
}

/**
 * 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;
967

968 969 970 971
  if (first_disable && disable_workarounds)
    {
      first_disable = FALSE;

972 973
      g_warning ("Workarounds for broken applications disabled. "
                 "Some applications may not behave properly.");
974 975 976
    }
}

977 978 979 980 981 982
MetaVirtualModifier
meta_prefs_get_mouse_button_mods  (void)
{
  return mouse_button_mods;
}

983
GDesktopFocusMode
984 985 986 987 988
meta_prefs_get_focus_mode (void)
{
  return focus_mode;
}

989
GDesktopFocusNewWindows
990 991 992 993 994
meta_prefs_get_focus_new_windows (void)
{
  return focus_new_windows;
}

995 996 997 998 999 1000
gboolean
meta_prefs_get_attach_modal_dialogs (void)
{
  return attach_modal_dialogs;
}

1001 1002 1003
gboolean
meta_prefs_get_raise_on_click (void)
{
1004
  return raise_on_click;
1005 1006
}

1007 1008
const gchar *
meta_prefs_get_theme_name (void)
1009
{
1010 1011 1012 1013 1014 1015 1016
  return current_theme_name;
}

MetaThemeType
meta_prefs_get_theme_type (void)
{
  return current_theme_type;
1017 1018
}

1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030
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
1031 1032 1033 1034
/****************************************************************************/
/* Handlers for string preferences.                                         */
/****************************************************************************/