summaryrefslogtreecommitdiff
path: root/capplets
diff options
context:
space:
mode:
authorPerberos <[email protected]>2011-12-01 21:51:44 -0300
committerPerberos <[email protected]>2011-12-01 21:51:44 -0300
commit0b0e6bc987da4fd88a7854ebb12bde705e92c428 (patch)
tree47d329edd31c67eaa36b2147780e37e197e901b5 /capplets
downloadmate-control-center-0b0e6bc987da4fd88a7854ebb12bde705e92c428.tar.bz2
mate-control-center-0b0e6bc987da4fd88a7854ebb12bde705e92c428.tar.xz
moving from https://github.com/perberos/mate-desktop-environment
Diffstat (limited to 'capplets')
-rw-r--r--capplets/Makefile.am31
-rw-r--r--capplets/about-me/AUTHORS2
-rw-r--r--capplets/about-me/Makefile.am59
-rw-r--r--capplets/about-me/e-image-chooser.c455
-rw-r--r--capplets/about-me/e-image-chooser.h66
-rw-r--r--capplets/about-me/eel-alert-dialog.c466
-rw-r--r--capplets/about-me/eel-alert-dialog.h61
-rw-r--r--capplets/about-me/eel-gtk-macros.h178
-rw-r--r--capplets/about-me/fingerprint-strings.h111
-rw-r--r--capplets/about-me/fprintd-marshal.list1
-rw-r--r--capplets/about-me/icons/Makefile.am30
-rw-r--r--capplets/about-me/icons/left-index-finger.pngbin0 -> 1515 bytes
-rw-r--r--capplets/about-me/icons/left-index-finger.svg177
-rw-r--r--capplets/about-me/icons/left-little-finger.pngbin0 -> 1500 bytes
-rw-r--r--capplets/about-me/icons/left-little-finger.svg180
-rw-r--r--capplets/about-me/icons/left-middle-finger.pngbin0 -> 1483 bytes
-rw-r--r--capplets/about-me/icons/left-middle-finger.svg180
-rw-r--r--capplets/about-me/icons/left-ring-finger.pngbin0 -> 1512 bytes
-rw-r--r--capplets/about-me/icons/left-ring-finger.svg180
-rw-r--r--capplets/about-me/icons/left-thumb.pngbin0 -> 1512 bytes
-rw-r--r--capplets/about-me/icons/left-thumb.svg180
-rw-r--r--capplets/about-me/icons/print_error.pngbin0 -> 4160 bytes
-rw-r--r--capplets/about-me/icons/print_error.svg525
-rw-r--r--capplets/about-me/icons/print_ok.pngbin0 -> 3677 bytes
-rw-r--r--capplets/about-me/icons/print_ok.svg310
-rw-r--r--capplets/about-me/icons/right-index-finger.pngbin0 -> 1506 bytes
-rw-r--r--capplets/about-me/icons/right-index-finger.svg179
-rw-r--r--capplets/about-me/icons/right-little-finger.pngbin0 -> 1479 bytes
-rw-r--r--capplets/about-me/icons/right-little-finger.svg182
-rw-r--r--capplets/about-me/icons/right-middle-finger.pngbin0 -> 1468 bytes
-rw-r--r--capplets/about-me/icons/right-middle-finger.svg182
-rw-r--r--capplets/about-me/icons/right-ring-finger.pngbin0 -> 1506 bytes
-rw-r--r--capplets/about-me/icons/right-ring-finger.svg182
-rw-r--r--capplets/about-me/icons/right-thumb.pngbin0 -> 1486 bytes
-rw-r--r--capplets/about-me/icons/right-thumb.svg182
-rw-r--r--capplets/about-me/mate-about-me-dialog.ui1622
-rw-r--r--capplets/about-me/mate-about-me-fingerprint.c624
-rw-r--r--capplets/about-me/mate-about-me-fingerprint.h27
-rw-r--r--capplets/about-me/mate-about-me-fingerprint.ui276
-rw-r--r--capplets/about-me/mate-about-me-password.c1136
-rw-r--r--capplets/about-me/mate-about-me-password.h9
-rw-r--r--capplets/about-me/mate-about-me-password.ui319
-rw-r--r--capplets/about-me/mate-about-me.c1005
-rw-r--r--capplets/about-me/mate-about-me.desktop.in.in14
-rw-r--r--capplets/accessibility/Makefile.am3
-rw-r--r--capplets/accessibility/at-properties/Makefile.am31
-rw-r--r--capplets/accessibility/at-properties/Makefile.in753
-rw-r--r--capplets/accessibility/at-properties/at-enable-dialog.ui351
-rw-r--r--capplets/accessibility/at-properties/at-properties.desktop.in.in14
-rw-r--r--capplets/accessibility/at-properties/at-startup.pngbin0 -> 2879 bytes
-rw-r--r--capplets/accessibility/at-properties/at-support.pngbin0 -> 2991 bytes
-rw-r--r--capplets/accessibility/at-properties/main.c293
-rw-r--r--capplets/appearance/Makefile.am58
-rw-r--r--capplets/appearance/appearance-desktop.c1400
-rw-r--r--capplets/appearance/appearance-desktop.h22
-rw-r--r--capplets/appearance/appearance-font.c961
-rw-r--r--capplets/appearance/appearance-font.h22
-rw-r--r--capplets/appearance/appearance-main.c218
-rw-r--r--capplets/appearance/appearance-style.c1073
-rw-r--r--capplets/appearance/appearance-style.h22
-rw-r--r--capplets/appearance/appearance-themes.c1179
-rw-r--r--capplets/appearance/appearance-themes.h22
-rw-r--r--capplets/appearance/appearance.h90
-rw-r--r--capplets/appearance/data/Makefile.am62
-rw-r--r--capplets/appearance/data/Makefile.in660
-rw-r--r--capplets/appearance/data/appearance.ui2603
-rw-r--r--capplets/appearance/data/cursor-large-white.pcfbin0 -> 18636 bytes
-rw-r--r--capplets/appearance/data/cursor-large.pcfbin0 -> 17432 bytes
-rw-r--r--capplets/appearance/data/cursor-white.pcfbin0 -> 13848 bytes
-rw-r--r--capplets/appearance/data/gtk-theme-thumbnailing.pngbin0 -> 1764 bytes
-rw-r--r--capplets/appearance/data/icon-theme-thumbnailing.pngbin0 -> 1167 bytes
-rw-r--r--capplets/appearance/data/mate-appearance-properties.desktop.in.in14
-rw-r--r--capplets/appearance/data/mate-theme-installer.desktop.in.in16
-rw-r--r--capplets/appearance/data/mate-theme-package.xml.in9
-rw-r--r--capplets/appearance/data/mouse-cursor-normal-large.pngbin0 -> 251 bytes
-rw-r--r--capplets/appearance/data/mouse-cursor-normal.pngbin0 -> 241 bytes
-rw-r--r--capplets/appearance/data/mouse-cursor-white-large.pngbin0 -> 268 bytes
-rw-r--r--capplets/appearance/data/mouse-cursor-white.pngbin0 -> 221 bytes
-rw-r--r--capplets/appearance/data/subpixel-bgr.pngbin0 -> 125 bytes
-rw-r--r--capplets/appearance/data/subpixel-rgb.pngbin0 -> 125 bytes
-rw-r--r--capplets/appearance/data/subpixel-vbgr.pngbin0 -> 138 bytes
-rw-r--r--capplets/appearance/data/subpixel-vrgb.pngbin0 -> 138 bytes
-rw-r--r--capplets/appearance/data/theme-thumbnailing.pngbin0 -> 4482 bytes
-rw-r--r--capplets/appearance/data/window-theme-thumbnailing.pngbin0 -> 2183 bytes
-rw-r--r--capplets/appearance/mate-wp-info.c87
-rw-r--r--capplets/appearance/mate-wp-info.h45
-rw-r--r--capplets/appearance/mate-wp-item.c307
-rw-r--r--capplets/appearance/mate-wp-item.h91
-rw-r--r--capplets/appearance/mate-wp-xml.c451
-rw-r--r--capplets/appearance/mate-wp-xml.h28
-rw-r--r--capplets/appearance/theme-installer.c801
-rw-r--r--capplets/appearance/theme-installer.h28
-rw-r--r--capplets/appearance/theme-save.c381
-rw-r--r--capplets/appearance/theme-save.h22
-rw-r--r--capplets/appearance/theme-util.c263
-rw-r--r--capplets/appearance/theme-util.h63
-rw-r--r--capplets/common/Makefile.am63
-rw-r--r--capplets/common/activate-settings-daemon.c60
-rw-r--r--capplets/common/activate-settings-daemon.h9
-rw-r--r--capplets/common/capplet-stock-icons.c101
-rw-r--r--capplets/common/capplet-stock-icons.h66
-rw-r--r--capplets/common/capplet-util.c205
-rw-r--r--capplets/common/capplet-util.h46
-rw-r--r--capplets/common/file-transfer-dialog.c608
-rw-r--r--capplets/common/file-transfer-dialog.h73
-rw-r--r--capplets/common/gtkrc-utils.c256
-rw-r--r--capplets/common/gtkrc-utils.h25
-rw-r--r--capplets/common/mate-theme-apply.c136
-rw-r--r--capplets/common/mate-theme-apply.h33
-rw-r--r--capplets/common/mate-theme-info.c1988
-rw-r--r--capplets/common/mate-theme-info.h190
-rw-r--r--capplets/common/mate-theme-test.c134
-rw-r--r--capplets/common/mateconf-property-editor-marshal.c41
-rw-r--r--capplets/common/mateconf-property-editor-marshal.h19
-rw-r--r--capplets/common/mateconf-property-editor.c1801
-rw-r--r--capplets/common/mateconf-property-editor.h162
-rw-r--r--capplets/common/theme-thumbnail.c1144
-rw-r--r--capplets/common/theme-thumbnail.h37
-rw-r--r--capplets/common/wm-common.c184
-rw-r--r--capplets/common/wm-common.h17
-rw-r--r--capplets/default-applications/Makefile.am75
-rw-r--r--capplets/default-applications/default-applications.desktop.in.in14
-rw-r--r--capplets/default-applications/icons/16x16/preferences-desktop-default-applications.pngbin0 -> 748 bytes
-rw-r--r--capplets/default-applications/icons/22x22/preferences-desktop-default-applications.pngbin0 -> 1310 bytes
-rw-r--r--capplets/default-applications/icons/24x24/preferences-desktop-default-applications.pngbin0 -> 1340 bytes
-rw-r--r--capplets/default-applications/icons/32x32/preferences-desktop-default-applications.pngbin0 -> 1727 bytes
-rw-r--r--capplets/default-applications/icons/48x48/preferences-desktop-default-applications.pngbin0 -> 2825 bytes
-rw-r--r--capplets/default-applications/mate-at-commandline.in.in101
-rw-r--r--capplets/default-applications/mate-at-session.desktop.in.in15
-rw-r--r--capplets/default-applications/mate-da-capplet.c970
-rw-r--r--capplets/default-applications/mate-da-capplet.h139
-rw-r--r--capplets/default-applications/mate-da-item.c148
-rw-r--r--capplets/default-applications/mate-da-item.h81
-rw-r--r--capplets/default-applications/mate-da-xml.c327
-rw-r--r--capplets/default-applications/mate-da-xml.h27
-rw-r--r--capplets/default-applications/mate-default-applications-properties.ui1518
-rw-r--r--capplets/default-applications/mate-default-applications.pc.in10
-rw-r--r--capplets/default-applications/mate-default-applications.xml.in483
-rw-r--r--capplets/display/Makefile.am78
-rw-r--r--capplets/display/TODO837
-rw-r--r--capplets/display/display-capplet.ui437
-rw-r--r--capplets/display/display-properties.desktop.in.in14
-rw-r--r--capplets/display/foo-marshal.c279
-rw-r--r--capplets/display/foo-marshal.h67
-rw-r--r--capplets/display/icons/16x16/mate-preferences-desktop-display.pngbin0 -> 613 bytes
-rw-r--r--capplets/display/icons/22x22/mate-preferences-desktop-display.pngbin0 -> 866 bytes
-rw-r--r--capplets/display/icons/24x24/mate-preferences-desktop-display.pngbin0 -> 909 bytes
-rw-r--r--capplets/display/icons/32x32/mate-preferences-desktop-display.pngbin0 -> 1602 bytes
-rw-r--r--capplets/display/icons/scalable/mate-preferences-desktop-display.svg470
-rw-r--r--capplets/display/mate-display-properties-install-systemwide.c272
-rw-r--r--capplets/display/org.mate.randr.policy.in29
-rw-r--r--capplets/display/scrollarea.c1944
-rw-r--r--capplets/display/scrollarea.h124
-rw-r--r--capplets/display/xrandr-capplet.c2571
-rw-r--r--capplets/keybindings/00-multimedia-key.xml.in35
-rw-r--r--capplets/keybindings/01-desktop-key.xml.in29
-rw-r--r--capplets/keybindings/Makefile.am46
-rw-r--r--capplets/keybindings/eggaccelerators.c632
-rw-r--r--capplets/keybindings/eggaccelerators.h99
-rw-r--r--capplets/keybindings/eggcellrendererkeys.c695
-rw-r--r--capplets/keybindings/eggcellrendererkeys.h93
-rw-r--r--capplets/keybindings/mate-keybinding-properties.c1948
-rw-r--r--capplets/keybindings/mate-keybinding-properties.ui301
-rw-r--r--capplets/keybindings/mate-keybinding.desktop.in.in14
-rw-r--r--capplets/keybindings/mate-keybindings.pc.in10
-rw-r--r--capplets/keyboard/Makefile.am42
-rw-r--r--capplets/keyboard/keyboard.desktop.in.in14
-rw-r--r--capplets/keyboard/mate-keyboard-properties-a11y-notifications.ui526
-rw-r--r--capplets/keyboard/mate-keyboard-properties-a11y.c325
-rw-r--r--capplets/keyboard/mate-keyboard-properties-a11y.h32
-rw-r--r--capplets/keyboard/mate-keyboard-properties-dialog.ui1857
-rw-r--r--capplets/keyboard/mate-keyboard-properties-layout-chooser.ui315
-rw-r--r--capplets/keyboard/mate-keyboard-properties-model-chooser.ui142
-rw-r--r--capplets/keyboard/mate-keyboard-properties-options-dialog.ui94
-rw-r--r--capplets/keyboard/mate-keyboard-properties-xkb.c254
-rw-r--r--capplets/keyboard/mate-keyboard-properties-xkb.h104
-rw-r--r--capplets/keyboard/mate-keyboard-properties-xkblt.c475
-rw-r--r--capplets/keyboard/mate-keyboard-properties-xkbltadd.c561
-rw-r--r--capplets/keyboard/mate-keyboard-properties-xkbmc.c347
-rw-r--r--capplets/keyboard/mate-keyboard-properties-xkbot.c516
-rw-r--r--capplets/keyboard/mate-keyboard-properties-xkbpv.c136
-rw-r--r--capplets/keyboard/mate-keyboard-properties.c265
-rw-r--r--capplets/mouse/Makefile.am35
-rw-r--r--capplets/mouse/double-click-maybe.pngbin0 -> 4643 bytes
-rw-r--r--capplets/mouse/double-click-off.pngbin0 -> 4751 bytes
-rw-r--r--capplets/mouse/double-click-on.pngbin0 -> 6360 bytes
-rw-r--r--capplets/mouse/mate-mouse-accessibility.c232
-rw-r--r--capplets/mouse/mate-mouse-accessibility.h33
-rw-r--r--capplets/mouse/mate-mouse-properties.c647
-rw-r--r--capplets/mouse/mate-mouse-properties.ui1707
-rw-r--r--capplets/mouse/mate-settings-mouse.desktop.in.in14
-rw-r--r--capplets/network/Makefile.am50
-rw-r--r--capplets/network/icons/16x16/mate-network-properties.pngbin0 -> 824 bytes
-rw-r--r--capplets/network/icons/22x22/mate-network-properties.pngbin0 -> 1081 bytes
-rw-r--r--capplets/network/icons/24x24/mate-network-properties.pngbin0 -> 1081 bytes
-rw-r--r--capplets/network/icons/32x32/mate-network-properties.pngbin0 -> 1855 bytes
-rw-r--r--capplets/network/icons/48x48/mate-network-properties.pngbin0 -> 3191 bytes
-rw-r--r--capplets/network/icons/scalable/mate-network-properties.svg628
-rw-r--r--capplets/network/mate-network-properties.c1397
-rw-r--r--capplets/network/mate-network-properties.desktop.in.in14
-rw-r--r--capplets/network/mate-network-properties.ui1056
-rw-r--r--capplets/windows/Makefile.am32
-rw-r--r--capplets/windows/mate-window-properties.c636
-rw-r--r--capplets/windows/mate-window-properties.ui387
-rw-r--r--capplets/windows/window-properties.desktop.in.in14
205 files changed, 56791 insertions, 0 deletions
diff --git a/capplets/Makefile.am b/capplets/Makefile.am
new file mode 100644
index 00000000..004d00fd
--- /dev/null
+++ b/capplets/Makefile.am
@@ -0,0 +1,31 @@
+SUBDIRS = \
+ common \
+ accessibility \
+ appearance \
+ default-applications \
+ display \
+ keybindings \
+ keyboard \
+ mouse \
+ network \
+ windows
+
+DIST_SUBDIRS = \
+ common \
+ accessibility \
+ appearance \
+ default-applications \
+ keybindings \
+ keyboard \
+ mouse \
+ network \
+ windows \
+ display \
+ about-me
+
+
+if BUILD_ABOUTME
+SUBDIRS += about-me
+endif
+
+-include $(top_srcdir)/git.mk
diff --git a/capplets/about-me/AUTHORS b/capplets/about-me/AUTHORS
new file mode 100644
index 00000000..c02ecb55
--- /dev/null
+++ b/capplets/about-me/AUTHORS
@@ -0,0 +1,2 @@
+Diego Gonzalez Gonzalez <[email protected]>
+Chris Toshok <[email protected]> \ No newline at end of file
diff --git a/capplets/about-me/Makefile.am b/capplets/about-me/Makefile.am
new file mode 100644
index 00000000..6cd5e139
--- /dev/null
+++ b/capplets/about-me/Makefile.am
@@ -0,0 +1,59 @@
+SUBDIRS = icons
+
+# This is used in MATECC_CAPPLETS_CFLAGS
+cappletname = about-me
+
+ui_files = mate-about-me-dialog.ui mate-about-me-password.ui mate-about-me-fingerprint.ui
+Desktop_in_files = mate-about-me.desktop.in
+
+mate_about_me_SOURCES = \
+ eel-alert-dialog.c \
+ eel-alert-dialog.h \
+ eel-gtk-macros.h \
+ mate-about-me-password.c \
+ mate-about-me-password.h \
+ e-image-chooser.c \
+ e-image-chooser.h \
+ mate-about-me-fingerprint.c \
+ mate-about-me-fingerprint.h \
+ $(MARSHALFILES) \
+ fingerprint-strings.h \
+ mate-about-me.c
+
+MARSHALFILES = marshal.c marshal.h
+BUILT_SOURCES = $(MARSHALFILES)
+
+marshal.h: fprintd-marshal.list
+ @GLIB_GENMARSHAL@ --prefix=fprintd_marshal $< --header > $@
+marshal.c: fprintd-marshal.list
+ @GLIB_GENMARSHAL@ --prefix=fprintd_marshal $< --body --header > $@
+
+if BUILD_ABOUTME
+bin_PROGRAMS = mate-about-me
+
+mate_about_me_LDADD = $(MATECC_CAPPLETS_LIBS) $(LIBEBOOK_LIBS)
+mate_about_me_LDFLAGS = -export-dynamic
+
+@INTLTOOL_DESKTOP_RULE@
+
+desktopdir = $(datadir)/applications
+desktop_DATA = $(Desktop_in_files:.desktop.in=.desktop)
+
+uidir = $(pkgdatadir)/ui
+ui_DATA = $(ui_files)
+
+INCLUDES = \
+ $(MATECC_CAPPLETS_CFLAGS) \
+ $(LIBEBOOK_CFLAGS) \
+ -DDATADIR="\"$(datadir)\"" \
+ -DMATECC_DATA_DIR="\"$(pkgdatadir)\"" \
+ -DMATECC_UI_DIR="\"$(uidir)\"" \
+ -DMATECC_PIXMAP_DIR="\"$(pkgdatadir)/pixmaps\"" \
+ -DMATELOCALEDIR="\"$(datadir)/locale\""
+
+endif # BUILD_ABOUTME
+
+CLEANFILES = $(MATECC_CAPPLETS_CLEANFILES) $(desktop_DATA) $(MARSHALFILES)
+EXTRA_DIST = $(ui_files) fprintd-marshal.list
+
+-include $(top_srcdir)/git.mk
diff --git a/capplets/about-me/e-image-chooser.c b/capplets/about-me/e-image-chooser.c
new file mode 100644
index 00000000..31a189f1
--- /dev/null
+++ b/capplets/about-me/e-image-chooser.c
@@ -0,0 +1,455 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* e-image-chooser.c
+ * Copyright (C) 2004 Novell, Inc.
+ * Author: Chris Toshok <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#include <string.h>
+
+#include <glib-object.h>
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+#include <gtk/gtk.h>
+
+#include "e-image-chooser.h"
+
+struct _EImageChooserPrivate {
+
+ GtkWidget *image;
+ GtkWidget *browse_button;
+
+ char *image_buf;
+ int image_buf_size;
+ int image_width;
+ int image_height;
+
+ gboolean editable;
+};
+
+enum {
+ CHANGED,
+ LAST_SIGNAL
+};
+
+
+static gint image_chooser_signals [LAST_SIGNAL] = { 0 };
+
+static void e_image_chooser_init (EImageChooser *chooser);
+static void e_image_chooser_class_init (EImageChooserClass *klass);
+static void e_image_chooser_dispose (GObject *object);
+
+static gboolean image_drag_motion_cb (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x, gint y, guint time, EImageChooser *chooser);
+static gboolean image_drag_drop_cb (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x, gint y, guint time, EImageChooser *chooser);
+static void image_drag_data_received_cb (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x, gint y,
+ GtkSelectionData *selection_data,
+ guint info, guint time, EImageChooser *chooser);
+
+static GtkObjectClass *parent_class = NULL;
+#define PARENT_TYPE GTK_TYPE_VBOX
+
+enum DndTargetType {
+ DND_TARGET_TYPE_URI_LIST
+};
+#define URI_LIST_TYPE "text/uri-list"
+
+static GtkTargetEntry image_drag_types[] = {
+ { URI_LIST_TYPE, 0, DND_TARGET_TYPE_URI_LIST },
+};
+static const int num_image_drag_types = sizeof (image_drag_types) / sizeof (image_drag_types[0]);
+
+GtkWidget *
+e_image_chooser_new (void)
+{
+ return g_object_new (E_TYPE_IMAGE_CHOOSER, NULL);
+}
+
+GType
+e_image_chooser_get_type (void)
+{
+ static GType eic_type = 0;
+
+ if (!eic_type) {
+ static const GTypeInfo eic_info = {
+ sizeof (EImageChooserClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) e_image_chooser_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (EImageChooser),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) e_image_chooser_init,
+ };
+
+ eic_type = g_type_register_static (PARENT_TYPE, "EImageChooser", &eic_info, 0);
+ }
+
+ return eic_type;
+}
+
+
+static void
+e_image_chooser_class_init (EImageChooserClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_ref (PARENT_TYPE);
+
+ image_chooser_signals [CHANGED] =
+ g_signal_new ("changed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (EImageChooserClass, changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ GTK_TYPE_NONE, 0);
+
+ object_class->dispose = e_image_chooser_dispose;
+}
+
+static void
+e_image_chooser_init (EImageChooser *chooser)
+{
+ EImageChooserPrivate *priv;
+
+ priv = chooser->priv = g_new0 (EImageChooserPrivate, 1);
+
+ priv->image = gtk_image_new ();
+
+ gtk_box_set_homogeneous (GTK_BOX (chooser), FALSE);
+ gtk_box_pack_start (GTK_BOX (chooser), priv->image, TRUE, TRUE, 0);
+
+ gtk_drag_dest_set (priv->image, 0, image_drag_types, num_image_drag_types, GDK_ACTION_COPY);
+ g_signal_connect (priv->image,
+ "drag_motion", G_CALLBACK (image_drag_motion_cb), chooser);
+ g_signal_connect (priv->image,
+ "drag_drop", G_CALLBACK (image_drag_drop_cb), chooser);
+ g_signal_connect (priv->image,
+ "drag_data_received", G_CALLBACK (image_drag_data_received_cb), chooser);
+
+ gtk_widget_show_all (priv->image);
+
+ /* we default to being editable */
+ priv->editable = TRUE;
+}
+
+static void
+e_image_chooser_dispose (GObject *object)
+{
+ EImageChooser *eic = E_IMAGE_CHOOSER (object);
+
+ if (eic->priv) {
+ EImageChooserPrivate *priv = eic->priv;
+
+ if (priv->image_buf) {
+ g_free (priv->image_buf);
+ priv->image_buf = NULL;
+ }
+
+ g_free (eic->priv);
+ eic->priv = NULL;
+ }
+
+ if (G_OBJECT_CLASS (parent_class)->dispose)
+ (* G_OBJECT_CLASS (parent_class)->dispose) (object);
+}
+
+
+static gboolean
+set_image_from_data (EImageChooser *chooser,
+ char *data, int length)
+{
+ gboolean rv = FALSE;
+ GdkPixbufLoader *loader = gdk_pixbuf_loader_new ();
+ GdkPixbuf *pixbuf;
+
+ gdk_pixbuf_loader_write (loader, data, length, NULL);
+ gdk_pixbuf_loader_close (loader, NULL);
+
+ pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
+ if (pixbuf)
+ g_object_ref (pixbuf);
+ g_object_unref (loader);
+
+ if (pixbuf) {
+ GdkPixbuf *scaled;
+ GtkRequisition chooser_size;
+
+ float scale;
+ int new_height, new_width;
+
+ gtk_widget_size_request (gtk_widget_get_parent (GTK_WIDGET (chooser)),
+ &chooser_size);
+ chooser_size.width -= 5;
+ chooser_size.height -= 5;
+
+ new_height = gdk_pixbuf_get_height (pixbuf);
+ new_width = gdk_pixbuf_get_width (pixbuf);
+
+ if (chooser->priv->image_height == 0
+ && chooser->priv->image_width == 0) {
+ scale = 1.0;
+ }
+ else if (chooser->priv->image_height < new_height
+ || chooser->priv->image_width < new_width) {
+ /* we need to scale down */
+ if (new_height > new_width)
+ scale = (float)chooser_size.height / new_height;
+ else
+ scale = (float)chooser_size.width / new_width;
+ }
+ else {
+ /* we need to scale up */
+ if (new_height > new_width)
+ scale = (float)new_height / chooser_size.height;
+ else
+ scale = (float)new_width / chooser_size.width;
+ }
+
+ if (scale == 1.0) {
+ gtk_image_set_from_pixbuf (GTK_IMAGE (chooser->priv->image), pixbuf);
+
+ chooser->priv->image_width = new_width;
+ chooser->priv->image_height = new_height;
+ }
+ else {
+ new_width *= scale;
+ new_height *= scale;
+ new_width = MIN (new_width, chooser_size.width);
+ new_height = MIN (new_height, chooser_size.height);
+
+ scaled = gdk_pixbuf_scale_simple (pixbuf,
+ new_width, new_height,
+ GDK_INTERP_BILINEAR);
+
+ gtk_image_set_from_pixbuf (GTK_IMAGE (chooser->priv->image), scaled);
+ g_object_unref (scaled);
+ }
+
+ g_object_unref (pixbuf);
+
+ g_free (chooser->priv->image_buf);
+ chooser->priv->image_buf = data;
+ chooser->priv->image_buf_size = length;
+
+ g_signal_emit (chooser,
+ image_chooser_signals [CHANGED], 0);
+
+ rv = TRUE;
+ }
+
+ return rv;
+}
+
+static gboolean
+image_drag_motion_cb (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x, gint y, guint time, EImageChooser *chooser)
+{
+ GList *p;
+
+ if (!chooser->priv->editable)
+ return FALSE;
+
+ for (p = context->targets; p != NULL; p = p->next) {
+ char *possible_type;
+
+ possible_type = gdk_atom_name (GDK_POINTER_TO_ATOM (p->data));
+ if (!strcmp (possible_type, URI_LIST_TYPE)) {
+ g_free (possible_type);
+ gdk_drag_status (context, GDK_ACTION_COPY, time);
+ return TRUE;
+ }
+
+ g_free (possible_type);
+ }
+
+ return FALSE;
+}
+
+static gboolean
+image_drag_drop_cb (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x, gint y, guint time, EImageChooser *chooser)
+{
+ GList *p;
+
+ if (!chooser->priv->editable)
+ return FALSE;
+
+ if (context->targets == NULL) {
+ return FALSE;
+ }
+
+ for (p = context->targets; p != NULL; p = p->next) {
+ char *possible_type;
+
+ possible_type = gdk_atom_name (GDK_POINTER_TO_ATOM (p->data));
+ if (!strcmp (possible_type, URI_LIST_TYPE)) {
+ g_free (possible_type);
+ gtk_drag_get_data (widget, context,
+ GDK_POINTER_TO_ATOM (p->data),
+ time);
+ return TRUE;
+ }
+
+ g_free (possible_type);
+ }
+
+ return FALSE;
+}
+
+static void
+image_drag_data_received_cb (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x, gint y,
+ GtkSelectionData *selection_data,
+ guint info, guint time, EImageChooser *chooser)
+{
+ char *target_type;
+ gboolean handled = FALSE;
+
+ target_type = gdk_atom_name (gtk_selection_data_get_target (selection_data));
+
+ if (!strcmp (target_type, URI_LIST_TYPE)) {
+ const char *data = gtk_selection_data_get_data (selection_data);
+ char *uri;
+ GFile *file;
+ GInputStream *istream;
+ char *nl = strstr (data, "\r\n");
+
+ if (nl)
+ uri = g_strndup (data, nl - (char *) data);
+ else
+ uri = g_strdup (data);
+
+ file = g_file_new_for_uri (uri);
+ istream = G_INPUT_STREAM (g_file_read (file, NULL, NULL));
+
+ if (istream != NULL) {
+ GFileInfo *info;
+
+ info = g_file_query_info (file,
+ G_FILE_ATTRIBUTE_STANDARD_SIZE,
+ G_FILE_QUERY_INFO_NONE,
+ NULL, NULL);
+
+ if (info != NULL) {
+ gsize size;
+ gboolean success;
+ gchar *buf;
+
+ size = g_file_info_get_size (info);
+ g_object_unref (info);
+
+ buf = g_malloc (size);
+
+ success = g_input_stream_read_all (istream,
+ buf,
+ size,
+ &size,
+ NULL,
+ NULL);
+ g_input_stream_close (istream, NULL, NULL);
+
+ if (success &&
+ set_image_from_data (chooser, buf, size))
+ handled = TRUE;
+ else
+ g_free (buf);
+ }
+
+ g_object_unref (istream);
+ }
+
+ g_object_unref (file);
+ g_free (uri);
+ }
+
+ gtk_drag_finish (context, handled, FALSE, time);
+}
+
+gboolean
+e_image_chooser_set_from_file (EImageChooser *chooser, const char *filename)
+{
+ gchar *data;
+ gsize data_length;
+
+ g_return_val_if_fail (E_IS_IMAGE_CHOOSER (chooser), FALSE);
+ g_return_val_if_fail (filename, FALSE);
+
+ if (!g_file_get_contents (filename, &data, &data_length, NULL)) {
+ return FALSE;
+ }
+
+ if (!set_image_from_data (chooser, data, data_length))
+ g_free (data);
+
+ return TRUE;
+}
+
+void
+e_image_chooser_set_editable (EImageChooser *chooser, gboolean editable)
+{
+ g_return_if_fail (E_IS_IMAGE_CHOOSER (chooser));
+
+ chooser->priv->editable = editable;
+
+ gtk_widget_set_sensitive (chooser->priv->browse_button, editable);
+}
+
+gboolean
+e_image_chooser_get_image_data (EImageChooser *chooser, char **data, gsize *data_length)
+{
+ g_return_val_if_fail (E_IS_IMAGE_CHOOSER (chooser), FALSE);
+ g_return_val_if_fail (data != NULL, FALSE);
+ g_return_val_if_fail (data_length != NULL, FALSE);
+
+ *data_length = chooser->priv->image_buf_size;
+ *data = g_malloc (*data_length);
+ memcpy (*data, chooser->priv->image_buf, *data_length);
+
+ return TRUE;
+}
+
+gboolean
+e_image_chooser_set_image_data (EImageChooser *chooser, char *data, gsize data_length)
+{
+ char *buf;
+
+ g_return_val_if_fail (E_IS_IMAGE_CHOOSER (chooser), FALSE);
+ g_return_val_if_fail (data != NULL, FALSE);
+
+ /* yuck, a copy... */
+ buf = g_malloc (data_length);
+ memcpy (buf, data, data_length);
+
+ if (!set_image_from_data (chooser, buf, data_length)) {
+ g_free (buf);
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/capplets/about-me/e-image-chooser.h b/capplets/about-me/e-image-chooser.h
new file mode 100644
index 00000000..b2b2fbf2
--- /dev/null
+++ b/capplets/about-me/e-image-chooser.h
@@ -0,0 +1,66 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* e-image-chooser.c
+ * Copyright (C) 2004 Novell, Inc.
+ * Author: Chris Toshok <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _E_IMAGE_CHOOSER_H_
+#define _E_IMAGE_CHOOSER_H_
+
+#include <gtk/gtk.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define E_TYPE_IMAGE_CHOOSER (e_image_chooser_get_type ())
+#define E_IMAGE_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_IMAGE_CHOOSER, EImageChooser))
+#define E_IMAGE_CHOOSER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_IMAGE_CHOOSER, EImageChooserClass))
+#define E_IS_IMAGE_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_IMAGE_CHOOSER))
+#define E_IS_IMAGE_CHOOSER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), E_TYPE_IMAGE_CHOOSER))
+
+typedef struct _EImageChooser EImageChooser;
+typedef struct _EImageChooserClass EImageChooserClass;
+typedef struct _EImageChooserPrivate EImageChooserPrivate;
+
+struct _EImageChooser
+{
+ GtkVBox parent;
+
+ EImageChooserPrivate *priv;
+};
+
+struct _EImageChooserClass
+{
+ GtkVBoxClass parent_class;
+
+ /* signals */
+ void (*changed) (EImageChooser *chooser);
+
+
+};
+
+GtkWidget *e_image_chooser_new (void);
+GType e_image_chooser_get_type (void);
+
+gboolean e_image_chooser_set_from_file (EImageChooser *chooser, const char *filename);
+gboolean e_image_chooser_set_image_data (EImageChooser *chooser, char *data, gsize data_length);
+void e_image_chooser_set_editable (EImageChooser *chooser, gboolean editable);
+
+gboolean e_image_chooser_get_image_data (EImageChooser *chooser, char **data, gsize *data_length);
+
+#endif /* _E_IMAGE_CHOOSER_H_ */
diff --git a/capplets/about-me/eel-alert-dialog.c b/capplets/about-me/eel-alert-dialog.c
new file mode 100644
index 00000000..6370d6db
--- /dev/null
+++ b/capplets/about-me/eel-alert-dialog.c
@@ -0,0 +1,466 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+
+/* eel-alert-dialog.c: An HIG compliant alert dialog.
+
+ The Mate Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Mate Library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Mate Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+*/
+
+#include "eel-alert-dialog.h"
+#include "eel-gtk-macros.h"
+
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+
+#include <string.h>
+
+enum {
+ PROP_0,
+ PROP_ALERT_TYPE,
+ PROP_BUTTONS
+};
+
+struct _EelAlertDialogDetails {
+ GtkWidget *image;
+ GtkWidget *primary_label;
+ GtkWidget *secondary_label;
+ GtkWidget *details_expander;
+ GtkWidget *details_label;
+ GtkMessageType type;
+};
+
+
+static gpointer parent_class;
+
+static void eel_alert_dialog_finalize (GObject *object);
+static void eel_alert_dialog_class_init (EelAlertDialogClass *klass);
+static void eel_alert_dialog_init (EelAlertDialog *dialog);
+static void eel_alert_dialog_style_set (GtkWidget *widget,
+ GtkStyle *prev_style);
+static void eel_alert_dialog_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void eel_alert_dialog_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void eel_alert_dialog_add_buttons (EelAlertDialog *alert_dialog,
+ GtkButtonsType buttons);
+
+GType
+eel_alert_dialog_get_type (void)
+{
+ static GType dialog_type = 0;
+
+ if (!dialog_type) {
+
+ static const GTypeInfo dialog_info =
+ {
+ sizeof (EelAlertDialogClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) eel_alert_dialog_class_init,
+ NULL,
+ NULL,
+ sizeof (EelAlertDialog),
+ 0,
+ (GInstanceInitFunc) eel_alert_dialog_init,
+ };
+
+ dialog_type = g_type_register_static (GTK_TYPE_DIALOG, "EelAlertDialog",
+ &dialog_info, 0);
+ }
+ return dialog_type;
+}
+
+static void
+eel_alert_dialog_class_init (EelAlertDialogClass *class)
+{
+ GtkWidgetClass *widget_class;
+ GObjectClass *gobject_class;
+
+ widget_class = GTK_WIDGET_CLASS (class);
+ gobject_class = G_OBJECT_CLASS (class);
+
+ parent_class = g_type_class_peek_parent (class);
+
+ G_OBJECT_CLASS (class)->finalize = eel_alert_dialog_finalize;
+
+ widget_class->style_set = eel_alert_dialog_style_set;
+
+ gobject_class->set_property = eel_alert_dialog_set_property;
+ gobject_class->get_property = eel_alert_dialog_get_property;
+
+ gtk_widget_class_install_style_property (widget_class,
+ g_param_spec_int ("alert_border",
+ _("Image/label border"),
+ _("Width of border around the label and image in the alert dialog"),
+ 0,
+ G_MAXINT,
+ 5,
+ G_PARAM_READABLE));
+
+ g_object_class_install_property (gobject_class,
+ PROP_ALERT_TYPE,
+ g_param_spec_enum ("alert_type",
+ _("Alert Type"),
+ _("The type of alert"),
+ GTK_TYPE_MESSAGE_TYPE,
+ GTK_MESSAGE_INFO,
+ G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (gobject_class,
+ PROP_BUTTONS,
+ g_param_spec_enum ("buttons",
+ _("Alert Buttons"),
+ _("The buttons shown in the alert dialog"),
+ GTK_TYPE_BUTTONS_TYPE,
+ GTK_BUTTONS_NONE,
+ G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+eel_alert_dialog_finalize (GObject *object)
+{
+ EelAlertDialog *dialog;
+
+ dialog = EEL_ALERT_DIALOG (object);
+
+ g_free (dialog->details);
+
+ EEL_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
+}
+
+
+static void
+eel_alert_dialog_init (EelAlertDialog *dialog)
+{
+ GtkWidget *hbox;
+ GtkWidget *vbox;
+ GtkWidget *expander;
+
+ dialog->details = g_new0 (EelAlertDialogDetails, 1);
+
+ dialog->details->primary_label = gtk_label_new (NULL);
+ dialog->details->secondary_label = gtk_label_new (NULL);
+ dialog->details->details_label = gtk_label_new (NULL);
+ dialog->details->image = gtk_image_new_from_stock (NULL, GTK_ICON_SIZE_DIALOG);
+ gtk_misc_set_alignment (GTK_MISC (dialog->details->image), 0.5, 0.0);
+
+ gtk_label_set_line_wrap (GTK_LABEL (dialog->details->primary_label), TRUE);
+ gtk_label_set_selectable (GTK_LABEL (dialog->details->primary_label), TRUE);
+ gtk_label_set_use_markup (GTK_LABEL (dialog->details->primary_label), TRUE);
+ gtk_misc_set_alignment (GTK_MISC (dialog->details->primary_label), 0.0, 0.5);
+
+ gtk_label_set_line_wrap (GTK_LABEL (dialog->details->secondary_label), TRUE);
+ gtk_label_set_selectable (GTK_LABEL (dialog->details->secondary_label), TRUE);
+ gtk_misc_set_alignment (GTK_MISC (dialog->details->secondary_label), 0.0, 0.5);
+
+ gtk_label_set_line_wrap (GTK_LABEL (dialog->details->details_label), TRUE);
+ gtk_label_set_selectable (GTK_LABEL (dialog->details->details_label), TRUE);
+ gtk_misc_set_alignment (GTK_MISC (dialog->details->details_label), 0.0, 0.5);
+
+ hbox = gtk_hbox_new (FALSE, 12);
+ gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
+
+ gtk_box_pack_start (GTK_BOX (hbox), dialog->details->image,
+ FALSE, FALSE, 0);
+
+ vbox = gtk_vbox_new (FALSE, 12);
+
+ gtk_box_pack_start (GTK_BOX (hbox), vbox,
+ FALSE, FALSE, 0);
+
+ gtk_box_pack_start (GTK_BOX (vbox), dialog->details->primary_label,
+ FALSE, FALSE, 0);
+
+ gtk_box_pack_start (GTK_BOX (vbox), dialog->details->secondary_label,
+ FALSE, FALSE, 0);
+
+ expander = gtk_expander_new_with_mnemonic (_("Show more _details"));
+ dialog->details->details_expander = expander;
+ gtk_expander_set_spacing (GTK_EXPANDER (expander), 6);
+ gtk_container_add (GTK_CONTAINER (expander), dialog->details->details_label);
+
+ gtk_box_pack_start (GTK_BOX (vbox), expander,
+ FALSE, FALSE, 0);
+
+
+ gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), hbox,
+ FALSE, FALSE, 0);
+
+ gtk_widget_show_all (hbox);
+ gtk_widget_hide (expander);
+
+}
+
+static void
+setup_type (EelAlertDialog *dialog,
+ GtkMessageType type)
+{
+ const gchar *stock_id = NULL;
+ GtkStockItem item;
+
+ switch (type) {
+ case GTK_MESSAGE_INFO:
+ stock_id = GTK_STOCK_DIALOG_INFO;
+ break;
+ case GTK_MESSAGE_QUESTION:
+ stock_id = GTK_STOCK_DIALOG_QUESTION;
+ break;
+ case GTK_MESSAGE_WARNING:
+ stock_id = GTK_STOCK_DIALOG_WARNING;
+ break;
+ case GTK_MESSAGE_ERROR:
+ stock_id = GTK_STOCK_DIALOG_ERROR;
+ break;
+ default:
+ g_warning ("Unknown GtkMessageType %d", type);
+ break;
+ }
+
+ if (stock_id == NULL) {
+ stock_id = GTK_STOCK_DIALOG_INFO;
+ }
+
+ if (gtk_stock_lookup (stock_id, &item)) {
+ gtk_image_set_from_stock (GTK_IMAGE (dialog->details->image), stock_id,
+ GTK_ICON_SIZE_DIALOG);
+ } else {
+ g_warning ("Stock dialog ID doesn't exist?");
+ }
+}
+
+static void
+eel_alert_dialog_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EelAlertDialog *dialog;
+
+ dialog = EEL_ALERT_DIALOG (object);
+
+ switch (prop_id) {
+ case PROP_ALERT_TYPE:
+ dialog->details->type = g_value_get_enum (value);
+ setup_type (dialog, dialog->details->type);
+ break;
+ case PROP_BUTTONS:
+ eel_alert_dialog_add_buttons (dialog, g_value_get_enum (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+eel_alert_dialog_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EelAlertDialog *dialog;
+
+ dialog = EEL_ALERT_DIALOG (object);
+
+ switch (prop_id) {
+ case PROP_ALERT_TYPE:
+ g_value_set_enum (value, dialog->details->type);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+void
+eel_alert_dialog_set_primary_label (EelAlertDialog *dialog,
+ const gchar *message)
+{
+ gchar *markup_str;
+ char *escaped_message;
+
+ if (message != NULL) {
+ escaped_message = g_markup_escape_text (message, -1);
+ markup_str = g_strconcat ("<span weight=\"bold\" size=\"larger\">", escaped_message, "</span>", NULL);
+ gtk_label_set_markup (GTK_LABEL (EEL_ALERT_DIALOG (dialog)->details->primary_label),
+ markup_str);
+ g_free (markup_str);
+ g_free (escaped_message);
+ }
+}
+
+void
+eel_alert_dialog_set_secondary_label (EelAlertDialog *dialog,
+ const gchar *message)
+{
+ if (message != NULL) {
+ gtk_label_set_text (GTK_LABEL (EEL_ALERT_DIALOG (dialog)->details->secondary_label),
+ message);
+ } else {
+ gtk_widget_hide (EEL_ALERT_DIALOG (dialog)->details->secondary_label);
+ }
+}
+
+void
+eel_alert_dialog_set_details_label (EelAlertDialog *dialog,
+ const gchar *message)
+{
+ if (message != NULL) {
+ gtk_widget_show (dialog->details->details_expander);
+ gtk_label_set_text (GTK_LABEL (dialog->details->details_label), message);
+ } else {
+ gtk_widget_hide (dialog->details->details_expander);
+ }
+}
+
+
+GtkWidget*
+eel_alert_dialog_new (GtkWindow *parent,
+ GtkDialogFlags flags,
+ GtkMessageType type,
+ GtkButtonsType buttons,
+ const gchar *primary_message,
+ const gchar *secondary_message,
+ const gchar *title)
+{
+ GtkWidget *widget;
+ GtkDialog *dialog;
+
+ g_return_val_if_fail (parent == NULL || GTK_IS_WINDOW (parent), NULL);
+
+ widget = g_object_new (EEL_TYPE_ALERT_DIALOG,
+ "alert_type", type,
+ "buttons", buttons,
+ NULL);
+ atk_object_set_role (gtk_widget_get_accessible (widget), ATK_ROLE_ALERT);
+
+ dialog = GTK_DIALOG (widget);
+
+ gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
+ gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), 14);
+ gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
+ gtk_dialog_set_has_separator (dialog, FALSE);
+
+ gtk_window_set_title (GTK_WINDOW (dialog),
+ (title != NULL) ? title : "");
+
+ eel_alert_dialog_set_primary_label (EEL_ALERT_DIALOG (dialog),
+ primary_message);
+
+ eel_alert_dialog_set_secondary_label (EEL_ALERT_DIALOG (dialog),
+ secondary_message);
+
+ if (parent != NULL) {
+ gtk_window_set_transient_for (GTK_WINDOW (widget),
+ GTK_WINDOW (parent));
+ }
+
+ if (flags & GTK_DIALOG_MODAL) {
+ gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
+ }
+
+ if (flags & GTK_DIALOG_DESTROY_WITH_PARENT) {
+ gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE);
+ }
+ return widget;
+}
+
+static void
+eel_alert_dialog_add_buttons (EelAlertDialog* alert_dialog,
+ GtkButtonsType buttons)
+{
+ GtkDialog* dialog;
+
+ dialog = GTK_DIALOG (alert_dialog);
+
+ switch (buttons) {
+ case GTK_BUTTONS_NONE:
+ break;
+ case GTK_BUTTONS_OK:
+ gtk_dialog_add_button (dialog,
+ GTK_STOCK_OK,
+ GTK_RESPONSE_OK);
+ gtk_dialog_set_default_response (dialog,
+ GTK_RESPONSE_OK);
+ break;
+ case GTK_BUTTONS_CLOSE:
+ gtk_dialog_add_button (dialog,
+ GTK_STOCK_CLOSE,
+ GTK_RESPONSE_CLOSE);
+ gtk_dialog_set_default_response (dialog,
+ GTK_RESPONSE_CLOSE);
+ break;
+ case GTK_BUTTONS_CANCEL:
+ gtk_dialog_add_button (dialog,
+ GTK_STOCK_CANCEL,
+ GTK_RESPONSE_CANCEL);
+ gtk_dialog_set_default_response (dialog,
+ GTK_RESPONSE_CANCEL);
+ break;
+ case GTK_BUTTONS_YES_NO:
+ gtk_dialog_add_button (dialog,
+ GTK_STOCK_NO,
+ GTK_RESPONSE_NO);
+ gtk_dialog_add_button (dialog,
+ GTK_STOCK_YES,
+ GTK_RESPONSE_YES);
+ gtk_dialog_set_default_response (dialog,
+ GTK_RESPONSE_YES);
+ break;
+ case GTK_BUTTONS_OK_CANCEL:
+ gtk_dialog_add_button (dialog,
+ GTK_STOCK_CANCEL,
+ GTK_RESPONSE_CANCEL);
+ gtk_dialog_add_button (dialog,
+ GTK_STOCK_OK,
+ GTK_RESPONSE_OK);
+ gtk_dialog_set_default_response (dialog,
+ GTK_RESPONSE_OK);
+ break;
+ default:
+ g_warning ("Unknown GtkButtonsType");
+ break;
+ }
+ g_object_notify (G_OBJECT (alert_dialog), "buttons");
+}
+
+static void
+eel_alert_dialog_style_set (GtkWidget *widget,
+ GtkStyle *prev_style)
+{
+ GtkWidget *parent;
+ gint border_width;
+
+ border_width = 0;
+
+ parent = gtk_widget_get_parent (EEL_ALERT_DIALOG (widget)->details->image);
+
+ if (parent != NULL) {
+ gtk_widget_style_get (widget, "alert_border",
+ &border_width, NULL);
+
+ gtk_container_set_border_width (GTK_CONTAINER (parent),
+ border_width);
+ }
+
+ if (GTK_WIDGET_CLASS (parent_class)->style_set) {
+ (GTK_WIDGET_CLASS (parent_class)->style_set) (widget, prev_style);
+ }
+}
diff --git a/capplets/about-me/eel-alert-dialog.h b/capplets/about-me/eel-alert-dialog.h
new file mode 100644
index 00000000..60c6b9c0
--- /dev/null
+++ b/capplets/about-me/eel-alert-dialog.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+
+/* eel-alert-dialog.h: An HIG compliant alert dialog.
+
+ The Mate Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Mate Library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Mate Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+*/
+
+#ifndef EEL_ALERT_DIALOG_H
+#define EEL_ALERT_DIALOG_H
+
+#include <gtk/gtk.h>
+
+#define EEL_TYPE_ALERT_DIALOG (eel_alert_dialog_get_type ())
+#define EEL_ALERT_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEL_TYPE_ALERT_DIALOG, EelAlertDialog))
+
+typedef struct _EelAlertDialog EelAlertDialog;
+typedef struct _EelAlertDialogClass EelAlertDialogClass;
+typedef struct _EelAlertDialogDetails EelAlertDialogDetails;
+
+struct _EelAlertDialog
+{
+ GtkDialog parent_instance;
+ EelAlertDialogDetails *details;
+};
+
+struct _EelAlertDialogClass
+{
+ GtkDialogClass parent_class;
+};
+
+GType eel_alert_dialog_get_type (void);
+
+GtkWidget* eel_alert_dialog_new (GtkWindow *parent,
+ GtkDialogFlags flags,
+ GtkMessageType type,
+ GtkButtonsType buttons,
+ const gchar *primary_message,
+ const gchar *secondary_message,
+ const gchar *title);
+void eel_alert_dialog_set_primary_label (EelAlertDialog *dialog,
+ const gchar *message);
+void eel_alert_dialog_set_secondary_label (EelAlertDialog *dialog,
+ const gchar *message);
+void eel_alert_dialog_set_details_label (EelAlertDialog *dialog,
+ const gchar *message);
+
+#endif /* EEL_ALERT_DIALOG_H */
diff --git a/capplets/about-me/eel-gtk-macros.h b/capplets/about-me/eel-gtk-macros.h
new file mode 100644
index 00000000..b3a9d671
--- /dev/null
+++ b/capplets/about-me/eel-gtk-macros.h
@@ -0,0 +1,178 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-
+
+ eel-gtk-macros.h: Macros to reduce boilerplate when using GTK.
+
+ Copyright (C) 1999, 2000, 2001 Eazel, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Authors: Darin Adler <[email protected]>
+ Ramiro Estrugo <[email protected]>
+*/
+
+#ifndef EEL_GTK_MACROS_H
+#define EEL_GTK_MACROS_H
+
+#ifndef EEL_DISABLE_DEPRECATED
+
+/* Define a parent_class global and a get_type function for a GTK class.
+ Since this is boilerplate, it's better not to repeat it over and over again.
+ Called like this:
+
+ EEL_CLASS_BOILERPLATE (EelBookmark, eel_bookmark, GTK_TYPE_OBJECT)
+
+ The parent_class_type parameter is guaranteed to be evaluated only once
+ so it can be an expression, even an expression that contains a function call.
+*/
+
+#define EEL_CLASS_BOILERPLATE(class_name, prefix, parent_class_type) \
+ EEL_BOILERPLATE (class_name, class_name, prefix, parent_class_type, \
+ EEL_REGISTER_TYPE)
+#define EEL_REGISTER_TYPE(class_name, corba_name) \
+ g_type_register_static (parent_type, #class_name, &info, 0)
+
+#define EEL_BOILERPLATE(class_name, corba_name, prefix, parent_class_type, \
+ register_type) \
+ \
+static gpointer parent_class; \
+ \
+GType \
+prefix##_get_type (void) \
+{ \
+ GType parent_type; \
+ static GType type; \
+ \
+ if (type == 0) { \
+ static GTypeInfo info = { \
+ sizeof (class_name##Class), \
+ NULL, NULL, \
+ (GClassInitFunc) prefix##_class_init, \
+ NULL, NULL, \
+ sizeof (class_name), 0, \
+ (GInstanceInitFunc) prefix##_init, \
+ NULL \
+ }; \
+ \
+ parent_type = (parent_class_type); \
+ type = register_type (class_name, corba_name); \
+ parent_class = g_type_class_ref (parent_type); \
+ } \
+ \
+ return type; \
+}
+
+/* Call a parent class version of a virtual function (or default
+ * signal handler since that's the same thing). Nice because it
+ * documents what it's doing and there is less chance for a
+ * typo. Depends on the parent class pointer having the conventional
+ * name "parent_class" as the boilerplate macro above does it.
+ */
+#define EEL_CALL_PARENT(parent_class_cast_macro, signal, parameters) \
+ \
+G_STMT_START { \
+ if (parent_class_cast_macro (parent_class)->signal != NULL) { \
+ (* parent_class_cast_macro (parent_class)->signal) parameters;\
+ } \
+} G_STMT_END
+
+/* Same thing, for functions with a return value. */
+#define EEL_CALL_PARENT_WITH_RETURN_VALUE(parent_class_cast_macro, signal, \
+ parameters) \
+ \
+(parent_class_cast_macro (parent_class)->signal == NULL) \
+ ? 0 \
+ : ((* parent_class_cast_macro (parent_class)->signal) parameters)
+
+#endif /* EEL_DISABLE_DEPRECATED */
+
+/* Call a virtual function. Useful when the virtual function is not a
+ * signal, otherwise you want to gtk_signal emit. Nice because it
+ * documents what it's doing and there is less chance for a typo.
+ */
+#define EEL_CALL_METHOD(class_cast_macro, object, signal, parameters) \
+ \
+G_STMT_START { \
+ if (class_cast_macro (G_OBJECT_GET_CLASS (object))->signal != NULL) { \
+ (* class_cast_macro (G_OBJECT_GET_CLASS (object))->signal) \
+ parameters; \
+ } \
+} G_STMT_END
+
+/* Same thing, for functions with a return value. */
+#define EEL_CALL_METHOD_WITH_RETURN_VALUE(class_cast_macro, object, signal, \
+ parameters) \
+ \
+(class_cast_macro (G_OBJECT_GET_CLASS (object))->signal == NULL) \
+ ? 0 \
+ : ((* class_cast_macro (G_OBJECT_GET_CLASS (object))->signal) \
+ parameters) \
+
+#ifndef G_DISABLE_ASSERT
+
+/* Define a signal that is not implemented by this class but must be
+ * implemented by subclasses. This macro should be used inside the
+ * class initialization function. The companion macro EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL
+ * must be used earlier in the file. Called like this:
+ *
+ * EEL_ASSIGN_MUST_OVERRIDE_SIGNAL (klass,
+ * fm_directory_view,
+ * clear);
+ */
+#define EEL_ASSIGN_MUST_OVERRIDE_SIGNAL(class_pointer, prefix, signal) \
+ \
+* (void (**)(void)) & (class_pointer)->signal = prefix##_unimplemented_##signal
+
+/* Provide a debug-only implementation of a signal that must be implemented
+ * by subclasses. The debug-only implementation fires a warning if it is called.
+ * This macro should be placed as if it were a function, earlier in the file
+ * than the class initialization function. Called like this:
+ *
+ * EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL (fm_directory_view, clear);
+ */
+#define EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL(prefix, signal) \
+ \
+static void \
+prefix##_unimplemented_##signal (void) \
+{ \
+ g_warning ("failed to override signal " #prefix "->" #signal); \
+}
+
+#else /* G_DISABLE_ASSERT */
+
+#define EEL_DEFINE_MUST_OVERRIDE_SIGNAL(class_cast_macro, class_pointer, prefix, signal)
+#define EEL_IMPLEMENT_MUST_OVERRIDE_SIGNAL(prefix, signal)
+#define EEL_ASSIGN_MUST_OVERRIDE_SIGNAL(class_pointer, prefix, signal)
+
+#endif /* G_DISABLE_ASSERT */
+
+/* Access a method. */
+#define EEL_ACCESS_METHOD(class_cast_macro, object, method) \
+(class_cast_macro (G_OBJECT_GET_CLASS (object))->method)
+
+/* Invoke a method for a given object. */
+#define EEL_INVOKE_METHOD(class_cast_macro, object, method, parameters) \
+((* EEL_ACCESS_METHOD (class_cast_macro, object, method)) parameters)
+
+/* Assert the non-nullness of a method for a given object. */
+#define EEL_ASSERT_METHOD(class_cast_macro, object, method) \
+g_assert (EEL_ACCESS_METHOD (class_cast_macro, object, method) != NULL)
+
+/* Invoke a method if it ain't null. */
+#define EEL_INVOKE_METHOD_IF(class_cast_macro, object, method, parameters) \
+(EEL_ACCESS_METHOD (class_cast_macro, object, method) ? 0 : \
+ EEL_INVOKE_METHOD (class_cast_macro, object, method, parameters))
+
+#endif /* EEL_GTK_MACROS_H */
diff --git a/capplets/about-me/fingerprint-strings.h b/capplets/about-me/fingerprint-strings.h
new file mode 100644
index 00000000..d1b919e9
--- /dev/null
+++ b/capplets/about-me/fingerprint-strings.h
@@ -0,0 +1,111 @@
+/*
+ * Helper functions to translate statuses and actions to strings
+ * Copyright (C) 2008 Bastien Nocera <[email protected]>
+ *
+ * Experimental code. This will be moved out of fprintd into it's own
+ * package once the system has matured.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+struct {
+ const char *dbus_name;
+ const char *place_str;
+ const char *swipe_str;
+} fingers[11] = {
+ { "left-thumb", N_("Place your left thumb on %s"), N_("Swipe your left thumb on %s") },
+ { "left-index-finger", N_("Place your left index finger on %s"), N_("Swipe your left index finger on %s") },
+ { "left-middle-finger", N_("Place your left middle finger on %s"), N_("Swipe your left middle finger on %s") },
+ { "left-ring-finger", N_("Place your left ring finger on %s"), N_("Swipe your left ring finger on %s") },
+ { "left-little-finger", N_("Place your left little finger on %s"), N_("Swipe your left little finger on %s") },
+ { "right-thumb", N_("Place your right thumb on %s"), N_("Swipe your right thumb on %s") },
+ { "right-index-finger", N_("Place your right index finger on %s"), N_("Swipe your right index finger on %s") },
+ { "right-middle-finger", N_("Place your right middle finger on %s"), N_("Swipe your right middle finger on %s") },
+ { "right-ring-finger", N_("Place your right ring finger on %s"), N_("Swipe your right ring finger on %s") },
+ { "right-little-finger", N_("Place your right little finger on %s"), N_("Swipe your right little finger on %s") },
+ { NULL, NULL, NULL }
+};
+
+static const char *finger_str_to_msg(const char *finger_name, gboolean is_swipe)
+{
+ int i;
+
+ if (finger_name == NULL)
+ return NULL;
+
+ for (i = 0; fingers[i].dbus_name != NULL; i++) {
+ if (g_str_equal (fingers[i].dbus_name, finger_name)) {
+ if (is_swipe == FALSE)
+ return fingers[i].place_str;
+ else
+ return fingers[i].swipe_str;
+ }
+ }
+
+ return NULL;
+}
+
+/* Cases not handled:
+ * verify-no-match
+ * verify-match
+ * verify-unknown-error
+ */
+static const char *verify_result_str_to_msg(const char *result, gboolean is_swipe)
+{
+ if (result == NULL)
+ return NULL;
+
+ if (strcmp (result, "verify-retry-scan") == 0) {
+ if (is_swipe == FALSE)
+ return N_("Place your finger on the reader again");
+ else
+ return N_("Swipe your finger again");
+ }
+ if (strcmp (result, "verify-swipe-too-short") == 0)
+ return N_("Swipe was too short, try again");
+ if (strcmp (result, "verify-finger-not-centered") == 0)
+ return N_("Your finger was not centered, try swiping your finger again");
+ if (strcmp (result, "verify-remove-and-retry") == 0)
+ return N_("Remove your finger, and try swiping your finger again");
+
+ return NULL;
+}
+
+/* Cases not handled:
+ * enroll-completed
+ * enroll-failed
+ * enroll-unknown-error
+ */
+static const char *enroll_result_str_to_msg(const char *result, gboolean is_swipe)
+{
+ if (result == NULL)
+ return NULL;
+
+ if (strcmp (result, "enroll-retry-scan") == 0 || strcmp (result, "enroll-stage-passed") == 0) {
+ if (is_swipe == FALSE)
+ return N_("Place your finger on the reader again");
+ else
+ return N_("Swipe your finger again");
+ }
+ if (strcmp (result, "enroll-swipe-too-short") == 0)
+ return N_("Swipe was too short, try again");
+ if (strcmp (result, "enroll-finger-not-centered") == 0)
+ return N_("Your finger was not centered, try swiping your finger again");
+ if (strcmp (result, "enroll-remove-and-retry") == 0)
+ return N_("Remove your finger, and try swiping your finger again");
+
+ return NULL;
+}
+
diff --git a/capplets/about-me/fprintd-marshal.list b/capplets/about-me/fprintd-marshal.list
new file mode 100644
index 00000000..c4effb63
--- /dev/null
+++ b/capplets/about-me/fprintd-marshal.list
@@ -0,0 +1 @@
+VOID:STRING,BOOLEAN
diff --git a/capplets/about-me/icons/Makefile.am b/capplets/about-me/icons/Makefile.am
new file mode 100644
index 00000000..a35a9e64
--- /dev/null
+++ b/capplets/about-me/icons/Makefile.am
@@ -0,0 +1,30 @@
+pixmapsdir = $(pkgdatadir)/pixmaps
+pixmaps_DATA = \
+ left-index-finger.svg \
+ left-little-finger.svg \
+ left-middle-finger.svg \
+ left-ring-finger.svg \
+ left-thumb.svg \
+ print_error.svg \
+ print_ok.svg \
+ right-index-finger.svg \
+ right-little-finger.svg \
+ right-middle-finger.svg \
+ right-ring-finger.svg \
+ right-thumb.svg \
+ left-index-finger.png \
+ left-middle-finger.png \
+ left-little-finger.png \
+ left-ring-finger.png \
+ left-thumb.png \
+ print_error.png \
+ print_ok.png \
+ right-index-finger.png \
+ right-middle-finger.png \
+ right-little-finger.png \
+ right-ring-finger.png \
+ right-thumb.png
+
+EXTRA_DIST = $(pixmaps_DATA)
+
+-include $(top_srcdir)/git.mk
diff --git a/capplets/about-me/icons/left-index-finger.png b/capplets/about-me/icons/left-index-finger.png
new file mode 100644
index 00000000..1a9cb2c7
--- /dev/null
+++ b/capplets/about-me/icons/left-index-finger.png
Binary files differ
diff --git a/capplets/about-me/icons/left-index-finger.svg b/capplets/about-me/icons/left-index-finger.svg
new file mode 100644
index 00000000..3c36aeaa
--- /dev/null
+++ b/capplets/about-me/icons/left-index-finger.svg
@@ -0,0 +1,177 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.0"
+ x="0px"
+ y="0px"
+ width="48"
+ height="48"
+ viewBox="0 0 40.425 46.214"
+ enable-background="new 0 0 40.425 46.214"
+ xml:space="preserve"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ sodipodi:docname="left-index-finger.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"><metadata
+ id="metadata44"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
+ id="defs42"><inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 23.107 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="40.424999 : 23.107 : 1"
+ inkscape:persp3d-origin="20.2125 : 15.404667 : 1"
+ id="perspective46" />
+
+
+
+
+
+
+<radialGradient
+ r="8.341651"
+ fy="9.3411446"
+ fx="38.658855"
+ cy="9.3411446"
+ cx="38.658855"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient2479"
+ xlink:href="#linearGradient2378"
+ inkscape:collect="always" /><linearGradient
+ id="linearGradient2378"><stop
+ id="stop2386"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" /><stop
+ style="stop-color:#27dc16;stop-opacity:1;"
+ offset="1"
+ id="stop2382" /></linearGradient><linearGradient
+ id="linearGradient3702"><stop
+ id="stop3704"
+ offset="0"
+ style="stop-color:black;stop-opacity:0;" /><stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0.5"
+ id="stop3710" /><stop
+ id="stop3706"
+ offset="1"
+ style="stop-color:black;stop-opacity:0;" /></linearGradient><linearGradient
+ id="linearGradient6732"><stop
+ id="stop6734"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" /><stop
+ id="stop6736"
+ offset="1"
+ style="stop-color:#dddddd;stop-opacity:1;" /></linearGradient><linearGradient
+ id="linearGradient4585"><stop
+ id="stop4587"
+ offset="0"
+ style="stop-color:#9e9e9e;stop-opacity:1;" /><stop
+ id="stop4589"
+ offset="1"
+ style="stop-color:#dddddd;stop-opacity:0;" /></linearGradient><inkscape:perspective
+ id="perspective2516"
+ inkscape:persp3d-origin="24 : 16 : 1"
+ inkscape:vp_z="48 : 24 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 24 : 1"
+ sodipodi:type="inkscape:persp3d" /><radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2378"
+ id="radialGradient86956"
+ cx="26.49"
+ cy="5.5700002"
+ fx="26.49"
+ fy="5.5700002"
+ r="4.0552225"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)" /><radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2378"
+ id="radialGradient86964"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)"
+ cx="26.49"
+ cy="5.5700002"
+ fx="26.49"
+ fy="5.5700002"
+ r="4.0552225" /><radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2378"
+ id="radialGradient86966"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)"
+ cx="26.49"
+ cy="5.5700002"
+ fx="26.49"
+ fy="5.5700002"
+ r="4.0552225" /></defs><sodipodi:namedview
+ inkscape:window-height="933"
+ inkscape:window-width="1054"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ guidetolerance="10.0"
+ gridtolerance="10.0"
+ objecttolerance="10.0"
+ borderopacity="1.0"
+ bordercolor="#666666"
+ pagecolor="#ffffff"
+ id="base"
+ showgrid="false"
+ inkscape:zoom="11.122171"
+ inkscape:cx="22.316511"
+ inkscape:cy="30.299841"
+ inkscape:window-x="36"
+ inkscape:window-y="91"
+ inkscape:current-layer="svg2" />
+<g
+ id="g35"
+ style="fill:url(#radialGradient86956);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ transform="matrix(1.1605241,0,0,1.3370602,-4.3871473,-0.7984997)">
+ <circle
+ style="fill:url(#radialGradient86964);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ sodipodi:ry="3.829"
+ sodipodi:rx="3.829"
+ sodipodi:cy="5.5700002"
+ sodipodi:cx="26.49"
+ id="circle37"
+ r="3.829"
+ cy="5.5700002"
+ cx="26.49"
+ stroke-miterlimit="3.8637" />
+ <path
+ style="fill:url(#radialGradient86966);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path39"
+ stroke-miterlimit="3.8637"
+ d="" />
+ </g><g
+ id="Background">
+</g>
+<g
+ id="Guides"
+ display="none"
+ style="display:none">
+</g>
+<g
+ id="g7"
+ style="fill:#2f2f2f;fill-opacity:1">
+ <path
+ style="fill:#2f2f2f;fill-opacity:1;fill-rule:evenodd"
+ id="path9"
+ d="M 20.569,13.286 C 20.843,15.459 20.791,17.834 20.82,18.542 C 20.865,18.917 21.913,19.241 22.094,18.877 C 22.301,17.514 22.586,14.847 22.92,13.455 C 23.372,9.917 23.886,8.247 24.072,7.257 C 24.58,4.567 25.014,3.12 26.762,3.12 C 28.384,3.12 28.623,5.167 28.153,8.165 C 28.025,9.379 28.036,12.24 27.433,14.894 C 27.165,16.691 26.962,21.278 27.139,24.981 C 27.189,26.045 27.669,27.315 28.242,27.945 C 29.462,27.773 30.379,24.377 31.988,22.847 C 32.809,21.464 34.883,19.299 36.951,19.299 C 39.243,19.299 39.292,21 38.345,22.262 C 37.187,23.806 36.525,24.528 36.079,25.802 C 35.633,27.076 33.758,29.778 33.471,31.209 C 32.902,34.054 32.471,35.105 29.284,37.661 C 27.783,38.865 27.302,39.637 26.855,40.401 C 26.347,41.273 26.409,44.721 26.409,46.212 L 10.64,46.212 C 10.64,46.212 10.767,43.587 10.513,42.058 C 10.461,41.746 10.105,39.613 9.176,38.231 C 8.317,36.954 5.902,32.306 5.902,26.836 C 5.902,24.026 4.39,21.718 3.854,19.533 C 3.591,17.833 2.638,15.423 2.57,14.709 C 1.684,11.559 2.132,10.118 3.741,10.118 C 5.132,10.118 5.528,11.927 6.093,13.622 C 6.258,14.52 7.505,16.934 7.788,18.233 C 8.038,19.088 8.897,21.556 9.437,21.727 C 9.75,21.784 10.151,21.523 10.291,21.043 C 10.52,20.26 9.818,18.945 9.539,15.26 C 9.087,12.343 9.17,10.139 9.116,8.949 C 8.653,5.424 9.133,3.598 10.693,3.598 C 12.176,3.598 12.568,4.455 13.02,7.936 C 13.189,9.518 13.754,12.095 14.037,14.864 C 14.213,16.364 14.639,18.601 14.98,19.17 C 15.285,19.503 15.919,19.198 15.9,18.848 C 15.894,16.377 15.732,14.977 15.958,12.999 C 15.845,10.287 16.219,7.823 16.219,6.467 C 16.219,3.494 16.502,1.473 18.358,1.473 C 20.333,1.473 20.287,3.776 20.287,6.806 C 20.399,7.545 20.456,10.087 20.569,13.286 z"
+ clip-rule="evenodd" />
+ </g>
+<g
+ style="display:inline"
+ inkscape:label="Base"
+ id="layer1"
+ transform="translate(-52.466647,2.6102791)" /></svg> \ No newline at end of file
diff --git a/capplets/about-me/icons/left-little-finger.png b/capplets/about-me/icons/left-little-finger.png
new file mode 100644
index 00000000..978942ee
--- /dev/null
+++ b/capplets/about-me/icons/left-little-finger.png
Binary files differ
diff --git a/capplets/about-me/icons/left-little-finger.svg b/capplets/about-me/icons/left-little-finger.svg
new file mode 100644
index 00000000..0835854f
--- /dev/null
+++ b/capplets/about-me/icons/left-little-finger.svg
@@ -0,0 +1,180 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.0"
+ x="0px"
+ y="0px"
+ width="48"
+ height="48"
+ viewBox="0 0 40.425 46.214"
+ enable-background="new 0 0 40.425 46.214"
+ xml:space="preserve"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ sodipodi:docname="left-pinky-finger.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ inkscape:export-filename="/Users/mlanglie/Desktop/Fingerprint Enrollment Icons/Vector/left-ring-finger.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"><metadata
+ id="metadata44"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
+ id="defs42"><inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 23.107 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="40.424999 : 23.107 : 1"
+ inkscape:persp3d-origin="20.2125 : 15.404667 : 1"
+ id="perspective46" />
+
+
+
+
+
+
+<radialGradient
+ r="8.341651"
+ fy="9.3411446"
+ fx="38.658855"
+ cy="9.3411446"
+ cx="38.658855"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient2479"
+ xlink:href="#linearGradient2378"
+ inkscape:collect="always" /><linearGradient
+ id="linearGradient2378"><stop
+ id="stop2386"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" /><stop
+ style="stop-color:#27dc16;stop-opacity:1;"
+ offset="1"
+ id="stop2382" /></linearGradient><linearGradient
+ id="linearGradient3702"><stop
+ id="stop3704"
+ offset="0"
+ style="stop-color:black;stop-opacity:0;" /><stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0.5"
+ id="stop3710" /><stop
+ id="stop3706"
+ offset="1"
+ style="stop-color:black;stop-opacity:0;" /></linearGradient><linearGradient
+ id="linearGradient6732"><stop
+ id="stop6734"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" /><stop
+ id="stop6736"
+ offset="1"
+ style="stop-color:#dddddd;stop-opacity:1;" /></linearGradient><linearGradient
+ id="linearGradient4585"><stop
+ id="stop4587"
+ offset="0"
+ style="stop-color:#9e9e9e;stop-opacity:1;" /><stop
+ id="stop4589"
+ offset="1"
+ style="stop-color:#dddddd;stop-opacity:0;" /></linearGradient><inkscape:perspective
+ id="perspective2516"
+ inkscape:persp3d-origin="24 : 16 : 1"
+ inkscape:vp_z="48 : 24 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 24 : 1"
+ sodipodi:type="inkscape:persp3d" /><radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2378"
+ id="radialGradient86956"
+ cx="26.49"
+ cy="5.5700002"
+ fx="26.49"
+ fy="5.5700002"
+ r="4.0552225"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)" /><radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2378"
+ id="radialGradient86964"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)"
+ cx="26.49"
+ cy="5.5700002"
+ fx="26.49"
+ fy="5.5700002"
+ r="4.0552225" /><radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2378"
+ id="radialGradient86966"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)"
+ cx="26.49"
+ cy="5.5700002"
+ fx="26.49"
+ fy="5.5700002"
+ r="4.0552225" /></defs><sodipodi:namedview
+ inkscape:window-height="933"
+ inkscape:window-width="1054"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ guidetolerance="10.0"
+ gridtolerance="10.0"
+ objecttolerance="10.0"
+ borderopacity="1.0"
+ bordercolor="#666666"
+ pagecolor="#ffffff"
+ id="base"
+ showgrid="false"
+ inkscape:zoom="11.122171"
+ inkscape:cx="22.316511"
+ inkscape:cy="30.299841"
+ inkscape:window-x="122"
+ inkscape:window-y="443"
+ inkscape:current-layer="svg2" />
+<g
+ id="g35"
+ style="fill:url(#radialGradient86956);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ transform="matrix(1.1074589,0,0,1.2726911,-25.531655,5.5330271)">
+ <circle
+ style="fill:url(#radialGradient86964);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ sodipodi:ry="3.829"
+ sodipodi:rx="3.829"
+ sodipodi:cy="5.5700002"
+ sodipodi:cx="26.49"
+ id="circle37"
+ r="3.829"
+ cy="5.5700002"
+ cx="26.49"
+ stroke-miterlimit="3.8637" />
+ <path
+ style="fill:url(#radialGradient86966);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path39"
+ stroke-miterlimit="3.8637"
+ d="" />
+ </g><g
+ id="Background">
+</g>
+<g
+ id="Guides"
+ display="none"
+ style="display:none">
+</g>
+<g
+ id="g7"
+ style="fill:#2f2f2f;fill-opacity:1">
+ <path
+ style="fill:#2f2f2f;fill-opacity:1;fill-rule:evenodd"
+ id="path9"
+ d="M 20.569,13.286 C 20.843,15.459 20.791,17.834 20.82,18.542 C 20.865,18.917 21.913,19.241 22.094,18.877 C 22.301,17.514 22.586,14.847 22.92,13.455 C 23.372,9.917 23.886,8.247 24.072,7.257 C 24.58,4.567 25.014,3.12 26.762,3.12 C 28.384,3.12 28.623,5.167 28.153,8.165 C 28.025,9.379 28.036,12.24 27.433,14.894 C 27.165,16.691 26.962,21.278 27.139,24.981 C 27.189,26.045 27.669,27.315 28.242,27.945 C 29.462,27.773 30.379,24.377 31.988,22.847 C 32.809,21.464 34.883,19.299 36.951,19.299 C 39.243,19.299 39.292,21 38.345,22.262 C 37.187,23.806 36.525,24.528 36.079,25.802 C 35.633,27.076 33.758,29.778 33.471,31.209 C 32.902,34.054 32.471,35.105 29.284,37.661 C 27.783,38.865 27.302,39.637 26.855,40.401 C 26.347,41.273 26.409,44.721 26.409,46.212 L 10.64,46.212 C 10.64,46.212 10.767,43.587 10.513,42.058 C 10.461,41.746 10.105,39.613 9.176,38.231 C 8.317,36.954 5.902,32.306 5.902,26.836 C 5.902,24.026 4.39,21.718 3.854,19.533 C 3.591,17.833 2.638,15.423 2.57,14.709 C 1.684,11.559 2.132,10.118 3.741,10.118 C 5.132,10.118 5.528,11.927 6.093,13.622 C 6.258,14.52 7.505,16.934 7.788,18.233 C 8.038,19.088 8.897,21.556 9.437,21.727 C 9.75,21.784 10.151,21.523 10.291,21.043 C 10.52,20.26 9.818,18.945 9.539,15.26 C 9.087,12.343 9.17,10.139 9.116,8.949 C 8.653,5.424 9.133,3.598 10.693,3.598 C 12.176,3.598 12.568,4.455 13.02,7.936 C 13.189,9.518 13.754,12.095 14.037,14.864 C 14.213,16.364 14.639,18.601 14.98,19.17 C 15.285,19.503 15.919,19.198 15.9,18.848 C 15.894,16.377 15.732,14.977 15.958,12.999 C 15.845,10.287 16.219,7.823 16.219,6.467 C 16.219,3.494 16.502,1.473 18.358,1.473 C 20.333,1.473 20.287,3.776 20.287,6.806 C 20.399,7.545 20.456,10.087 20.569,13.286 z"
+ clip-rule="evenodd" />
+ </g>
+<g
+ style="display:inline"
+ inkscape:label="Base"
+ id="layer1"
+ transform="translate(-52.466647,2.6102791)" /></svg> \ No newline at end of file
diff --git a/capplets/about-me/icons/left-middle-finger.png b/capplets/about-me/icons/left-middle-finger.png
new file mode 100644
index 00000000..406925e9
--- /dev/null
+++ b/capplets/about-me/icons/left-middle-finger.png
Binary files differ
diff --git a/capplets/about-me/icons/left-middle-finger.svg b/capplets/about-me/icons/left-middle-finger.svg
new file mode 100644
index 00000000..1082da2e
--- /dev/null
+++ b/capplets/about-me/icons/left-middle-finger.svg
@@ -0,0 +1,180 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.0"
+ x="0px"
+ y="0px"
+ width="48"
+ height="48"
+ viewBox="0 0 40.425 46.214"
+ enable-background="new 0 0 40.425 46.214"
+ xml:space="preserve"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ sodipodi:docname="left-middle-finger.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ inkscape:export-filename="/Users/mlanglie/Desktop/Fingerprint Enrollment Icons/Vector/left-index-finger.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"><metadata
+ id="metadata44"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
+ id="defs42"><inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 23.107 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="40.424999 : 23.107 : 1"
+ inkscape:persp3d-origin="20.2125 : 15.404667 : 1"
+ id="perspective46" />
+
+
+
+
+
+
+<radialGradient
+ r="8.341651"
+ fy="9.3411446"
+ fx="38.658855"
+ cy="9.3411446"
+ cx="38.658855"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient2479"
+ xlink:href="#linearGradient2378"
+ inkscape:collect="always" /><linearGradient
+ id="linearGradient2378"><stop
+ id="stop2386"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" /><stop
+ style="stop-color:#27dc16;stop-opacity:1;"
+ offset="1"
+ id="stop2382" /></linearGradient><linearGradient
+ id="linearGradient3702"><stop
+ id="stop3704"
+ offset="0"
+ style="stop-color:black;stop-opacity:0;" /><stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0.5"
+ id="stop3710" /><stop
+ id="stop3706"
+ offset="1"
+ style="stop-color:black;stop-opacity:0;" /></linearGradient><linearGradient
+ id="linearGradient6732"><stop
+ id="stop6734"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" /><stop
+ id="stop6736"
+ offset="1"
+ style="stop-color:#dddddd;stop-opacity:1;" /></linearGradient><linearGradient
+ id="linearGradient4585"><stop
+ id="stop4587"
+ offset="0"
+ style="stop-color:#9e9e9e;stop-opacity:1;" /><stop
+ id="stop4589"
+ offset="1"
+ style="stop-color:#dddddd;stop-opacity:0;" /></linearGradient><inkscape:perspective
+ id="perspective2516"
+ inkscape:persp3d-origin="24 : 16 : 1"
+ inkscape:vp_z="48 : 24 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 24 : 1"
+ sodipodi:type="inkscape:persp3d" /><radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2378"
+ id="radialGradient86956"
+ cx="26.49"
+ cy="5.5700002"
+ fx="26.49"
+ fy="5.5700002"
+ r="4.0552225"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)" /><radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2378"
+ id="radialGradient86964"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)"
+ cx="26.49"
+ cy="5.5700002"
+ fx="26.49"
+ fy="5.5700002"
+ r="4.0552225" /><radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2378"
+ id="radialGradient86966"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)"
+ cx="26.49"
+ cy="5.5700002"
+ fx="26.49"
+ fy="5.5700002"
+ r="4.0552225" /></defs><sodipodi:namedview
+ inkscape:window-height="933"
+ inkscape:window-width="1054"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ guidetolerance="10.0"
+ gridtolerance="10.0"
+ objecttolerance="10.0"
+ borderopacity="1.0"
+ bordercolor="#666666"
+ pagecolor="#ffffff"
+ id="base"
+ showgrid="false"
+ inkscape:zoom="11.122171"
+ inkscape:cx="22.316511"
+ inkscape:cy="30.299841"
+ inkscape:window-x="122"
+ inkscape:window-y="443"
+ inkscape:current-layer="svg2" />
+<g
+ id="g35"
+ style="fill:url(#radialGradient86956);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ transform="matrix(1.1824583,0,0,1.3363867,-12.845608,-2.0066594)">
+ <circle
+ style="fill:url(#radialGradient86964);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ sodipodi:ry="3.829"
+ sodipodi:rx="3.829"
+ sodipodi:cy="5.5700002"
+ sodipodi:cx="26.49"
+ id="circle37"
+ r="3.829"
+ cy="5.5700002"
+ cx="26.49"
+ stroke-miterlimit="3.8637" />
+ <path
+ style="fill:url(#radialGradient86966);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path39"
+ stroke-miterlimit="3.8637"
+ d="" />
+ </g><g
+ id="Background">
+</g>
+<g
+ id="Guides"
+ display="none"
+ style="display:none">
+</g>
+<g
+ id="g7"
+ style="fill:#2f2f2f;fill-opacity:1">
+ <path
+ style="fill:#2f2f2f;fill-opacity:1;fill-rule:evenodd"
+ id="path9"
+ d="M 20.569,13.286 C 20.843,15.459 20.791,17.834 20.82,18.542 C 20.865,18.917 21.913,19.241 22.094,18.877 C 22.301,17.514 22.586,14.847 22.92,13.455 C 23.372,9.917 23.886,8.247 24.072,7.257 C 24.58,4.567 25.014,3.12 26.762,3.12 C 28.384,3.12 28.623,5.167 28.153,8.165 C 28.025,9.379 28.036,12.24 27.433,14.894 C 27.165,16.691 26.962,21.278 27.139,24.981 C 27.189,26.045 27.669,27.315 28.242,27.945 C 29.462,27.773 30.379,24.377 31.988,22.847 C 32.809,21.464 34.883,19.299 36.951,19.299 C 39.243,19.299 39.292,21 38.345,22.262 C 37.187,23.806 36.525,24.528 36.079,25.802 C 35.633,27.076 33.758,29.778 33.471,31.209 C 32.902,34.054 32.471,35.105 29.284,37.661 C 27.783,38.865 27.302,39.637 26.855,40.401 C 26.347,41.273 26.409,44.721 26.409,46.212 L 10.64,46.212 C 10.64,46.212 10.767,43.587 10.513,42.058 C 10.461,41.746 10.105,39.613 9.176,38.231 C 8.317,36.954 5.902,32.306 5.902,26.836 C 5.902,24.026 4.39,21.718 3.854,19.533 C 3.591,17.833 2.638,15.423 2.57,14.709 C 1.684,11.559 2.132,10.118 3.741,10.118 C 5.132,10.118 5.528,11.927 6.093,13.622 C 6.258,14.52 7.505,16.934 7.788,18.233 C 8.038,19.088 8.897,21.556 9.437,21.727 C 9.75,21.784 10.151,21.523 10.291,21.043 C 10.52,20.26 9.818,18.945 9.539,15.26 C 9.087,12.343 9.17,10.139 9.116,8.949 C 8.653,5.424 9.133,3.598 10.693,3.598 C 12.176,3.598 12.568,4.455 13.02,7.936 C 13.189,9.518 13.754,12.095 14.037,14.864 C 14.213,16.364 14.639,18.601 14.98,19.17 C 15.285,19.503 15.919,19.198 15.9,18.848 C 15.894,16.377 15.732,14.977 15.958,12.999 C 15.845,10.287 16.219,7.823 16.219,6.467 C 16.219,3.494 16.502,1.473 18.358,1.473 C 20.333,1.473 20.287,3.776 20.287,6.806 C 20.399,7.545 20.456,10.087 20.569,13.286 z"
+ clip-rule="evenodd" />
+ </g>
+<g
+ style="display:inline"
+ inkscape:label="Base"
+ id="layer1"
+ transform="translate(-52.466647,2.6102791)" /></svg> \ No newline at end of file
diff --git a/capplets/about-me/icons/left-ring-finger.png b/capplets/about-me/icons/left-ring-finger.png
new file mode 100644
index 00000000..169ff687
--- /dev/null
+++ b/capplets/about-me/icons/left-ring-finger.png
Binary files differ
diff --git a/capplets/about-me/icons/left-ring-finger.svg b/capplets/about-me/icons/left-ring-finger.svg
new file mode 100644
index 00000000..50ace807
--- /dev/null
+++ b/capplets/about-me/icons/left-ring-finger.svg
@@ -0,0 +1,180 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.0"
+ x="0px"
+ y="0px"
+ width="48"
+ height="48"
+ viewBox="0 0 40.425 46.214"
+ enable-background="new 0 0 40.425 46.214"
+ xml:space="preserve"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ sodipodi:docname="left-ring-finger.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ inkscape:export-filename="/Users/mlanglie/Desktop/Fingerprint Enrollment Icons/Vector/left-middle-finger.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"><metadata
+ id="metadata44"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
+ id="defs42"><inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 23.107 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="40.424999 : 23.107 : 1"
+ inkscape:persp3d-origin="20.2125 : 15.404667 : 1"
+ id="perspective46" />
+
+
+
+
+
+
+<radialGradient
+ r="8.341651"
+ fy="9.3411446"
+ fx="38.658855"
+ cy="9.3411446"
+ cx="38.658855"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient2479"
+ xlink:href="#linearGradient2378"
+ inkscape:collect="always" /><linearGradient
+ id="linearGradient2378"><stop
+ id="stop2386"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" /><stop
+ style="stop-color:#27dc16;stop-opacity:1;"
+ offset="1"
+ id="stop2382" /></linearGradient><linearGradient
+ id="linearGradient3702"><stop
+ id="stop3704"
+ offset="0"
+ style="stop-color:black;stop-opacity:0;" /><stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0.5"
+ id="stop3710" /><stop
+ id="stop3706"
+ offset="1"
+ style="stop-color:black;stop-opacity:0;" /></linearGradient><linearGradient
+ id="linearGradient6732"><stop
+ id="stop6734"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" /><stop
+ id="stop6736"
+ offset="1"
+ style="stop-color:#dddddd;stop-opacity:1;" /></linearGradient><linearGradient
+ id="linearGradient4585"><stop
+ id="stop4587"
+ offset="0"
+ style="stop-color:#9e9e9e;stop-opacity:1;" /><stop
+ id="stop4589"
+ offset="1"
+ style="stop-color:#dddddd;stop-opacity:0;" /></linearGradient><inkscape:perspective
+ id="perspective2516"
+ inkscape:persp3d-origin="24 : 16 : 1"
+ inkscape:vp_z="48 : 24 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 24 : 1"
+ sodipodi:type="inkscape:persp3d" /><radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2378"
+ id="radialGradient86956"
+ cx="26.49"
+ cy="5.5700002"
+ fx="26.49"
+ fy="5.5700002"
+ r="4.0552225"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)" /><radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2378"
+ id="radialGradient86964"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)"
+ cx="26.49"
+ cy="5.5700002"
+ fx="26.49"
+ fy="5.5700002"
+ r="4.0552225" /><radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2378"
+ id="radialGradient86966"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)"
+ cx="26.49"
+ cy="5.5700002"
+ fx="26.49"
+ fy="5.5700002"
+ r="4.0552225" /></defs><sodipodi:namedview
+ inkscape:window-height="933"
+ inkscape:window-width="1054"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ guidetolerance="10.0"
+ gridtolerance="10.0"
+ objecttolerance="10.0"
+ borderopacity="1.0"
+ bordercolor="#666666"
+ pagecolor="#ffffff"
+ id="base"
+ showgrid="false"
+ inkscape:zoom="11.122171"
+ inkscape:cx="22.316511"
+ inkscape:cy="30.299841"
+ inkscape:window-x="122"
+ inkscape:window-y="443"
+ inkscape:current-layer="svg2" />
+<g
+ id="g35"
+ style="fill:url(#radialGradient86956);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ transform="matrix(1.1824583,0,0,1.3363867,-20.636466,-0.7947482)">
+ <circle
+ style="fill:url(#radialGradient86964);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ sodipodi:ry="3.829"
+ sodipodi:rx="3.829"
+ sodipodi:cy="5.5700002"
+ sodipodi:cx="26.49"
+ id="circle37"
+ r="3.829"
+ cy="5.5700002"
+ cx="26.49"
+ stroke-miterlimit="3.8637" />
+ <path
+ style="fill:url(#radialGradient86966);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path39"
+ stroke-miterlimit="3.8637"
+ d="" />
+ </g><g
+ id="Background">
+</g>
+<g
+ id="Guides"
+ display="none"
+ style="display:none">
+</g>
+<g
+ id="g7"
+ style="fill:#2f2f2f;fill-opacity:1">
+ <path
+ style="fill:#2f2f2f;fill-opacity:1;fill-rule:evenodd"
+ id="path9"
+ d="M 20.569,13.286 C 20.843,15.459 20.791,17.834 20.82,18.542 C 20.865,18.917 21.913,19.241 22.094,18.877 C 22.301,17.514 22.586,14.847 22.92,13.455 C 23.372,9.917 23.886,8.247 24.072,7.257 C 24.58,4.567 25.014,3.12 26.762,3.12 C 28.384,3.12 28.623,5.167 28.153,8.165 C 28.025,9.379 28.036,12.24 27.433,14.894 C 27.165,16.691 26.962,21.278 27.139,24.981 C 27.189,26.045 27.669,27.315 28.242,27.945 C 29.462,27.773 30.379,24.377 31.988,22.847 C 32.809,21.464 34.883,19.299 36.951,19.299 C 39.243,19.299 39.292,21 38.345,22.262 C 37.187,23.806 36.525,24.528 36.079,25.802 C 35.633,27.076 33.758,29.778 33.471,31.209 C 32.902,34.054 32.471,35.105 29.284,37.661 C 27.783,38.865 27.302,39.637 26.855,40.401 C 26.347,41.273 26.409,44.721 26.409,46.212 L 10.64,46.212 C 10.64,46.212 10.767,43.587 10.513,42.058 C 10.461,41.746 10.105,39.613 9.176,38.231 C 8.317,36.954 5.902,32.306 5.902,26.836 C 5.902,24.026 4.39,21.718 3.854,19.533 C 3.591,17.833 2.638,15.423 2.57,14.709 C 1.684,11.559 2.132,10.118 3.741,10.118 C 5.132,10.118 5.528,11.927 6.093,13.622 C 6.258,14.52 7.505,16.934 7.788,18.233 C 8.038,19.088 8.897,21.556 9.437,21.727 C 9.75,21.784 10.151,21.523 10.291,21.043 C 10.52,20.26 9.818,18.945 9.539,15.26 C 9.087,12.343 9.17,10.139 9.116,8.949 C 8.653,5.424 9.133,3.598 10.693,3.598 C 12.176,3.598 12.568,4.455 13.02,7.936 C 13.189,9.518 13.754,12.095 14.037,14.864 C 14.213,16.364 14.639,18.601 14.98,19.17 C 15.285,19.503 15.919,19.198 15.9,18.848 C 15.894,16.377 15.732,14.977 15.958,12.999 C 15.845,10.287 16.219,7.823 16.219,6.467 C 16.219,3.494 16.502,1.473 18.358,1.473 C 20.333,1.473 20.287,3.776 20.287,6.806 C 20.399,7.545 20.456,10.087 20.569,13.286 z"
+ clip-rule="evenodd" />
+ </g>
+<g
+ style="display:inline"
+ inkscape:label="Base"
+ id="layer1"
+ transform="translate(-52.466647,2.6102791)" /></svg> \ No newline at end of file
diff --git a/capplets/about-me/icons/left-thumb.png b/capplets/about-me/icons/left-thumb.png
new file mode 100644
index 00000000..eaf875d0
--- /dev/null
+++ b/capplets/about-me/icons/left-thumb.png
Binary files differ
diff --git a/capplets/about-me/icons/left-thumb.svg b/capplets/about-me/icons/left-thumb.svg
new file mode 100644
index 00000000..fd0f5827
--- /dev/null
+++ b/capplets/about-me/icons/left-thumb.svg
@@ -0,0 +1,180 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.0"
+ x="0px"
+ y="0px"
+ width="48"
+ height="48"
+ viewBox="0 0 40.425 46.214"
+ enable-background="new 0 0 40.425 46.214"
+ xml:space="preserve"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ sodipodi:docname="left-thumb.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ inkscape:export-filename="/Users/mlanglie/Desktop/Fingerprint Enrollment Icons/Vector/left-pinky-finger.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"><metadata
+ id="metadata44"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
+ id="defs42"><inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 23.107 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="40.424999 : 23.107 : 1"
+ inkscape:persp3d-origin="20.2125 : 15.404667 : 1"
+ id="perspective46" />
+
+
+
+
+
+
+<radialGradient
+ r="8.341651"
+ fy="9.3411446"
+ fx="38.658855"
+ cy="9.3411446"
+ cx="38.658855"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient2479"
+ xlink:href="#linearGradient2378"
+ inkscape:collect="always" /><linearGradient
+ id="linearGradient2378"><stop
+ id="stop2386"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" /><stop
+ style="stop-color:#27dc16;stop-opacity:1;"
+ offset="1"
+ id="stop2382" /></linearGradient><linearGradient
+ id="linearGradient3702"><stop
+ id="stop3704"
+ offset="0"
+ style="stop-color:black;stop-opacity:0;" /><stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0.5"
+ id="stop3710" /><stop
+ id="stop3706"
+ offset="1"
+ style="stop-color:black;stop-opacity:0;" /></linearGradient><linearGradient
+ id="linearGradient6732"><stop
+ id="stop6734"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" /><stop
+ id="stop6736"
+ offset="1"
+ style="stop-color:#dddddd;stop-opacity:1;" /></linearGradient><linearGradient
+ id="linearGradient4585"><stop
+ id="stop4587"
+ offset="0"
+ style="stop-color:#9e9e9e;stop-opacity:1;" /><stop
+ id="stop4589"
+ offset="1"
+ style="stop-color:#dddddd;stop-opacity:0;" /></linearGradient><inkscape:perspective
+ id="perspective2516"
+ inkscape:persp3d-origin="24 : 16 : 1"
+ inkscape:vp_z="48 : 24 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 24 : 1"
+ sodipodi:type="inkscape:persp3d" /><radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2378"
+ id="radialGradient86956"
+ cx="26.49"
+ cy="5.5700002"
+ fx="26.49"
+ fy="5.5700002"
+ r="4.0552225"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)" /><radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2378"
+ id="radialGradient86964"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)"
+ cx="26.49"
+ cy="5.5700002"
+ fx="26.49"
+ fy="5.5700002"
+ r="4.0552225" /><radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2378"
+ id="radialGradient86966"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)"
+ cx="26.49"
+ cy="5.5700002"
+ fx="26.49"
+ fy="5.5700002"
+ r="4.0552225" /></defs><sodipodi:namedview
+ inkscape:window-height="933"
+ inkscape:window-width="1054"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ guidetolerance="10.0"
+ gridtolerance="10.0"
+ objecttolerance="10.0"
+ borderopacity="1.0"
+ bordercolor="#666666"
+ pagecolor="#ffffff"
+ id="base"
+ showgrid="false"
+ inkscape:zoom="11.122171"
+ inkscape:cx="22.316511"
+ inkscape:cy="30.299841"
+ inkscape:window-x="116"
+ inkscape:window-y="498"
+ inkscape:current-layer="svg2" />
+<g
+ id="g35"
+ style="fill:url(#radialGradient86956);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ transform="matrix(1.1916623,0,0,1.4021101,4.5265732,14.334323)">
+ <circle
+ style="fill:url(#radialGradient86964);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ sodipodi:ry="3.829"
+ sodipodi:rx="3.829"
+ sodipodi:cy="5.5700002"
+ sodipodi:cx="26.49"
+ id="circle37"
+ r="3.829"
+ cy="5.5700002"
+ cx="26.49"
+ stroke-miterlimit="3.8637" />
+ <path
+ style="fill:url(#radialGradient86966);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path39"
+ stroke-miterlimit="3.8637"
+ d="" />
+ </g><g
+ id="Background">
+</g>
+<g
+ id="Guides"
+ display="none"
+ style="display:none">
+</g>
+<g
+ id="g7"
+ style="fill:#2f2f2f;fill-opacity:1">
+ <path
+ style="fill:#2f2f2f;fill-opacity:1;fill-rule:evenodd"
+ id="path9"
+ d="M 20.569,13.286 C 20.843,15.459 20.791,17.834 20.82,18.542 C 20.865,18.917 21.913,19.241 22.094,18.877 C 22.301,17.514 22.586,14.847 22.92,13.455 C 23.372,9.917 23.886,8.247 24.072,7.257 C 24.58,4.567 25.014,3.12 26.762,3.12 C 28.384,3.12 28.623,5.167 28.153,8.165 C 28.025,9.379 28.036,12.24 27.433,14.894 C 27.165,16.691 26.962,21.278 27.139,24.981 C 27.189,26.045 27.669,27.315 28.242,27.945 C 29.462,27.773 30.379,24.377 31.988,22.847 C 32.809,21.464 34.883,19.299 36.951,19.299 C 39.243,19.299 39.292,21 38.345,22.262 C 37.187,23.806 36.525,24.528 36.079,25.802 C 35.633,27.076 33.758,29.778 33.471,31.209 C 32.902,34.054 32.471,35.105 29.284,37.661 C 27.783,38.865 27.302,39.637 26.855,40.401 C 26.347,41.273 26.409,44.721 26.409,46.212 L 10.64,46.212 C 10.64,46.212 10.767,43.587 10.513,42.058 C 10.461,41.746 10.105,39.613 9.176,38.231 C 8.317,36.954 5.902,32.306 5.902,26.836 C 5.902,24.026 4.39,21.718 3.854,19.533 C 3.591,17.833 2.638,15.423 2.57,14.709 C 1.684,11.559 2.132,10.118 3.741,10.118 C 5.132,10.118 5.528,11.927 6.093,13.622 C 6.258,14.52 7.505,16.934 7.788,18.233 C 8.038,19.088 8.897,21.556 9.437,21.727 C 9.75,21.784 10.151,21.523 10.291,21.043 C 10.52,20.26 9.818,18.945 9.539,15.26 C 9.087,12.343 9.17,10.139 9.116,8.949 C 8.653,5.424 9.133,3.598 10.693,3.598 C 12.176,3.598 12.568,4.455 13.02,7.936 C 13.189,9.518 13.754,12.095 14.037,14.864 C 14.213,16.364 14.639,18.601 14.98,19.17 C 15.285,19.503 15.919,19.198 15.9,18.848 C 15.894,16.377 15.732,14.977 15.958,12.999 C 15.845,10.287 16.219,7.823 16.219,6.467 C 16.219,3.494 16.502,1.473 18.358,1.473 C 20.333,1.473 20.287,3.776 20.287,6.806 C 20.399,7.545 20.456,10.087 20.569,13.286 z"
+ clip-rule="evenodd" />
+ </g>
+<g
+ style="display:inline"
+ inkscape:label="Base"
+ id="layer1"
+ transform="translate(-52.466647,2.6102791)" /></svg> \ No newline at end of file
diff --git a/capplets/about-me/icons/print_error.png b/capplets/about-me/icons/print_error.png
new file mode 100644
index 00000000..d67150b1
--- /dev/null
+++ b/capplets/about-me/icons/print_error.png
Binary files differ
diff --git a/capplets/about-me/icons/print_error.svg b/capplets/about-me/icons/print_error.svg
new file mode 100644
index 00000000..4ad6beed
--- /dev/null
+++ b/capplets/about-me/icons/print_error.svg
@@ -0,0 +1,525 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.0"
+ x="0px"
+ y="0px"
+ width="48"
+ height="48"
+ viewBox="0 0 36.184 43.865"
+ enable-background="new 0 0 36.184 43.865"
+ xml:space="preserve"
+ id="svg2419"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ sodipodi:docname="print_error.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ inkscape:export-filename="/Users/mlanglie/Desktop/print_error.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"><metadata
+ id="metadata2435"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
+ id="defs2433"><linearGradient
+ inkscape:collect="always"
+ id="linearGradient84104"><stop
+ style="stop-color:#fffffc;stop-opacity:1;"
+ offset="0"
+ id="stop84106" /><stop
+ style="stop-color:#fffffc;stop-opacity:0;"
+ offset="1"
+ id="stop84108" /></linearGradient><linearGradient
+ id="linearGradient84076"><stop
+ style="stop-color:#73d216;stop-opacity:1;"
+ offset="0"
+ id="stop84078" /><stop
+ id="stop84090"
+ offset="0.31459025"
+ style="stop-color:#73d216;stop-opacity:1;" /><stop
+ style="stop-color:#4e9a06;stop-opacity:1;"
+ offset="1"
+ id="stop84080" /></linearGradient><linearGradient
+ id="linearGradient3531"><stop
+ id="stop3533"
+ offset="0"
+ style="stop-color:#9b9b9b;stop-opacity:1;" /><stop
+ id="stop3535"
+ offset="1"
+ style="stop-color:#414141;stop-opacity:1;" /></linearGradient><linearGradient
+ id="linearGradient3483"><stop
+ id="stop3485"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" /><stop
+ id="stop3487"
+ offset="1"
+ style="stop-color:#787878;stop-opacity:1" /></linearGradient><linearGradient
+ id="linearGradient3263"><stop
+ id="stop3265"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" /><stop
+ id="stop3267"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:0;" /></linearGradient><linearGradient
+ id="linearGradient3247"><stop
+ style="stop-color:#52a714;stop-opacity:1;"
+ offset="0"
+ id="stop3249" /><stop
+ style="stop-color:#398800;stop-opacity:1;"
+ offset="1"
+ id="stop3251" /></linearGradient><linearGradient
+ id="linearGradient3233"><stop
+ id="stop3235"
+ offset="0"
+ style="stop-color:#398800;stop-opacity:1;" /><stop
+ id="stop3237"
+ offset="1"
+ style="stop-color:#84c706;stop-opacity:1;" /></linearGradient><inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 21.932501 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="36.183998 : 21.932501 : 1"
+ inkscape:persp3d-origin="18.091999 : 14.621667 : 1"
+ id="perspective2437" />
+
+
+
+
+
+ <filter
+ inkscape:collect="always"
+ id="filter3471"><feGaussianBlur
+ inkscape:collect="always"
+ stdDeviation="0.057808254"
+ id="feGaussianBlur3473" /></filter><linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3233"
+ id="linearGradient3517"
+ gradientUnits="userSpaceOnUse"
+ x1="25.144751"
+ y1="43.865002"
+ x2="25.144751"
+ y2="23.838018" /><linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3247"
+ id="linearGradient3519"
+ gradientUnits="userSpaceOnUse"
+ x1="30.691881"
+ y1="23.365002"
+ x2="30.691881"
+ y2="44.365963" /><linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3263"
+ id="linearGradient3521"
+ gradientUnits="userSpaceOnUse"
+ x1="26.455547"
+ y1="24.322035"
+ x2="26.455547"
+ y2="30.466549" /><linearGradient
+ gradientUnits="userSpaceOnUse"
+ y2="55.692348"
+ x2="18.072493"
+ y1="29.205048"
+ x1="21.55229"
+ id="linearGradient5138"
+ xlink:href="#linearGradient5132"
+ inkscape:collect="always" /><linearGradient
+ id="linearGradient5132"
+ inkscape:collect="always"><stop
+ id="stop5134"
+ offset="0"
+ style="stop-color:white;stop-opacity:1;" /><stop
+ id="stop5136"
+ offset="1"
+ style="stop-color:white;stop-opacity:0;" /></linearGradient><linearGradient
+ id="linearGradient1913"><stop
+ id="stop1915"
+ offset="0"
+ style="stop-color:#73d216;stop-opacity:1" /><stop
+ id="stop1917"
+ offset="1"
+ style="stop-color:#8ae234;stop-opacity:1" /></linearGradient><inkscape:perspective
+ id="perspective84036"
+ inkscape:persp3d-origin="24 : 16 : 1"
+ inkscape:vp_z="48 : 24 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 24 : 1"
+ sodipodi:type="inkscape:persp3d" /><radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient84076"
+ id="radialGradient84088"
+ cx="26.183998"
+ cy="40.111427"
+ fx="26.183998"
+ fy="40.111427"
+ r="10.5"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.9228377,7.3282173e-8,-7.9001009e-8,0.8924238,2.0204218,4.4167191)" /><linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3263"
+ id="linearGradient84092"
+ gradientUnits="userSpaceOnUse"
+ x1="26.455547"
+ y1="24.322035"
+ x2="26.455547"
+ y2="30.466549" /><linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient84104"
+ id="linearGradient84110"
+ x1="28.185518"
+ y1="22.649143"
+ x2="27.596079"
+ y2="42.648415"
+ gradientUnits="userSpaceOnUse" /><radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient84076"
+ id="radialGradient84134"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0862379,-2.5925308e-8,1.5464794e-8,0.8186283,-2.2580516,7.302016)"
+ cx="26.183998"
+ cy="39.098457"
+ fx="26.183998"
+ fy="39.098457"
+ r="10.5" /><linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3263"
+ id="linearGradient84136"
+ gradientUnits="userSpaceOnUse"
+ x1="26.455547"
+ y1="24.322035"
+ x2="26.455547"
+ y2="30.466549" /><linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient84104"
+ id="linearGradient84138"
+ gradientUnits="userSpaceOnUse"
+ x1="21.515692"
+ y1="23.09075"
+ x2="34.488232"
+ y2="40.661182" /><filter
+ inkscape:collect="always"
+ id="filter84266"
+ x="-0.07103052"
+ width="1.142061"
+ y="-0.5276553"
+ height="2.0553105"><feGaussianBlur
+ inkscape:collect="always"
+ stdDeviation="0.45756194"
+ id="feGaussianBlur84268" /></filter><linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3263"
+ id="linearGradient84277"
+ gradientUnits="userSpaceOnUse"
+ x1="26.455547"
+ y1="24.322035"
+ x2="26.455547"
+ y2="30.466549" /><linearGradient
+ id="linearGradient5171"><stop
+ style="stop-color:#fe3a00;stop-opacity:1"
+ offset="0"
+ id="stop5173" /><stop
+ style="stop-color:#c00;stop-opacity:1;"
+ offset="1"
+ id="stop5175" /></linearGradient><inkscape:perspective
+ id="perspective7871"
+ inkscape:persp3d-origin="24 : 16 : 1"
+ inkscape:vp_z="48 : 24 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 24 : 1"
+ sodipodi:type="inkscape:persp3d" /><inkscape:perspective
+ id="perspective7973"
+ inkscape:persp3d-origin="14 : 9.3333333 : 1"
+ inkscape:vp_z="28 : 14 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 14 : 1"
+ sodipodi:type="inkscape:persp3d" />
+
+<radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5171"
+ id="radialGradient8812"
+ cx="26.184002"
+ cy="39.797016"
+ fx="26.184002"
+ fy="39.797016"
+ r="10.65866"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.9444304,0,0,0.7220468,1.4550326,11.504981)" /><linearGradient
+ y2="40.661182"
+ x2="34.488232"
+ y1="23.09075"
+ x1="21.515692"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient84279"
+ xlink:href="#linearGradient84104"
+ inkscape:collect="always" /><linearGradient
+ y2="30.466549"
+ x2="26.455547"
+ y1="24.322035"
+ x1="26.455547"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9095"
+ xlink:href="#linearGradient3263"
+ inkscape:collect="always" /><linearGradient
+ y2="40.661182"
+ x2="34.488232"
+ y1="23.09075"
+ x1="21.515692"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9089"
+ xlink:href="#linearGradient84104"
+ inkscape:collect="always" /><linearGradient
+ y2="30.466549"
+ x2="26.455547"
+ y1="24.322035"
+ x1="26.455547"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9087"
+ xlink:href="#linearGradient3263"
+ inkscape:collect="always" /><radialGradient
+ r="10.5"
+ fy="39.098457"
+ fx="26.183998"
+ cy="39.098457"
+ cx="26.183998"
+ gradientTransform="matrix(1.0862379,-2.5925308e-8,1.5464794e-8,0.8186283,-2.2580516,7.302016)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient9085"
+ xlink:href="#linearGradient84076"
+ inkscape:collect="always" /><linearGradient
+ gradientUnits="userSpaceOnUse"
+ y2="42.648415"
+ x2="27.596079"
+ y1="22.649143"
+ x1="28.185518"
+ id="linearGradient9083"
+ xlink:href="#linearGradient84104"
+ inkscape:collect="always" /><linearGradient
+ y2="30.466549"
+ x2="26.455547"
+ y1="24.322035"
+ x1="26.455547"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9081"
+ xlink:href="#linearGradient3263"
+ inkscape:collect="always" /><radialGradient
+ gradientTransform="matrix(0.9228377,7.3282173e-8,-7.9001009e-8,0.8924238,2.0204218,4.4167191)"
+ gradientUnits="userSpaceOnUse"
+ r="10.5"
+ fy="40.111427"
+ fx="26.183998"
+ cy="40.111427"
+ cx="26.183998"
+ id="radialGradient9079"
+ xlink:href="#linearGradient84076"
+ inkscape:collect="always" /><inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 24 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="48 : 24 : 1"
+ inkscape:persp3d-origin="24 : 16 : 1"
+ id="perspective9077" /><linearGradient
+ id="linearGradient9071"><stop
+ style="stop-color:#73d216;stop-opacity:1"
+ offset="0"
+ id="stop9073" /><stop
+ style="stop-color:#8ae234;stop-opacity:1"
+ offset="1"
+ id="stop9075" /></linearGradient><linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5132"
+ id="linearGradient9063"
+ x1="21.55229"
+ y1="29.205048"
+ x2="18.072493"
+ y2="55.692348"
+ gradientUnits="userSpaceOnUse" /><linearGradient
+ y2="30.466549"
+ x2="26.455547"
+ y1="24.322035"
+ x1="26.455547"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9061"
+ xlink:href="#linearGradient3263"
+ inkscape:collect="always" /><linearGradient
+ y2="44.365963"
+ x2="30.691881"
+ y1="23.365002"
+ x1="30.691881"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9059"
+ xlink:href="#linearGradient3247"
+ inkscape:collect="always" /><linearGradient
+ y2="23.838018"
+ x2="25.144751"
+ y1="43.865002"
+ x1="25.144751"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient9057"
+ xlink:href="#linearGradient3233"
+ inkscape:collect="always" />
+
+
+
+
+
+ <inkscape:perspective
+ id="perspective9051"
+ inkscape:persp3d-origin="18.091999 : 14.621667 : 1"
+ inkscape:vp_z="36.183998 : 21.932501 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 21.932501 : 1"
+ sodipodi:type="inkscape:persp3d" /><linearGradient
+ id="linearGradient9045"><stop
+ style="stop-color:#398800;stop-opacity:1;"
+ offset="0"
+ id="stop9047" /><stop
+ style="stop-color:#84c706;stop-opacity:1;"
+ offset="1"
+ id="stop9049" /></linearGradient><linearGradient
+ id="linearGradient9039"><stop
+ id="stop9041"
+ offset="0"
+ style="stop-color:#52a714;stop-opacity:1;" /><stop
+ id="stop9043"
+ offset="1"
+ style="stop-color:#398800;stop-opacity:1;" /></linearGradient><linearGradient
+ id="linearGradient9033"><stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop9035" /><stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop9037" /></linearGradient><linearGradient
+ id="linearGradient9027"><stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop9029" /><stop
+ style="stop-color:#787878;stop-opacity:1"
+ offset="1"
+ id="stop9031" /></linearGradient><linearGradient
+ id="linearGradient9021"><stop
+ style="stop-color:#9b9b9b;stop-opacity:1;"
+ offset="0"
+ id="stop9023" /><stop
+ style="stop-color:#414141;stop-opacity:1;"
+ offset="1"
+ id="stop9025" /></linearGradient><linearGradient
+ id="linearGradient9013"><stop
+ id="stop9015"
+ offset="0"
+ style="stop-color:#73d216;stop-opacity:1;" /><stop
+ style="stop-color:#73d216;stop-opacity:1;"
+ offset="0.31459025"
+ id="stop9017" /><stop
+ id="stop9019"
+ offset="1"
+ style="stop-color:#4e9a06;stop-opacity:1;" /></linearGradient><linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3263"
+ id="linearGradient9115"
+ gradientUnits="userSpaceOnUse"
+ x1="26.455547"
+ y1="24.322035"
+ x2="26.455547"
+ y2="30.466549" /></defs><sodipodi:namedview
+ inkscape:window-height="733"
+ inkscape:window-width="1263"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ guidetolerance="10.0"
+ gridtolerance="10.0"
+ objecttolerance="10.0"
+ borderopacity="1.0"
+ bordercolor="#666666"
+ pagecolor="#ffffff"
+ id="base"
+ showgrid="false"
+ inkscape:zoom="10.958333"
+ inkscape:cx="16.307224"
+ inkscape:cy="24"
+ inkscape:window-x="6"
+ inkscape:window-y="140"
+ inkscape:current-layer="svg2419" />
+<path
+ id="path2424"
+ d="M 11.485207,8.6743869 C 11.872117,8.5219533 18.066562,7.5772471 17.547442,14.819684 C 16.836811,24.751336 10.199071,21.863582 8.4570051,28.091683 C 9.1530536,27.855507 9.3319265,27.184615 9.77036,26.633222 C 11.09052,24.971517 11.912946,24.144427 13.199081,23.591154 C 17.777838,21.620819 20.261644,13.237019 16.405184,9.3659791 C 14.958646,7.9131637 12.270692,8.0514823 11.485207,8.6743869 z M -0.41567362,30.622819 C -0.62079412,30.073309 -0.81036052,29.508743 -0.98534482,28.932886 C 0.28134733,30.510848 2.408639,29.511665 3.7800623,29.851546 C 7.7792565,30.842672 10.201988,29.700696 12.4972,27.002072 C 14.538683,24.600785 15.730521,26.026314 17.692291,22.415916 C 18.187107,21.506024 19.527682,20.515211 20.049718,16.478567 C 20.335526,14.26641 21.73087,14.007651 21.560747,12.407106 C 21.300215,9.95501 21.209476,9.6012157 20.182901,7.9460967 C 18.706228,5.5636294 16.443158,4.9249489 14.396731,4.9187631 C 12.674334,4.9140584 11.84411,5.6088349 11.260829,5.8365431 C 15.390232,4.8356399 18.977454,6.2618089 19.977781,8.6743869 C 20.486207,9.9004346 20.744795,10.273048 20.835204,11.578136 C 20.978108,13.644446 20.307334,14.416019 20.263588,13.790293 C 20.079855,11.11331 19.152438,7.8049552 16.050354,6.738867 C 14.094417,6.0670338 11.302445,6.5779657 9.6303729,7.8454158 C 7.5908326,9.7988133 6.4952361,12.616937 6.4952361,14.474358 C 6.4952361,18.037708 6.4689884,19.168722 5.854599,22.494014 C 5.596011,23.89696 4.6627611,25.357303 5.2022963,27.278709 C 5.9975029,26.985134 6.7110502,25.878585 6.9949136,25.111717 C 8.9868188,19.727642 10.292396,20.99227 12.343602,18.829042 C 12.831614,18.314346 13.669595,16.922691 13.771669,16.409877 C 14.018591,15.167833 14.629092,12.200099 12.557472,12.269729 C 10.832904,13.36875 11.557145,15.649595 10.237957,17.872102 C 12.271664,16.963152 12.138481,13.127869 12.885082,13.037538 C 13.533495,12.95944 13.493638,14.504468 13.351707,15.328734 C 13.046456,17.100529 12.422345,18.101693 11.019554,19.120734 C 9.9006261,19.933709 8.8604412,20.065441 7.8484484,21.773252 C 7.6579099,22.073413 6.3027534,25.346012 6.134574,25.654641 C 5.2858998,27.216607 5.3879741,25.564311 6.3212239,22.946607 C 6.3212239,22.946607 7.2311425,20.110606 7.1115699,17.014904 C 7.0571303,15.581848 7.1368454,9.9201951 10.843597,7.9150456 C 12.438871,7.052201 14.9149,6.5102179 16.620025,7.776727 C 21.95802,11.740919 19.47227,21.463682 15.405828,24.214058 C 13.770697,25.320606 12.413596,25.389296 11.019554,27.516768 C 9.932706,29.17565 6.8500655,30.289726 4.7074794,29.321496 C 5.5649027,28.845379 6.8957558,28.803036 7.2787772,27.73883 C 10.085332,19.931827 15.530262,23.306048 16.183536,14.966471 C 16.414904,12.009088 14.877959,9.6953099 12.69746,9.6953099 C 10.466409,9.6953099 8.9664042,12.675276 8.6281009,15.440706 C 8.4657544,16.774023 8.3782621,18.528881 8.2713273,19.450064 C 10.056167,18.413145 8.4851971,11.162239 12.484562,10.747283 C 15.963834,10.386902 15.66636,14.964589 15.26973,16.96127 C 14.967396,18.483716 14.270374,19.795389 11.270365,21.516375 C 9.690645,22.422502 8.643655,23.573275 7.8426157,25.457043 C 7.3730743,26.56171 6.4126046,28.452065 4.547077,28.632726 C 4.3332073,28.653426 3.9268547,26.573943 3.8004772,25.47304 C 3.6138271,23.848031 4.453752,22.765006 4.7327549,21.015793 C 5.0438382,19.072746 5.2615964,17.525836 5.2781228,14.197721 C 4.4936096,9.0893427 5.2917327,7.5791289 7.4226532,5.1562011 C 9.9142358,2.3220811 12.045219,2.0705493 13.508882,2.0570557 C 15.652565,2.0393053 16.899028,3.5509526 16.263252,3.4276891 C 14.62326,3.1105913 11.630055,2.6909308 9.0577845,5.2945196 C 7.6229131,6.7454536 6.0402768,8.6122845 6.2084562,10.886543 C 6.8802017,7.6195895 10.334508,3.7516736 13.747676,3.7516736 C 17.577206,3.7516736 19.976808,5.1712562 21.120039,7.0155042 C 22.280769,8.8889209 22.761976,10.297513 22.761976,12.822062 C 22.761976,14.686071 21.730541,15.451057 21.262943,16.962211 C 21.083098,17.542773 20.463848,19.045459 20.191651,20.211286 C 19.097998,24.896241 18.309596,27.152622 14.271346,30.220096 C 12.511782,31.556235 11.111907,31.646565 10.179629,31.285243 C 10.187406,31.13281 12.366934,30.934272 13.724035,28.937591 C 15.002392,27.055705 16.650162,27.007717 17.396761,24.840726 C 16.622941,25.778846 15.419438,26.673683 14.41425,27.115925 C 14.130387,27.241071 13.618072,27.886557 13.421701,28.116148 C 11.368551,30.531548 9.713004,31.103642 7.3458545,31.373692 C 7.7220709,31.550589 8.110925,31.687026 8.5231103,31.739719 C 11.53187,32.124565 13.387675,32.163143 15.774267,30.055431 C 19.142717,27.08111 19.696834,25.201106 20.047775,22.967308 C 20.307334,21.313131 21.669648,17.436727 22.261326,15.868175 C 23.094574,13.65922 22.570465,18.105457 22.332292,18.688842 C 20.93825,22.115755 21.500144,26.735784 17.955739,30.380997 C 15.523456,32.882964 12.32416,33.811675 7.1358733,32.637379 C 5.7525248,32.324044 6.253216,31.857336 4.671552,31.373692 C 4.1971499,31.159157 1.6540024,31.013311 1.3623619,31.011429 C 0.72269676,31.007665 0.11997297,30.875933 -0.41567362,30.622819 z M 4.2680743,5.1477326 C 2.8681995,6.7162844 3.1442858,7.9310416 2.2158966,9.2445983 C 0.39119867,11.826545 1.4517984,15.393659 1.0658607,17.99913 C 0.56618308,21.378997 0.52283784,20.110089 0.0065640818,17.990301 C -0.75463862,14.864849 -0.20180392,13.731954 -0.076398418,12.407106 C 0.6186783,9.1298026 1.2262629,7.7560263 2.8691715,5.6887748 C 4.2253003,3.9828454 6.149156,3.0371977 4.2680743,5.1477326 z M 24.036445,36.450079 C 23.488161,37.083333 22.896131,37.673305 22.262298,38.211523 L 21.475841,38.506979 C 18.241547,39.711387 16.58114,39.821477 11.857534,39.082837 C 9.932706,38.781735 7.3050248,38.411944 5.4978253,39.277612 C 6.5839482,39.510065 10.395401,38.361053 11.576587,39.986142 C 11.459931,40.156453 9.2113823,39.88358 7.0960157,40.347465 C 6.5837004,40.058595 6.0888836,39.731146 5.6115651,39.367002 C 5.1527173,39.009443 4.8173306,38.720573 4.4926375,38.413826 C 6.9570004,37.030641 10.904842,37.507699 13.34879,37.820091 C 17.581468,38.362075 19.260345,38.181414 21.964825,37.188718 C 22.696843,36.919609 23.388031,36.670259 24.036445,36.450079 z M 26.094456,7.8981086 C 27.151167,9.9813566 28.257457,11.575313 28.257457,14.734999 C 28.257457,18.212845 25.759069,19.908303 25.360494,22.223022 C 24.987194,24.390014 24.927894,26.193802 24.599312,26.193802 C 24.132687,26.193802 23.98395,24.125609 24.054915,22.674675 C 24.126854,21.205864 24.314124,20.404861 24.655344,19.310545 C 25.039337,18.081673 25.62266,15.331577 25.504059,13.251152 C 25.348517,10.505481 25.590559,11.089486 26.303134,12.745546 C 26.769759,13.828571 26.261622,15.950138 26.303134,17.484815 C 27.329709,15.648996 27.135261,12.882863 26.349775,10.877714 C 26.087298,10.20494 25.726989,8.8446969 26.094456,7.8981086 z M 24.622001,9.2587722 C 24.485902,8.654687 23.723397,6.4935811 22.726959,5.2026076 C 21.232786,3.2689699 22.578201,3.6726143 23.649494,4.846911 C 24.696483,5.9948613 25.472289,7.3598893 25.501453,8.680032 C 25.560753,11.39277 25.122651,11.470929 24.622001,9.2587722 z M 28.324534,16.874703 C 28.602565,16.515264 28.874762,18.765998 28.371196,19.556391 C 27.026733,21.665043 27.509885,25.128655 26.639823,27.894085 C 25.254531,32.293934 20.848813,35.618286 15.998831,35.528896 C 19.543236,34.354599 22.714341,33.813557 24.183237,26.840229 C 24.312532,26.225793 25.174816,26.557005 24.397107,29.459814 C 25.254531,28.223415 25.999186,25.124891 26.111954,22.623864 C 26.186809,20.930167 27.729588,18.502534 28.324534,16.874703 z M 0.35036898,7.0776065 C 3.1160939,2.0115701 8.6912897,0.54275818 13.214636,0.54275818 C 16.041605,0.54275818 18.507912,1.0273437 20.818678,2.3550142 C 21.174479,2.6147144 21.713042,2.9355759 22.002738,3.2253863 C 22.938905,4.1653883 21.369626,3.7445623 19.405193,2.8753556 C 15.80217,1.2811182 13.224356,1.5241817 11.057467,1.8713897 C 9.4544161,2.1282671 8.4327017,3.4107521 7.629718,4.1889118 C 4.6705382,7.05126 4.2097461,9.6106249 4.5655476,12.822062 C 5.0068971,16.806955 4.2680743,21.015793 3.3367686,23.309812 C 2.8604223,24.48505 2.9236112,26.011258 3.1365088,26.978548 C 3.5214743,28.723056 5.0173803,29.448829 3.1481744,29.208582 C -0.12595652,28.787761 -0.12403302,24.289333 0.99392257,21.109887 C 2.1361815,17.860811 1.50895,15.966631 1.7492717,13.57764 C 2.8163869,2.8893489 3.1267874,15.841548 3.0655428,16.408937 C 2.7077971,19.726701 2.2340211,20.608302 1.7385783,22.084704 C 0.6727661,25.260787 1.9314335,27.1104 2.2661583,27.366598 C 0.91096007,23.04949 3.2794126,21.655634 3.4660626,16.648877 C 3.5117529,15.433179 3.5311956,14.688893 3.3455178,13.046948 C 2.7748744,7.9799706 4.0814242,5.0574021 6.9725545,2.7097496 C 5.2188225,2.7266866 3.8724152,3.9950776 2.6825216,5.1477326 C 1.376944,6.4114188 0.16469114,9.2935264 -0.21249732,10.402898 C -0.77633582,12.06178 -1.2711526,10.046281 0.35036898,7.0776065 z M -1.1097781,28.513226 C -2.0128918,25.368594 -2.4649347,21.861701 -2.3900803,18.216487 C -2.3609163,16.765553 -2.2306501,15.171597 -1.7834679,13.305707 C -0.91243472,9.6699043 -0.68197602,11.586122 -0.74034592,12.032491 C -1.892347,20.8421 1.6144968,19.138912 -0.52455272,25.744091 C -1.2711526,25.202108 -0.48304042,21.510409 -1.656139,19.312946 C -1.3508469,21.734954 -2.0167804,25.74309 0.62937185,28.271403 C 1.3856931,28.994988 2.8681995,29.389244 0.72269676,29.208582 C -0.014181718,29.14648 -0.61787772,28.901835 -1.1097781,28.513226 z M 0.48744008,32.752173 C 0.31731635,32.398379 0.15496979,32.036116 -0.001544018,31.666325 C 1.0075324,31.547766 3.0567937,31.442381 4.827052,32.187607 C 5.8555711,32.620441 3.7965886,32.40967 2.0000826,32.51976 C 1.3565291,32.558339 0.82574314,32.712653 0.48744008,32.752173 z M 1.3409749,34.366831 C 1.1446035,34.029973 0.95600926,33.683706 0.77422,33.328971 C 5.2207668,32.537638 7.1728144,33.319562 10.628756,33.606549 C 14.190659,33.902946 18.050036,32.097277 19.263261,30.020616 C 19.886399,28.953587 20.061384,28.694827 20.186789,28.414427 C 20.295669,28.171663 20.367606,27.912904 20.662164,27.098048 C 21.315439,25.292378 21.284331,27.753885 21.120039,28.360793 C 20.008889,32.4586 19.076611,31.735955 17.211084,33.542565 C 21.502088,32.007888 22.154392,28.937591 21.595413,24.661006 C 21.461259,23.63726 22.257437,20.869947 22.622961,19.880074 C 22.622961,19.880074 23.390948,17.397867 23.395808,12.997078 C 23.398724,10.126261 22.460614,5.7019479 18.621652,4.0505932 C 17.335517,3.4973188 15.549704,1.9767551 15.549704,1.9767551 C 16.345283,2.4005401 18.263906,2.6674072 20.120685,3.773956 C 20.191651,3.8162985 24.211429,6.0576243 24.612921,11.923462 C 24.802488,14.69548 24.823213,14.824989 24.636563,16.630658 C 24.636563,16.630658 24.522513,18.48748 23.87021,20.022157 C 23.555238,20.876533 23.217907,23.396378 23.404558,24.661006 C 23.836185,27.588279 22.063983,34.896582 14.845879,34.896582 C 11.657275,34.896582 9.7168927,34.487272 8.1906401,34.251096 C 6.8082637,34.036561 4.0143469,33.91612 1.3409749,34.366831 z M 3.9297711,37.852084 C 3.5603597,37.465356 3.2055303,37.055105 2.865283,36.622271 C 3.9113006,36.029477 4.8299684,36.020068 6.6935517,36.070879 C 8.8283608,36.070879 12.045156,36.916786 11.057467,37.195306 C 11.009832,37.207538 6.4806541,36.578988 3.9297711,37.852084 z M 14.733111,41.653493 C 14.310232,41.716536 13.88152,41.763583 13.44406,41.791811 C 11.361746,41.927308 9.4310844,41.515174 7.6851297,40.656094 C 8.5367202,40.538475 10.183517,40.482019 11.744767,40.7022 C 12.669268,40.832991 13.723062,41.288407 14.733111,41.653493 z M 20.761322,39.340655 C 19.332282,40.284421 17.738953,40.992951 16.005636,41.406965 C 14.734083,41.029648 11.984449,40.585503 12.005589,39.75495 C 12.021421,39.132891 15.493321,40.331468 17.489114,40.076472 C 18.855937,39.902398 19.892232,39.635171 20.761322,39.340655 z M 26.76134,32.003183 C 27.309624,31.472491 26.651489,34.623708 23.573708,35.937265 C 21.48945,36.675905 18.394173,38.324437 13.07076,36.917727 C 12.417485,36.744594 10.347808,36.196965 9.8870164,36.103812 C 6.2998369,35.382109 4.4372258,35.597584 2.4064351,36.01254 C 2.1702062,35.685092 1.9417545,35.345412 1.7210798,34.995381 C 2.3753268,34.730976 4.0192075,34.628413 5.200352,34.626531 C 8.9615437,34.619945 14.003037,35.980548 15.996887,36.070879 C 20.670913,36.282591 23.680644,33.000582 24.053944,33.000582 C 24.986221,33.000582 23.179994,34.632178 22.678372,35.082889 C 22.251605,35.467734 24.361138,34.516441 26.76134,32.003183 z M 28.531599,25.021387 C 28.408138,27.148859 28.247735,30.101537 26.467755,31.577877 C 23.628148,33.933056 24.799572,32.277938 26.039044,30.634111 C 28.194268,27.774586 27.297959,21.332891 28.708527,20.0852 C 28.725053,21.437335 28.621035,23.498941 28.531599,25.021387 z"
+ style="fill:#a1a1a1;fill-opacity:1"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ sodipodi:nodetypes="cscssscccssssssscsssscsscsssccssscscssssscsssscssssssscsssscsssssscscsscssssssscsccssscsccccscccscssccssssssscsccsssccsscscsccscsssssssssssscsscssccsssccsscccsscccssssscscsscssccsssccccsccscscccsscccssccssssccsscc" /><path
+ sodipodi:type="arc"
+ style="opacity:0.24299999;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;filter:url(#filter84266)"
+ id="path84140"
+ sodipodi:cx="27.093658"
+ sodipodi:cy="38.810692"
+ sodipodi:rx="7.7301183"
+ sodipodi:ry="1.0405928"
+ d="M 34.823777,38.810692 A 7.7301183,1.0405928 0 1 1 19.36354,38.810692 A 7.7301183,1.0405928 0 1 1 34.823777,38.810692 z"
+ transform="matrix(1.1911672,0,0,2.1266149,-5.0625748,-41.775272)" /><g
+ id="Background">
+</g>
+<g
+ id="Guides">
+</g>
+
+<circle
+ clip-rule="evenodd"
+ cx="26.184"
+ cy="33.865002"
+ r="10"
+ id="circle2428"
+ sodipodi:cx="26.184"
+ sodipodi:cy="33.865002"
+ sodipodi:rx="10"
+ sodipodi:ry="10"
+ style="fill:url(#radialGradient8812);fill-opacity:1;fill-rule:evenodd;stroke:#a40000;stroke-width:1.31732059000000001;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ transform="matrix(1.1263785,0,0,1.1511056,-2.2713556,-9.1997707)" /><path
+ sodipodi:type="arc"
+ style="opacity:0.5;fill:url(#linearGradient84277);fill-opacity:1;stroke:none;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path3253"
+ sodipodi:cx="26.455547"
+ sodipodi:cy="27.394291"
+ sodipodi:rx="6.1445141"
+ sodipodi:ry="3.072257"
+ d="M 32.600061,27.394291 A 6.1445141,3.072257 0 1 1 20.311033,27.394291 A 6.1445141,3.072257 0 1 1 32.600061,27.394291 z"
+ transform="matrix(1.1246822,0,0,1.4387643,-2.5144268,-14.969086)" /><path
+ sodipodi:type="arc"
+ style="opacity:0.48;fill:none;fill-opacity:1;stroke:#e64837;stroke-width:1.21842730000000010;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path84102"
+ sodipodi:cx="28.185518"
+ sodipodi:cy="31.917336"
+ sodipodi:rx="10.027505"
+ sodipodi:ry="10.240856"
+ d="M 38.213023,31.917336 A 10.027505,10.240856 0 1 1 18.158013,31.917336 A 10.027505,10.240856 0 1 1 38.213023,31.917336 z"
+ transform="matrix(0.9962424,0,0,0.9957004,-0.8393988,-2.0505383)" /><g
+ id="g7978"
+ transform="translate(103.26268,8.6771365)">
+</g><g
+ style="display:none"
+ id="g7980"
+ display="none"
+ transform="translate(103.26268,8.6771365)">
+</g><path
+ id="path7993"
+ style="opacity:0.55;fill:#a40000;fill-opacity:1;fill-rule:evenodd;stroke:#a40000;stroke-width:1.14231765000000007;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 27.143847,37.652725 C 26.708227,37.652725 26.326837,37.518032 25.998788,37.249507 C 25.677852,36.974118 25.516939,36.592349 25.516939,36.10334 C 25.516939,35.676959 25.66985,35.315778 25.977452,35.018942 C 26.291276,34.7161 26.672666,34.565107 27.122511,34.56425 C 27.571466,34.56425 27.953745,34.7161 28.26757,35.018942 C 28.588505,35.31492 28.749418,35.676959 28.749418,36.10334 C 28.749418,36.585484 28.588505,36.963823 28.26757,37.239212 C 27.946633,37.515458 27.571466,37.652725 27.143847,37.652725 z M 25.956115,30.858079 L 25.613842,25.912229 C 25.549833,24.94794 25.517828,24.256464 25.517828,23.836088 C 25.517828,23.26472 25.670739,22.82118 25.978341,22.504613 C 26.292165,22.18118 26.702004,22.019893 27.208746,22.019035 C 27.82217,22.019035 28.232008,22.225791 28.439151,22.638445 C 28.645403,23.045095 28.749418,23.633622 28.749418,24.404025 C 28.749418,24.858717 28.724526,25.320272 28.674741,25.787834 L 28.214228,30.878669 C 28.164443,31.484354 28.056871,31.94934 27.893292,32.272773 C 27.728822,32.596205 27.457671,32.758349 27.079838,32.758349 C 26.694892,32.758349 26.427296,32.603067 26.277052,32.293362 C 26.126807,31.976794 26.020125,31.498939 25.956115,30.858079 z" /><path
+ id="path8814"
+ style="fill:#ffffff;fill-rule:evenodd"
+ d="M 27.143847,36.992527 C 26.708227,36.992527 26.326837,36.857834 25.998788,36.589309 C 25.677852,36.31392 25.516939,35.932151 25.516939,35.443142 C 25.516939,35.016761 25.66985,34.65558 25.977452,34.358744 C 26.291276,34.055902 26.672666,33.904909 27.122511,33.904052 C 27.571466,33.904052 27.953745,34.055902 28.26757,34.358744 C 28.588505,34.654722 28.749418,35.016761 28.749418,35.443142 C 28.749418,35.925286 28.588505,36.303625 28.26757,36.579014 C 27.946633,36.85526 27.571466,36.992527 27.143847,36.992527 z M 25.956115,30.197881 L 25.613842,25.252031 C 25.549833,24.287742 25.517828,23.596266 25.517828,23.17589 C 25.517828,22.604522 25.670739,22.160982 25.978341,21.844415 C 26.292165,21.520982 26.702004,21.359695 27.208746,21.358837 C 27.82217,21.358837 28.232008,21.565593 28.439151,21.978247 C 28.645403,22.384897 28.749418,22.973424 28.749418,23.743827 C 28.749418,24.198519 28.724526,24.660074 28.674741,25.127636 L 28.214228,30.218471 C 28.164443,30.824156 28.056871,31.289142 27.893292,31.612575 C 27.728822,31.936007 27.457671,32.098151 27.079838,32.098151 C 26.694892,32.098151 26.427296,31.942869 26.277052,31.633164 C 26.126807,31.316596 26.020125,30.838741 25.956115,30.197881 z" /><rect
+ style="fill:#666666;fill-opacity:0.75;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect9126"
+ width="1.8060035"
+ height="42.650608"
+ x="-26.038683"
+ y="-24.284592"
+ transform="matrix(-0.6420845,-0.7666339,0.7632254,-0.6461324,0,0)"
+ ry="0"
+ rx="0.018515259" /></svg> \ No newline at end of file
diff --git a/capplets/about-me/icons/print_ok.png b/capplets/about-me/icons/print_ok.png
new file mode 100644
index 00000000..4dd615e7
--- /dev/null
+++ b/capplets/about-me/icons/print_ok.png
Binary files differ
diff --git a/capplets/about-me/icons/print_ok.svg b/capplets/about-me/icons/print_ok.svg
new file mode 100644
index 00000000..ba821ef7
--- /dev/null
+++ b/capplets/about-me/icons/print_ok.svg
@@ -0,0 +1,310 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.0"
+ x="0px"
+ y="0px"
+ width="48"
+ height="48"
+ viewBox="0 0 36.184 43.865"
+ enable-background="new 0 0 36.184 43.865"
+ xml:space="preserve"
+ id="svg2419"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ sodipodi:docname="print_ok.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ inkscape:export-filename="/Users/mlanglie/Desktop/Fingerprint Enrollment Icons/Vector/print_ok.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"><metadata
+ id="metadata2435"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
+ id="defs2433"><linearGradient
+ inkscape:collect="always"
+ id="linearGradient84104"><stop
+ style="stop-color:#fffffc;stop-opacity:1;"
+ offset="0"
+ id="stop84106" /><stop
+ style="stop-color:#fffffc;stop-opacity:0;"
+ offset="1"
+ id="stop84108" /></linearGradient><linearGradient
+ id="linearGradient84076"><stop
+ style="stop-color:#73d216;stop-opacity:1;"
+ offset="0"
+ id="stop84078" /><stop
+ id="stop84090"
+ offset="0.31459025"
+ style="stop-color:#73d216;stop-opacity:1;" /><stop
+ style="stop-color:#4e9a06;stop-opacity:1;"
+ offset="1"
+ id="stop84080" /></linearGradient><linearGradient
+ id="linearGradient3531"><stop
+ id="stop3533"
+ offset="0"
+ style="stop-color:#9b9b9b;stop-opacity:1;" /><stop
+ id="stop3535"
+ offset="1"
+ style="stop-color:#414141;stop-opacity:1;" /></linearGradient><linearGradient
+ id="linearGradient3483"><stop
+ id="stop3485"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" /><stop
+ id="stop3487"
+ offset="1"
+ style="stop-color:#787878;stop-opacity:1" /></linearGradient><linearGradient
+ id="linearGradient3263"><stop
+ id="stop3265"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" /><stop
+ id="stop3267"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:0;" /></linearGradient><linearGradient
+ id="linearGradient3247"><stop
+ style="stop-color:#52a714;stop-opacity:1;"
+ offset="0"
+ id="stop3249" /><stop
+ style="stop-color:#398800;stop-opacity:1;"
+ offset="1"
+ id="stop3251" /></linearGradient><linearGradient
+ id="linearGradient3233"><stop
+ id="stop3235"
+ offset="0"
+ style="stop-color:#398800;stop-opacity:1;" /><stop
+ id="stop3237"
+ offset="1"
+ style="stop-color:#84c706;stop-opacity:1;" /></linearGradient><inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 21.932501 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="36.183998 : 21.932501 : 1"
+ inkscape:persp3d-origin="18.091999 : 14.621667 : 1"
+ id="perspective2437" />
+
+
+
+
+
+ <filter
+ inkscape:collect="always"
+ id="filter3471"><feGaussianBlur
+ inkscape:collect="always"
+ stdDeviation="0.057808254"
+ id="feGaussianBlur3473" /></filter><linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3233"
+ id="linearGradient3517"
+ gradientUnits="userSpaceOnUse"
+ x1="25.144751"
+ y1="43.865002"
+ x2="25.144751"
+ y2="23.838018" /><linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3247"
+ id="linearGradient3519"
+ gradientUnits="userSpaceOnUse"
+ x1="30.691881"
+ y1="23.365002"
+ x2="30.691881"
+ y2="44.365963" /><linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3263"
+ id="linearGradient3521"
+ gradientUnits="userSpaceOnUse"
+ x1="26.455547"
+ y1="24.322035"
+ x2="26.455547"
+ y2="30.466549" /><linearGradient
+ gradientUnits="userSpaceOnUse"
+ y2="55.692348"
+ x2="18.072493"
+ y1="29.205048"
+ x1="21.55229"
+ id="linearGradient5138"
+ xlink:href="#linearGradient5132"
+ inkscape:collect="always" /><linearGradient
+ id="linearGradient5132"
+ inkscape:collect="always"><stop
+ id="stop5134"
+ offset="0"
+ style="stop-color:white;stop-opacity:1;" /><stop
+ id="stop5136"
+ offset="1"
+ style="stop-color:white;stop-opacity:0;" /></linearGradient><linearGradient
+ id="linearGradient1913"><stop
+ id="stop1915"
+ offset="0"
+ style="stop-color:#73d216;stop-opacity:1" /><stop
+ id="stop1917"
+ offset="1"
+ style="stop-color:#8ae234;stop-opacity:1" /></linearGradient><inkscape:perspective
+ id="perspective84036"
+ inkscape:persp3d-origin="24 : 16 : 1"
+ inkscape:vp_z="48 : 24 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 24 : 1"
+ sodipodi:type="inkscape:persp3d" /><radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient84076"
+ id="radialGradient84088"
+ cx="26.183998"
+ cy="40.111427"
+ fx="26.183998"
+ fy="40.111427"
+ r="10.5"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.9228377,7.3282173e-8,-7.9001009e-8,0.8924238,2.0204218,4.4167191)" /><linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3263"
+ id="linearGradient84092"
+ gradientUnits="userSpaceOnUse"
+ x1="26.455547"
+ y1="24.322035"
+ x2="26.455547"
+ y2="30.466549" /><linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient84104"
+ id="linearGradient84110"
+ x1="28.185518"
+ y1="22.649143"
+ x2="27.596079"
+ y2="42.648415"
+ gradientUnits="userSpaceOnUse" /><radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient84076"
+ id="radialGradient84134"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0862379,-2.5925308e-8,1.5464794e-8,0.8186283,-2.2580516,7.302016)"
+ cx="26.183998"
+ cy="39.098457"
+ fx="26.183998"
+ fy="39.098457"
+ r="10.5" /><linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3263"
+ id="linearGradient84136"
+ gradientUnits="userSpaceOnUse"
+ x1="26.455547"
+ y1="24.322035"
+ x2="26.455547"
+ y2="30.466549" /><linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient84104"
+ id="linearGradient84138"
+ gradientUnits="userSpaceOnUse"
+ x1="21.515692"
+ y1="23.09075"
+ x2="34.488232"
+ y2="40.661182" /><filter
+ inkscape:collect="always"
+ id="filter84266"
+ x="-0.07103052"
+ width="1.142061"
+ y="-0.5276553"
+ height="2.0553105"><feGaussianBlur
+ inkscape:collect="always"
+ stdDeviation="0.45756194"
+ id="feGaussianBlur84268" /></filter><linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3263"
+ id="linearGradient84277"
+ gradientUnits="userSpaceOnUse"
+ x1="26.455547"
+ y1="24.322035"
+ x2="26.455547"
+ y2="30.466549" /><linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient84104"
+ id="linearGradient84279"
+ gradientUnits="userSpaceOnUse"
+ x1="21.515692"
+ y1="23.09075"
+ x2="34.488232"
+ y2="40.661182" /></defs><sodipodi:namedview
+ inkscape:window-height="713"
+ inkscape:window-width="1222"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ guidetolerance="10.0"
+ gridtolerance="10.0"
+ objecttolerance="10.0"
+ borderopacity="1.0"
+ bordercolor="#666666"
+ pagecolor="#ffffff"
+ id="base"
+ showgrid="false"
+ inkscape:zoom="4.399364"
+ inkscape:cx="39.372624"
+ inkscape:cy="7.0437262"
+ inkscape:window-x="15"
+ inkscape:window-y="165"
+ inkscape:current-layer="svg2419" />
+<path
+ sodipodi:type="arc"
+ style="opacity:0.24299999;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;filter:url(#filter84266)"
+ id="path84140"
+ sodipodi:cx="27.093658"
+ sodipodi:cy="38.810692"
+ sodipodi:rx="7.7301183"
+ sodipodi:ry="1.0405928"
+ d="M 34.823777,38.810692 A 7.7301183,1.0405928 0 1 1 19.36354,38.810692 A 7.7301183,1.0405928 0 1 1 34.823777,38.810692 z"
+ transform="matrix(1.1911672,0,0,2.1266149,-5.0625748,-41.775272)" /><g
+ id="Background">
+</g>
+<g
+ id="Guides">
+</g>
+<path
+ id="path2424"
+ d="M 11.4715,8.6587828 C 11.85841,8.5063492 18.052855,7.561643 17.533735,14.80408 C 16.823104,24.735732 10.185364,21.847978 8.4432981,28.076079 C 9.1393466,27.839903 9.3182195,27.169011 9.756653,26.617618 C 11.076813,24.955913 11.899239,24.128823 13.185374,23.57555 C 17.764131,21.605215 20.247937,13.221415 16.391477,9.350375 C 14.944939,7.8975596 12.256985,8.0358782 11.4715,8.6587828 z M -0.42938057,30.607215 C -0.63450107,30.057705 -0.82406747,29.493139 -0.99905177,28.917282 C 0.26764038,30.495244 2.394932,29.496061 3.7663553,29.835942 C 7.7655495,30.827068 10.188281,29.685092 12.483493,26.986468 C 14.524976,24.585181 15.716814,26.01071 17.678584,22.400312 C 18.1734,21.49042 19.513975,20.499607 20.036011,16.462963 C 20.321819,14.250806 21.717163,13.992047 21.54704,12.391502 C 21.286508,9.9394059 21.195769,9.5856116 20.169194,7.9304926 C 18.692521,5.5480253 16.429451,4.9093448 14.383024,4.903159 C 12.660627,4.8984543 11.830403,5.5932308 11.247122,5.820939 C 15.376525,4.8200358 18.963747,6.2462048 19.964074,8.6587828 C 20.4725,9.8848305 20.731088,10.257444 20.821497,11.562532 C 20.964401,13.628842 20.293627,14.400415 20.249881,13.774689 C 20.066148,11.097706 19.138731,7.7893511 16.036647,6.7232629 C 14.08071,6.0514297 11.288738,6.5623616 9.6166659,7.8298117 C 7.5771256,9.7832092 6.4815291,12.601333 6.4815291,14.458754 C 6.4815291,18.022104 6.4552814,19.153118 5.840892,22.47841 C 5.582304,23.881356 4.6490541,25.341699 5.1885893,27.263105 C 5.9837959,26.96953 6.6973432,25.862981 6.9812066,25.096113 C 8.9731118,19.712038 10.278689,20.976666 12.329895,18.813438 C 12.817907,18.298742 13.655888,16.907087 13.757962,16.394273 C 14.004884,15.152229 14.615385,12.184495 12.543765,12.254125 C 10.819197,13.353146 11.543438,15.633991 10.22425,17.856498 C 12.257957,16.947548 12.124774,13.112265 12.871375,13.021934 C 13.519788,12.943836 13.479931,14.488864 13.338,15.31313 C 13.032749,17.084925 12.408638,18.086089 11.005847,19.10513 C 9.8869191,19.918105 8.8467342,20.049837 7.8347414,21.757648 C 7.6442029,22.057809 6.2890464,25.330408 6.120867,25.639037 C 5.2721928,27.201003 5.3742671,25.548707 6.3075169,22.931003 C 6.3075169,22.931003 7.2174355,20.095002 7.0978629,16.9993 C 7.0434233,15.566244 7.1231384,9.904591 10.82989,7.8994415 C 12.425164,7.0365969 14.901193,6.4946138 16.606318,7.7611229 C 21.944313,11.725315 19.458563,21.448078 15.392121,24.198454 C 13.75699,25.305002 12.399889,25.373692 11.005847,27.501164 C 9.918999,29.160046 6.8363585,30.274122 4.6937724,29.305892 C 5.5511957,28.829775 6.8820488,28.787432 7.2650702,27.723226 C 10.071625,19.916223 15.516555,23.290444 16.169829,14.950867 C 16.401197,11.993484 14.864252,9.6797058 12.683753,9.6797058 C 10.452702,9.6797058 8.9526972,12.659672 8.6143939,15.425102 C 8.4520474,16.758419 8.3645551,18.513277 8.2576203,19.43446 C 10.04246,18.397541 8.4714901,11.146635 12.470855,10.731679 C 15.950127,10.371298 15.652653,14.948985 15.256023,16.945666 C 14.953689,18.468112 14.256667,19.779785 11.256658,21.500771 C 9.676938,22.406898 8.629948,23.557671 7.8289087,25.441439 C 7.3593673,26.546106 6.3988976,28.436461 4.53337,28.617122 C 4.3195003,28.637822 3.9131477,26.558339 3.7867702,25.457436 C 3.6001201,23.832427 4.440045,22.749402 4.7190479,21.000189 C 5.0301312,19.057142 5.2478894,17.510232 5.2644158,14.182117 C 4.4799026,9.0737386 5.2780257,7.5635248 7.4089462,5.140597 C 9.9005288,2.306477 12.031512,2.0549452 13.495175,2.0414516 C 15.638858,2.0237012 16.885321,3.5353485 16.249545,3.412085 C 14.609553,3.0949872 11.616348,2.6753267 9.0440775,5.2789155 C 7.6092061,6.7298495 6.0265698,8.5966804 6.1947492,10.870939 C 6.8664947,7.6039854 10.320801,3.7360695 13.733969,3.7360695 C 17.563499,3.7360695 19.963101,5.1556521 21.106332,6.9999001 C 22.267062,8.8733168 22.748269,10.281909 22.748269,12.806458 C 22.748269,14.670467 21.716834,15.435453 21.249236,16.946607 C 21.069391,17.527169 20.450141,19.029855 20.177944,20.195682 C 19.084291,24.880637 18.295889,27.137018 14.257639,30.204492 C 12.498075,31.540631 11.0982,31.630961 10.165922,31.269639 C 10.173699,31.117206 12.353227,30.918668 13.710328,28.921987 C 14.988685,27.040101 16.636455,26.992113 17.383054,24.825122 C 16.609234,25.763242 15.405731,26.658079 14.400543,27.100321 C 14.11668,27.225467 13.604365,27.870953 13.407994,28.100544 C 11.354844,30.515944 9.699297,31.088038 7.3321475,31.358088 C 7.7083639,31.534985 8.097218,31.671422 8.5094033,31.724115 C 11.518163,32.108961 13.373968,32.147539 15.76056,30.039827 C 19.12901,27.065506 19.683127,25.185502 20.034068,22.951704 C 20.293627,21.297527 21.655941,17.421123 22.247619,15.852571 C 23.080867,13.643616 22.556758,18.089853 22.318585,18.673238 C 20.924543,22.100151 21.486437,26.72018 17.942032,30.365393 C 15.509749,32.86736 12.310453,33.796071 7.1221663,32.621775 C 5.7388178,32.30844 6.239509,31.841732 4.657845,31.358088 C 4.1834429,31.143553 1.6402954,30.997707 1.3486549,30.995825 C 0.70898981,30.992061 0.10626602,30.860329 -0.42938057,30.607215 z M 4.2543673,5.1321285 C 2.8544925,6.7006803 3.1305788,7.9154375 2.2021896,9.2289942 C 0.37749172,11.810941 1.4380914,15.378055 1.0521537,17.983526 C 0.55247613,21.363393 0.50913089,20.094485 -0.0071428722,17.974697 C -0.76834557,14.849245 -0.21551087,13.71635 -0.090105372,12.391502 C 0.60497135,9.1141985 1.2125559,7.7404222 2.8554645,5.6731707 C 4.2115933,3.9672413 6.135449,3.0215936 4.2543673,5.1321285 z M 24.022738,36.434475 C 23.474454,37.067729 22.882424,37.657701 22.248591,38.195919 L 21.462134,38.491375 C 18.22784,39.695783 16.567433,39.805873 11.843827,39.067233 C 9.918999,38.766131 7.2913178,38.39634 5.4841183,39.262008 C 6.5702412,39.494461 10.381694,38.345449 11.56288,39.970538 C 11.446224,40.140849 9.1976753,39.867976 7.0823087,40.331861 C 6.5699934,40.042991 6.0751766,39.715542 5.5978581,39.351398 C 5.1390103,38.993839 4.8036236,38.704969 4.4789305,38.398222 C 6.9432934,37.015037 10.891135,37.492095 13.335083,37.804487 C 17.567761,38.346471 19.246638,38.16581 21.951118,37.173114 C 22.683136,36.904005 23.374324,36.654655 24.022738,36.434475 z M 26.080749,7.8825045 C 27.13746,9.9657525 28.24375,11.559709 28.24375,14.719395 C 28.24375,18.197241 25.745362,19.892699 25.346787,22.207418 C 24.973487,24.37441 24.914187,26.178198 24.585605,26.178198 C 24.11898,26.178198 23.970243,24.110005 24.041208,22.659071 C 24.113147,21.19026 24.300417,20.389257 24.641637,19.294941 C 25.02563,18.066069 25.608953,15.315973 25.490352,13.235548 C 25.33481,10.489877 25.576852,11.073882 26.289427,12.729942 C 26.756052,13.812967 26.247915,15.934534 26.289427,17.469211 C 27.316002,15.633392 27.121554,12.867259 26.336068,10.86211 C 26.073591,10.189336 25.713282,8.8290928 26.080749,7.8825045 z M 24.608294,9.2431681 C 24.472195,8.6390829 23.70969,6.477977 22.713252,5.1870035 C 21.219079,3.2533658 22.564494,3.6570102 23.635787,4.8313069 C 24.682776,5.9792572 25.458582,7.3442852 25.487746,8.6644279 C 25.547046,11.377166 25.108944,11.455325 24.608294,9.2431681 z M 28.310827,16.859099 C 28.588858,16.49966 28.861055,18.750394 28.357489,19.540787 C 27.013026,21.649439 27.496178,25.113051 26.626116,27.878481 C 25.240824,32.27833 20.835106,35.602682 15.985124,35.513292 C 19.529529,34.338995 22.700634,33.797953 24.16953,26.824625 C 24.298825,26.210189 25.161109,26.541401 24.3834,29.44421 C 25.240824,28.207811 25.985479,25.109287 26.098247,22.60826 C 26.173102,20.914563 27.715881,18.48693 28.310827,16.859099 z M 0.33666203,7.0620024 C 3.1023869,1.995966 8.6775827,0.52715408 13.200929,0.52715408 C 16.027898,0.52715408 18.494205,1.0117396 20.804971,2.3394101 C 21.160772,2.5991103 21.699335,2.9199718 21.989031,3.2097822 C 22.925198,4.1497842 21.355919,3.7289582 19.391486,2.8597515 C 15.788463,1.2655141 13.210649,1.5085776 11.04376,1.8557856 C 9.4407091,2.112663 8.4189947,3.395148 7.616011,4.1733077 C 4.6568312,7.0356559 4.1960391,9.5950208 4.5518406,12.806458 C 4.9931901,16.791351 4.2543673,21.000189 3.3230616,23.294208 C 2.8467153,24.469446 2.9099042,25.995654 3.1228018,26.962944 C 3.5077673,28.707452 5.0036733,29.433225 3.1344674,29.192978 C -0.13966347,28.772157 -0.13773997,24.273729 0.98021562,21.094283 C 2.1224745,17.845207 1.495243,15.951027 1.7355647,13.562036 C 2.8026799,2.8737448 3.1130804,15.825944 3.0518358,16.393333 C 2.6940901,19.711097 2.2203141,20.592698 1.7248713,22.0691 C 0.65905915,25.245183 1.9177265,27.094796 2.2524513,27.350994 C 0.89725312,23.033886 3.2657056,21.64003 3.4523556,16.633273 C 3.4980459,15.417575 3.5174886,14.673289 3.3318108,13.031344 C 2.7611674,7.9643665 4.0677172,5.041798 6.9588475,2.6941455 C 5.2051155,2.7110825 3.8587082,3.9794735 2.6688146,5.1321285 C 1.363237,6.3958147 0.15098419,9.2779223 -0.22620427,10.387294 C -0.79004277,12.046176 -1.2848596,10.030677 0.33666203,7.0620024 z M -1.1234851,28.497622 C -2.0265988,25.35299 -2.4786417,21.846097 -2.4037873,18.200883 C -2.3746233,16.749949 -2.2443571,15.155993 -1.7971749,13.290103 C -0.92614167,9.6543002 -0.69568297,11.570518 -0.75405287,12.016887 C -1.906054,20.826496 1.6007898,19.123308 -0.53825967,25.728487 C -1.2848596,25.186504 -0.49674737,21.494805 -1.669846,19.297342 C -1.3645539,21.71935 -2.0304874,25.727486 0.6156649,28.255799 C 1.3719861,28.979384 2.8544925,29.37364 0.70898981,29.192978 C -0.027888672,29.130876 -0.63158467,28.886231 -1.1234851,28.497622 z M 0.47373313,32.736569 C 0.3036094,32.382775 0.14126284,32.020512 -0.015250972,31.650721 C 0.99382545,31.532162 3.0430867,31.426777 4.813345,32.172003 C 5.8418641,32.604837 3.7828816,32.394066 1.9863756,32.504156 C 1.3428221,32.542735 0.81203619,32.697049 0.47373313,32.736569 z M 1.3272679,34.351227 C 1.1308965,34.014369 0.94230231,33.668102 0.76051305,33.313367 C 5.2070598,32.522034 7.1591074,33.303958 10.615049,33.590945 C 14.176952,33.887342 18.036329,32.081673 19.249554,30.005012 C 19.872692,28.937983 20.047677,28.679223 20.173082,28.398823 C 20.281962,28.156059 20.353899,27.8973 20.648457,27.082444 C 21.301732,25.276774 21.270624,27.738281 21.106332,28.345189 C 19.995182,32.442996 19.062904,31.720351 17.197377,33.526961 C 21.488381,31.992284 22.140685,28.921987 21.581706,24.645402 C 21.447552,23.621656 22.24373,20.854343 22.609254,19.86447 C 22.609254,19.86447 23.377241,17.382263 23.382101,12.981474 C 23.385017,10.110657 22.446907,5.6863438 18.607945,4.0349891 C 17.32181,3.4817147 15.535997,1.961151 15.535997,1.961151 C 16.331576,2.384936 18.250199,2.6518031 20.106978,3.7583519 C 20.177944,3.8006944 24.197722,6.0420202 24.599214,11.907858 C 24.788781,14.679876 24.809506,14.809385 24.622856,16.615054 C 24.622856,16.615054 24.508806,18.471876 23.856503,20.006553 C 23.541531,20.860929 23.2042,23.380774 23.390851,24.645402 C 23.822478,27.572675 22.050276,34.880978 14.832172,34.880978 C 11.643568,34.880978 9.7031857,34.471668 8.1769331,34.235492 C 6.7945567,34.020957 4.0006399,33.900516 1.3272679,34.351227 z M 3.9160641,37.83648 C 3.5466527,37.449752 3.1918233,37.039501 2.851576,36.606667 C 3.8975936,36.013873 4.8162614,36.004464 6.6798447,36.055275 C 8.8146538,36.055275 12.031449,36.901182 11.04376,37.179702 C 10.996125,37.191934 6.4669471,36.563384 3.9160641,37.83648 z M 14.719404,41.637889 C 14.296525,41.700932 13.867813,41.747979 13.430353,41.776207 C 11.348039,41.911704 9.4173774,41.49957 7.6714227,40.64049 C 8.5230132,40.522871 10.16981,40.466415 11.73106,40.686596 C 12.655561,40.817387 13.709355,41.272803 14.719404,41.637889 z M 20.747615,39.325051 C 19.318575,40.268817 17.725246,40.977347 15.991929,41.391361 C 14.720376,41.014044 11.970742,40.569899 11.991882,39.739346 C 12.007714,39.117287 15.479614,40.315864 17.475407,40.060868 C 18.84223,39.886794 19.878525,39.619567 20.747615,39.325051 z M 26.747633,31.987579 C 27.295917,31.456887 26.637782,34.608104 23.560001,35.921661 C 21.475743,36.660301 18.380466,38.308833 13.057053,36.902123 C 12.403778,36.72899 10.334101,36.181361 9.8733094,36.088208 C 6.2861299,35.366505 4.4235188,35.58198 2.3927281,35.996936 C 2.1564992,35.669488 1.9280475,35.329808 1.7073728,34.979777 C 2.3616198,34.715372 4.0055005,34.612809 5.186645,34.610927 C 8.9478367,34.604341 13.98933,35.964944 15.98318,36.055275 C 20.657206,36.266987 23.666937,32.984978 24.040237,32.984978 C 24.972514,32.984978 23.166287,34.616574 22.664665,35.067285 C 22.237898,35.45213 24.347431,34.500837 26.747633,31.987579 z M 28.517892,25.005783 C 28.394431,27.133255 28.234028,30.085933 26.454048,31.562273 C 23.614441,33.917452 24.785865,32.262334 26.025337,30.618507 C 28.180561,27.758982 27.284252,21.317287 28.69482,20.069596 C 28.711346,21.421731 28.607328,23.483337 28.517892,25.005783 z"
+ style="fill:#a1a1a1;fill-opacity:1"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ sodipodi:nodetypes="cscssscccssssssscsssscsscsssccssscscssssscsssscssssssscsssscsssssscscsscssssssscsccssscsccccscccscssccssssssscsccsssccsscscsccscsssssssssssscsscssccsssccsscccsscccssssscscsscssccsssccccsccscscccsscccssccssssccsscc" />
+<circle
+ clip-rule="evenodd"
+ cx="26.184"
+ cy="33.865002"
+ r="10"
+ id="circle2428"
+ sodipodi:cx="26.184"
+ sodipodi:cy="33.865002"
+ sodipodi:rx="10"
+ sodipodi:ry="10"
+ style="fill:url(#radialGradient84134);fill-opacity:1;fill-rule:evenodd;stroke:#448c00;stroke-width:1.31732059;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ transform="matrix(1.1263785,0,0,1.1511056,-2.2713556,-9.1997707)" /><path
+ sodipodi:type="arc"
+ style="opacity:0.50746268;fill:url(#linearGradient84277);fill-opacity:1;stroke:none;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path3253"
+ sodipodi:cx="26.455547"
+ sodipodi:cy="27.394291"
+ sodipodi:rx="6.1445141"
+ sodipodi:ry="3.072257"
+ d="M 32.600061,27.394291 A 6.1445141,3.072257 0 1 1 20.311033,27.394291 A 6.1445141,3.072257 0 1 1 32.600061,27.394291 z"
+ transform="matrix(1.1111101,0,0,1.2758999,-2.2387648,-10.924499)" /><path
+ clip-rule="evenodd"
+ d="M 21.777021,33.575871 C 22.428021,34.222871 23.330021,35.596871 24.012021,36.209871 C 25.264021,34.898871 27.599021,31.912871 31.077021,29.499871 C 31.754021,29.029871 33.458021,29.462871 32.557021,30.487871 C 29.846021,33.287871 27.332021,36.692871 25.385021,39.387871 C 24.468021,40.656871 23.706021,39.994871 22.908021,38.978871 C 21.912021,37.682871 20.897021,36.071871 20.509021,35.011871 C 20.282021,34.392871 20.974021,32.785871 21.777021,33.575871 z"
+ id="path2430"
+ style="opacity:0.42786069;fill:#398800;fill-opacity:1;fill-rule:evenodd;stroke:#398800;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;filter:url(#filter3471)"
+ transform="matrix(1.1263785,0,0,1.1511056,-2.2713556,-9.1997707)" /><path
+ clip-rule="evenodd"
+ d="M 21.969435,28.185201 C 22.702707,28.929966 23.718701,30.511585 24.486892,31.217213 C 25.897117,29.708113 28.527211,26.270911 32.444755,23.493294 C 33.207314,22.952275 35.126663,23.450703 34.111795,24.630586 C 31.058183,27.853682 28.226468,31.773196 26.033409,34.875426 C 25.00052,36.33618 24.142219,35.574148 23.243369,34.404624 C 22.121497,32.912791 20.978222,31.05836 20.541188,29.838188 C 20.2855,29.125654 21.064954,27.275827 21.969435,28.185201 z"
+ id="path3469"
+ style="fill:#ffffff;fill-rule:evenodd" /><path
+ sodipodi:type="arc"
+ style="opacity:0.36815945;fill:none;fill-opacity:1;stroke:url(#linearGradient84279);stroke-width:1.2184273;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path84102"
+ sodipodi:cx="28.185518"
+ sodipodi:cy="31.917336"
+ sodipodi:rx="10.027505"
+ sodipodi:ry="10.240856"
+ d="M 38.213023,31.917336 A 10.027505,10.240856 0 1 1 18.158013,31.917336 A 10.027505,10.240856 0 1 1 38.213023,31.917336 z"
+ transform="matrix(1.0116992,0,0,1.0189783,-1.4418411,-2.7101136)" /></svg> \ No newline at end of file
diff --git a/capplets/about-me/icons/right-index-finger.png b/capplets/about-me/icons/right-index-finger.png
new file mode 100644
index 00000000..4aaeaac4
--- /dev/null
+++ b/capplets/about-me/icons/right-index-finger.png
Binary files differ
diff --git a/capplets/about-me/icons/right-index-finger.svg b/capplets/about-me/icons/right-index-finger.svg
new file mode 100644
index 00000000..5a621a2e
--- /dev/null
+++ b/capplets/about-me/icons/right-index-finger.svg
@@ -0,0 +1,179 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.0"
+ x="0px"
+ y="0px"
+ width="48"
+ height="48"
+ viewBox="0 0 40.425 46.214"
+ enable-background="new 0 0 40.425 46.214"
+ xml:space="preserve"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ sodipodi:docname="right-index-finger.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"><metadata
+ id="metadata44"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
+ id="defs42"><inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 23.107 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="40.424999 : 23.107 : 1"
+ inkscape:persp3d-origin="20.2125 : 15.404667 : 1"
+ id="perspective46" />
+
+
+
+
+
+
+<radialGradient
+ r="8.341651"
+ fy="9.3411446"
+ fx="38.658855"
+ cy="9.3411446"
+ cx="38.658855"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient2479"
+ xlink:href="#linearGradient2378"
+ inkscape:collect="always" /><linearGradient
+ id="linearGradient2378"><stop
+ id="stop2386"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" /><stop
+ style="stop-color:#27dc16;stop-opacity:1;"
+ offset="1"
+ id="stop2382" /></linearGradient><linearGradient
+ id="linearGradient3702"><stop
+ id="stop3704"
+ offset="0"
+ style="stop-color:black;stop-opacity:0;" /><stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0.5"
+ id="stop3710" /><stop
+ id="stop3706"
+ offset="1"
+ style="stop-color:black;stop-opacity:0;" /></linearGradient><linearGradient
+ id="linearGradient6732"><stop
+ id="stop6734"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" /><stop
+ id="stop6736"
+ offset="1"
+ style="stop-color:#dddddd;stop-opacity:1;" /></linearGradient><linearGradient
+ id="linearGradient4585"><stop
+ id="stop4587"
+ offset="0"
+ style="stop-color:#9e9e9e;stop-opacity:1;" /><stop
+ id="stop4589"
+ offset="1"
+ style="stop-color:#dddddd;stop-opacity:0;" /></linearGradient><inkscape:perspective
+ id="perspective2516"
+ inkscape:persp3d-origin="24 : 16 : 1"
+ inkscape:vp_z="48 : 24 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 24 : 1"
+ sodipodi:type="inkscape:persp3d" /><radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2378"
+ id="radialGradient86956"
+ cx="26.49"
+ cy="5.5700002"
+ fx="26.49"
+ fy="5.5700002"
+ r="4.0552225"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)" /><radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2378"
+ id="radialGradient86964"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)"
+ cx="26.49"
+ cy="5.5700002"
+ fx="26.49"
+ fy="5.5700002"
+ r="4.0552225" /><radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2378"
+ id="radialGradient86966"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)"
+ cx="26.49"
+ cy="5.5700002"
+ fx="26.49"
+ fy="5.5700002"
+ r="4.0552225" /></defs><sodipodi:namedview
+ inkscape:window-height="922"
+ inkscape:window-width="1302"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ guidetolerance="10.0"
+ gridtolerance="10.0"
+ objecttolerance="10.0"
+ borderopacity="1.0"
+ bordercolor="#666666"
+ pagecolor="#ffffff"
+ id="base"
+ showgrid="false"
+ inkscape:zoom="11.122171"
+ inkscape:cx="15.672125"
+ inkscape:cy="30.299841"
+ inkscape:window-x="36"
+ inkscape:window-y="91"
+ inkscape:current-layer="svg2" />
+<g
+ id="g35"
+ style="fill:url(#radialGradient86956);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ transform="matrix(-1.1605241,0,0,1.3370602,44.823901,-0.7984997)">
+ <circle
+ style="fill:url(#radialGradient86964);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ sodipodi:ry="3.829"
+ sodipodi:rx="3.829"
+ sodipodi:cy="5.5700002"
+ sodipodi:cx="26.49"
+ id="circle37"
+ r="3.829"
+ cy="5.5700002"
+ cx="26.49"
+ stroke-miterlimit="3.8637" />
+ <path
+ style="fill:url(#radialGradient86966);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path39"
+ stroke-miterlimit="3.8637"
+ d="" />
+ </g><g
+ id="Background"
+ transform="matrix(-1,0,0,1,40.436754,0)">
+</g>
+<g
+ id="Guides"
+ display="none"
+ style="display:none">
+</g>
+<g
+ id="g7"
+ style="fill:#2f2f2f;fill-opacity:1"
+ transform="matrix(-1,0,0,1,40.436754,0)">
+ <path
+ style="fill:#2f2f2f;fill-opacity:1;fill-rule:evenodd"
+ id="path9"
+ d="M 20.569,13.286 C 20.843,15.459 20.791,17.834 20.82,18.542 C 20.865,18.917 21.913,19.241 22.094,18.877 C 22.301,17.514 22.586,14.847 22.92,13.455 C 23.372,9.917 23.886,8.247 24.072,7.257 C 24.58,4.567 25.014,3.12 26.762,3.12 C 28.384,3.12 28.623,5.167 28.153,8.165 C 28.025,9.379 28.036,12.24 27.433,14.894 C 27.165,16.691 26.962,21.278 27.139,24.981 C 27.189,26.045 27.669,27.315 28.242,27.945 C 29.462,27.773 30.379,24.377 31.988,22.847 C 32.809,21.464 34.883,19.299 36.951,19.299 C 39.243,19.299 39.292,21 38.345,22.262 C 37.187,23.806 36.525,24.528 36.079,25.802 C 35.633,27.076 33.758,29.778 33.471,31.209 C 32.902,34.054 32.471,35.105 29.284,37.661 C 27.783,38.865 27.302,39.637 26.855,40.401 C 26.347,41.273 26.409,44.721 26.409,46.212 L 10.64,46.212 C 10.64,46.212 10.767,43.587 10.513,42.058 C 10.461,41.746 10.105,39.613 9.176,38.231 C 8.317,36.954 5.902,32.306 5.902,26.836 C 5.902,24.026 4.39,21.718 3.854,19.533 C 3.591,17.833 2.638,15.423 2.57,14.709 C 1.684,11.559 2.132,10.118 3.741,10.118 C 5.132,10.118 5.528,11.927 6.093,13.622 C 6.258,14.52 7.505,16.934 7.788,18.233 C 8.038,19.088 8.897,21.556 9.437,21.727 C 9.75,21.784 10.151,21.523 10.291,21.043 C 10.52,20.26 9.818,18.945 9.539,15.26 C 9.087,12.343 9.17,10.139 9.116,8.949 C 8.653,5.424 9.133,3.598 10.693,3.598 C 12.176,3.598 12.568,4.455 13.02,7.936 C 13.189,9.518 13.754,12.095 14.037,14.864 C 14.213,16.364 14.639,18.601 14.98,19.17 C 15.285,19.503 15.919,19.198 15.9,18.848 C 15.894,16.377 15.732,14.977 15.958,12.999 C 15.845,10.287 16.219,7.823 16.219,6.467 C 16.219,3.494 16.502,1.473 18.358,1.473 C 20.333,1.473 20.287,3.776 20.287,6.806 C 20.399,7.545 20.456,10.087 20.569,13.286 z"
+ clip-rule="evenodd" />
+ </g>
+<g
+ style="display:inline"
+ inkscape:label="Base"
+ id="layer1"
+ transform="matrix(-1,0,0,1,92.903401,2.6102791)" /></svg> \ No newline at end of file
diff --git a/capplets/about-me/icons/right-little-finger.png b/capplets/about-me/icons/right-little-finger.png
new file mode 100644
index 00000000..17946afc
--- /dev/null
+++ b/capplets/about-me/icons/right-little-finger.png
Binary files differ
diff --git a/capplets/about-me/icons/right-little-finger.svg b/capplets/about-me/icons/right-little-finger.svg
new file mode 100644
index 00000000..9fcec2af
--- /dev/null
+++ b/capplets/about-me/icons/right-little-finger.svg
@@ -0,0 +1,182 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.0"
+ x="0px"
+ y="0px"
+ width="48"
+ height="48"
+ viewBox="0 0 40.425 46.214"
+ enable-background="new 0 0 40.425 46.214"
+ xml:space="preserve"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ sodipodi:docname="right-pinky-finger.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ inkscape:export-filename="/Users/mlanglie/Desktop/Fingerprint Enrollment Icons/Vector/left-ring-finger.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"><metadata
+ id="metadata44"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
+ id="defs42"><inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 23.107 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="40.424999 : 23.107 : 1"
+ inkscape:persp3d-origin="20.2125 : 15.404667 : 1"
+ id="perspective46" />
+
+
+
+
+
+
+<radialGradient
+ r="8.341651"
+ fy="9.3411446"
+ fx="38.658855"
+ cy="9.3411446"
+ cx="38.658855"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient2479"
+ xlink:href="#linearGradient2378"
+ inkscape:collect="always" /><linearGradient
+ id="linearGradient2378"><stop
+ id="stop2386"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" /><stop
+ style="stop-color:#27dc16;stop-opacity:1;"
+ offset="1"
+ id="stop2382" /></linearGradient><linearGradient
+ id="linearGradient3702"><stop
+ id="stop3704"
+ offset="0"
+ style="stop-color:black;stop-opacity:0;" /><stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0.5"
+ id="stop3710" /><stop
+ id="stop3706"
+ offset="1"
+ style="stop-color:black;stop-opacity:0;" /></linearGradient><linearGradient
+ id="linearGradient6732"><stop
+ id="stop6734"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" /><stop
+ id="stop6736"
+ offset="1"
+ style="stop-color:#dddddd;stop-opacity:1;" /></linearGradient><linearGradient
+ id="linearGradient4585"><stop
+ id="stop4587"
+ offset="0"
+ style="stop-color:#9e9e9e;stop-opacity:1;" /><stop
+ id="stop4589"
+ offset="1"
+ style="stop-color:#dddddd;stop-opacity:0;" /></linearGradient><inkscape:perspective
+ id="perspective2516"
+ inkscape:persp3d-origin="24 : 16 : 1"
+ inkscape:vp_z="48 : 24 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 24 : 1"
+ sodipodi:type="inkscape:persp3d" /><radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2378"
+ id="radialGradient86956"
+ cx="26.49"
+ cy="5.5700002"
+ fx="26.49"
+ fy="5.5700002"
+ r="4.0552225"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)" /><radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2378"
+ id="radialGradient86964"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)"
+ cx="26.49"
+ cy="5.5700002"
+ fx="26.49"
+ fy="5.5700002"
+ r="4.0552225" /><radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2378"
+ id="radialGradient86966"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)"
+ cx="26.49"
+ cy="5.5700002"
+ fx="26.49"
+ fy="5.5700002"
+ r="4.0552225" /></defs><sodipodi:namedview
+ inkscape:window-height="933"
+ inkscape:window-width="1054"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ guidetolerance="10.0"
+ gridtolerance="10.0"
+ objecttolerance="10.0"
+ borderopacity="1.0"
+ bordercolor="#666666"
+ pagecolor="#ffffff"
+ id="base"
+ showgrid="false"
+ inkscape:zoom="11.122171"
+ inkscape:cx="22.316511"
+ inkscape:cy="30.299841"
+ inkscape:window-x="346"
+ inkscape:window-y="109"
+ inkscape:current-layer="svg2" />
+<g
+ id="g35"
+ style="fill:url(#radialGradient86956);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ transform="matrix(-1.1074589,0,0,1.2726911,65.968411,5.5330271)">
+ <circle
+ style="fill:url(#radialGradient86964);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ sodipodi:ry="3.829"
+ sodipodi:rx="3.829"
+ sodipodi:cy="5.5700002"
+ sodipodi:cx="26.49"
+ id="circle37"
+ r="3.829"
+ cy="5.5700002"
+ cx="26.49"
+ stroke-miterlimit="3.8637" />
+ <path
+ style="fill:url(#radialGradient86966);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path39"
+ stroke-miterlimit="3.8637"
+ d="" />
+ </g><g
+ id="Background"
+ transform="matrix(-1,0,0,1,40.436756,0)">
+</g>
+<g
+ id="Guides"
+ display="none"
+ style="display:none">
+</g>
+<g
+ id="g7"
+ style="fill:#2f2f2f;fill-opacity:1"
+ transform="matrix(-1,0,0,1,40.436756,0)">
+ <path
+ style="fill:#2f2f2f;fill-opacity:1;fill-rule:evenodd"
+ id="path9"
+ d="M 20.569,13.286 C 20.843,15.459 20.791,17.834 20.82,18.542 C 20.865,18.917 21.913,19.241 22.094,18.877 C 22.301,17.514 22.586,14.847 22.92,13.455 C 23.372,9.917 23.886,8.247 24.072,7.257 C 24.58,4.567 25.014,3.12 26.762,3.12 C 28.384,3.12 28.623,5.167 28.153,8.165 C 28.025,9.379 28.036,12.24 27.433,14.894 C 27.165,16.691 26.962,21.278 27.139,24.981 C 27.189,26.045 27.669,27.315 28.242,27.945 C 29.462,27.773 30.379,24.377 31.988,22.847 C 32.809,21.464 34.883,19.299 36.951,19.299 C 39.243,19.299 39.292,21 38.345,22.262 C 37.187,23.806 36.525,24.528 36.079,25.802 C 35.633,27.076 33.758,29.778 33.471,31.209 C 32.902,34.054 32.471,35.105 29.284,37.661 C 27.783,38.865 27.302,39.637 26.855,40.401 C 26.347,41.273 26.409,44.721 26.409,46.212 L 10.64,46.212 C 10.64,46.212 10.767,43.587 10.513,42.058 C 10.461,41.746 10.105,39.613 9.176,38.231 C 8.317,36.954 5.902,32.306 5.902,26.836 C 5.902,24.026 4.39,21.718 3.854,19.533 C 3.591,17.833 2.638,15.423 2.57,14.709 C 1.684,11.559 2.132,10.118 3.741,10.118 C 5.132,10.118 5.528,11.927 6.093,13.622 C 6.258,14.52 7.505,16.934 7.788,18.233 C 8.038,19.088 8.897,21.556 9.437,21.727 C 9.75,21.784 10.151,21.523 10.291,21.043 C 10.52,20.26 9.818,18.945 9.539,15.26 C 9.087,12.343 9.17,10.139 9.116,8.949 C 8.653,5.424 9.133,3.598 10.693,3.598 C 12.176,3.598 12.568,4.455 13.02,7.936 C 13.189,9.518 13.754,12.095 14.037,14.864 C 14.213,16.364 14.639,18.601 14.98,19.17 C 15.285,19.503 15.919,19.198 15.9,18.848 C 15.894,16.377 15.732,14.977 15.958,12.999 C 15.845,10.287 16.219,7.823 16.219,6.467 C 16.219,3.494 16.502,1.473 18.358,1.473 C 20.333,1.473 20.287,3.776 20.287,6.806 C 20.399,7.545 20.456,10.087 20.569,13.286 z"
+ clip-rule="evenodd" />
+ </g>
+<g
+ style="display:inline"
+ inkscape:label="Base"
+ id="layer1"
+ transform="matrix(-1,0,0,1,92.903403,2.6102791)" /></svg> \ No newline at end of file
diff --git a/capplets/about-me/icons/right-middle-finger.png b/capplets/about-me/icons/right-middle-finger.png
new file mode 100644
index 00000000..71bd41ba
--- /dev/null
+++ b/capplets/about-me/icons/right-middle-finger.png
Binary files differ
diff --git a/capplets/about-me/icons/right-middle-finger.svg b/capplets/about-me/icons/right-middle-finger.svg
new file mode 100644
index 00000000..b33a654a
--- /dev/null
+++ b/capplets/about-me/icons/right-middle-finger.svg
@@ -0,0 +1,182 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.0"
+ x="0px"
+ y="0px"
+ width="48"
+ height="48"
+ viewBox="0 0 40.425 46.214"
+ enable-background="new 0 0 40.425 46.214"
+ xml:space="preserve"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ sodipodi:docname="right-middle-finger.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ inkscape:export-filename="/Users/mlanglie/Desktop/Fingerprint Enrollment Icons/Vector/left-index-finger.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"><metadata
+ id="metadata44"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
+ id="defs42"><inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 23.107 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="40.424999 : 23.107 : 1"
+ inkscape:persp3d-origin="20.2125 : 15.404667 : 1"
+ id="perspective46" />
+
+
+
+
+
+
+<radialGradient
+ r="8.341651"
+ fy="9.3411446"
+ fx="38.658855"
+ cy="9.3411446"
+ cx="38.658855"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient2479"
+ xlink:href="#linearGradient2378"
+ inkscape:collect="always" /><linearGradient
+ id="linearGradient2378"><stop
+ id="stop2386"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" /><stop
+ style="stop-color:#27dc16;stop-opacity:1;"
+ offset="1"
+ id="stop2382" /></linearGradient><linearGradient
+ id="linearGradient3702"><stop
+ id="stop3704"
+ offset="0"
+ style="stop-color:black;stop-opacity:0;" /><stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0.5"
+ id="stop3710" /><stop
+ id="stop3706"
+ offset="1"
+ style="stop-color:black;stop-opacity:0;" /></linearGradient><linearGradient
+ id="linearGradient6732"><stop
+ id="stop6734"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" /><stop
+ id="stop6736"
+ offset="1"
+ style="stop-color:#dddddd;stop-opacity:1;" /></linearGradient><linearGradient
+ id="linearGradient4585"><stop
+ id="stop4587"
+ offset="0"
+ style="stop-color:#9e9e9e;stop-opacity:1;" /><stop
+ id="stop4589"
+ offset="1"
+ style="stop-color:#dddddd;stop-opacity:0;" /></linearGradient><inkscape:perspective
+ id="perspective2516"
+ inkscape:persp3d-origin="24 : 16 : 1"
+ inkscape:vp_z="48 : 24 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 24 : 1"
+ sodipodi:type="inkscape:persp3d" /><radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2378"
+ id="radialGradient86956"
+ cx="26.49"
+ cy="5.5700002"
+ fx="26.49"
+ fy="5.5700002"
+ r="4.0552225"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)" /><radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2378"
+ id="radialGradient86964"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)"
+ cx="26.49"
+ cy="5.5700002"
+ fx="26.49"
+ fy="5.5700002"
+ r="4.0552225" /><radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2378"
+ id="radialGradient86966"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)"
+ cx="26.49"
+ cy="5.5700002"
+ fx="26.49"
+ fy="5.5700002"
+ r="4.0552225" /></defs><sodipodi:namedview
+ inkscape:window-height="933"
+ inkscape:window-width="1054"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ guidetolerance="10.0"
+ gridtolerance="10.0"
+ objecttolerance="10.0"
+ borderopacity="1.0"
+ bordercolor="#666666"
+ pagecolor="#ffffff"
+ id="base"
+ showgrid="false"
+ inkscape:zoom="11.122171"
+ inkscape:cx="22.316511"
+ inkscape:cy="30.299841"
+ inkscape:window-x="362"
+ inkscape:window-y="121"
+ inkscape:current-layer="svg2" />
+<g
+ id="g35"
+ style="fill:url(#radialGradient86956);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ transform="matrix(-1.1824583,0,0,1.3363867,53.282364,-2.0066594)">
+ <circle
+ style="fill:url(#radialGradient86964);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ sodipodi:ry="3.829"
+ sodipodi:rx="3.829"
+ sodipodi:cy="5.5700002"
+ sodipodi:cx="26.49"
+ id="circle37"
+ r="3.829"
+ cy="5.5700002"
+ cx="26.49"
+ stroke-miterlimit="3.8637" />
+ <path
+ style="fill:url(#radialGradient86966);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path39"
+ stroke-miterlimit="3.8637"
+ d="" />
+ </g><g
+ id="Background"
+ transform="matrix(-1,0,0,1,40.436756,0)">
+</g>
+<g
+ id="Guides"
+ display="none"
+ style="display:none">
+</g>
+<g
+ id="g7"
+ style="fill:#2f2f2f;fill-opacity:1"
+ transform="matrix(-1,0,0,1,40.436756,0)">
+ <path
+ style="fill:#2f2f2f;fill-opacity:1;fill-rule:evenodd"
+ id="path9"
+ d="M 20.569,13.286 C 20.843,15.459 20.791,17.834 20.82,18.542 C 20.865,18.917 21.913,19.241 22.094,18.877 C 22.301,17.514 22.586,14.847 22.92,13.455 C 23.372,9.917 23.886,8.247 24.072,7.257 C 24.58,4.567 25.014,3.12 26.762,3.12 C 28.384,3.12 28.623,5.167 28.153,8.165 C 28.025,9.379 28.036,12.24 27.433,14.894 C 27.165,16.691 26.962,21.278 27.139,24.981 C 27.189,26.045 27.669,27.315 28.242,27.945 C 29.462,27.773 30.379,24.377 31.988,22.847 C 32.809,21.464 34.883,19.299 36.951,19.299 C 39.243,19.299 39.292,21 38.345,22.262 C 37.187,23.806 36.525,24.528 36.079,25.802 C 35.633,27.076 33.758,29.778 33.471,31.209 C 32.902,34.054 32.471,35.105 29.284,37.661 C 27.783,38.865 27.302,39.637 26.855,40.401 C 26.347,41.273 26.409,44.721 26.409,46.212 L 10.64,46.212 C 10.64,46.212 10.767,43.587 10.513,42.058 C 10.461,41.746 10.105,39.613 9.176,38.231 C 8.317,36.954 5.902,32.306 5.902,26.836 C 5.902,24.026 4.39,21.718 3.854,19.533 C 3.591,17.833 2.638,15.423 2.57,14.709 C 1.684,11.559 2.132,10.118 3.741,10.118 C 5.132,10.118 5.528,11.927 6.093,13.622 C 6.258,14.52 7.505,16.934 7.788,18.233 C 8.038,19.088 8.897,21.556 9.437,21.727 C 9.75,21.784 10.151,21.523 10.291,21.043 C 10.52,20.26 9.818,18.945 9.539,15.26 C 9.087,12.343 9.17,10.139 9.116,8.949 C 8.653,5.424 9.133,3.598 10.693,3.598 C 12.176,3.598 12.568,4.455 13.02,7.936 C 13.189,9.518 13.754,12.095 14.037,14.864 C 14.213,16.364 14.639,18.601 14.98,19.17 C 15.285,19.503 15.919,19.198 15.9,18.848 C 15.894,16.377 15.732,14.977 15.958,12.999 C 15.845,10.287 16.219,7.823 16.219,6.467 C 16.219,3.494 16.502,1.473 18.358,1.473 C 20.333,1.473 20.287,3.776 20.287,6.806 C 20.399,7.545 20.456,10.087 20.569,13.286 z"
+ clip-rule="evenodd" />
+ </g>
+<g
+ style="display:inline"
+ inkscape:label="Base"
+ id="layer1"
+ transform="matrix(-1,0,0,1,92.903403,2.6102791)" /></svg> \ No newline at end of file
diff --git a/capplets/about-me/icons/right-ring-finger.png b/capplets/about-me/icons/right-ring-finger.png
new file mode 100644
index 00000000..aa73ae6e
--- /dev/null
+++ b/capplets/about-me/icons/right-ring-finger.png
Binary files differ
diff --git a/capplets/about-me/icons/right-ring-finger.svg b/capplets/about-me/icons/right-ring-finger.svg
new file mode 100644
index 00000000..9e264fe6
--- /dev/null
+++ b/capplets/about-me/icons/right-ring-finger.svg
@@ -0,0 +1,182 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.0"
+ x="0px"
+ y="0px"
+ width="48"
+ height="48"
+ viewBox="0 0 40.425 46.214"
+ enable-background="new 0 0 40.425 46.214"
+ xml:space="preserve"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ sodipodi:docname="right-ring-finger.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ inkscape:export-filename="/Users/mlanglie/Desktop/Fingerprint Enrollment Icons/Vector/left-middle-finger.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"><metadata
+ id="metadata44"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
+ id="defs42"><inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 23.107 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="40.424999 : 23.107 : 1"
+ inkscape:persp3d-origin="20.2125 : 15.404667 : 1"
+ id="perspective46" />
+
+
+
+
+
+
+<radialGradient
+ r="8.341651"
+ fy="9.3411446"
+ fx="38.658855"
+ cy="9.3411446"
+ cx="38.658855"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient2479"
+ xlink:href="#linearGradient2378"
+ inkscape:collect="always" /><linearGradient
+ id="linearGradient2378"><stop
+ id="stop2386"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" /><stop
+ style="stop-color:#27dc16;stop-opacity:1;"
+ offset="1"
+ id="stop2382" /></linearGradient><linearGradient
+ id="linearGradient3702"><stop
+ id="stop3704"
+ offset="0"
+ style="stop-color:black;stop-opacity:0;" /><stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0.5"
+ id="stop3710" /><stop
+ id="stop3706"
+ offset="1"
+ style="stop-color:black;stop-opacity:0;" /></linearGradient><linearGradient
+ id="linearGradient6732"><stop
+ id="stop6734"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" /><stop
+ id="stop6736"
+ offset="1"
+ style="stop-color:#dddddd;stop-opacity:1;" /></linearGradient><linearGradient
+ id="linearGradient4585"><stop
+ id="stop4587"
+ offset="0"
+ style="stop-color:#9e9e9e;stop-opacity:1;" /><stop
+ id="stop4589"
+ offset="1"
+ style="stop-color:#dddddd;stop-opacity:0;" /></linearGradient><inkscape:perspective
+ id="perspective2516"
+ inkscape:persp3d-origin="24 : 16 : 1"
+ inkscape:vp_z="48 : 24 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 24 : 1"
+ sodipodi:type="inkscape:persp3d" /><radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2378"
+ id="radialGradient86956"
+ cx="26.49"
+ cy="5.5700002"
+ fx="26.49"
+ fy="5.5700002"
+ r="4.0552225"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)" /><radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2378"
+ id="radialGradient86964"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)"
+ cx="26.49"
+ cy="5.5700002"
+ fx="26.49"
+ fy="5.5700002"
+ r="4.0552225" /><radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2378"
+ id="radialGradient86966"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)"
+ cx="26.49"
+ cy="5.5700002"
+ fx="26.49"
+ fy="5.5700002"
+ r="4.0552225" /></defs><sodipodi:namedview
+ inkscape:window-height="933"
+ inkscape:window-width="1054"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ guidetolerance="10.0"
+ gridtolerance="10.0"
+ objecttolerance="10.0"
+ borderopacity="1.0"
+ bordercolor="#666666"
+ pagecolor="#ffffff"
+ id="base"
+ showgrid="false"
+ inkscape:zoom="11.122171"
+ inkscape:cx="22.316511"
+ inkscape:cy="30.299841"
+ inkscape:window-x="424"
+ inkscape:window-y="91"
+ inkscape:current-layer="svg2" />
+<g
+ id="g35"
+ style="fill:url(#radialGradient86956);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ transform="matrix(-1.1824583,0,0,1.3363867,61.073222,-0.7947482)">
+ <circle
+ style="fill:url(#radialGradient86964);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ sodipodi:ry="3.829"
+ sodipodi:rx="3.829"
+ sodipodi:cy="5.5700002"
+ sodipodi:cx="26.49"
+ id="circle37"
+ r="3.829"
+ cy="5.5700002"
+ cx="26.49"
+ stroke-miterlimit="3.8637" />
+ <path
+ style="fill:url(#radialGradient86966);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path39"
+ stroke-miterlimit="3.8637"
+ d="" />
+ </g><g
+ id="Background"
+ transform="matrix(-1,0,0,1,40.436756,0)">
+</g>
+<g
+ id="Guides"
+ display="none"
+ style="display:none">
+</g>
+<g
+ id="g7"
+ style="fill:#2f2f2f;fill-opacity:1"
+ transform="matrix(-1,0,0,1,40.436756,0)">
+ <path
+ style="fill:#2f2f2f;fill-opacity:1;fill-rule:evenodd"
+ id="path9"
+ d="M 20.569,13.286 C 20.843,15.459 20.791,17.834 20.82,18.542 C 20.865,18.917 21.913,19.241 22.094,18.877 C 22.301,17.514 22.586,14.847 22.92,13.455 C 23.372,9.917 23.886,8.247 24.072,7.257 C 24.58,4.567 25.014,3.12 26.762,3.12 C 28.384,3.12 28.623,5.167 28.153,8.165 C 28.025,9.379 28.036,12.24 27.433,14.894 C 27.165,16.691 26.962,21.278 27.139,24.981 C 27.189,26.045 27.669,27.315 28.242,27.945 C 29.462,27.773 30.379,24.377 31.988,22.847 C 32.809,21.464 34.883,19.299 36.951,19.299 C 39.243,19.299 39.292,21 38.345,22.262 C 37.187,23.806 36.525,24.528 36.079,25.802 C 35.633,27.076 33.758,29.778 33.471,31.209 C 32.902,34.054 32.471,35.105 29.284,37.661 C 27.783,38.865 27.302,39.637 26.855,40.401 C 26.347,41.273 26.409,44.721 26.409,46.212 L 10.64,46.212 C 10.64,46.212 10.767,43.587 10.513,42.058 C 10.461,41.746 10.105,39.613 9.176,38.231 C 8.317,36.954 5.902,32.306 5.902,26.836 C 5.902,24.026 4.39,21.718 3.854,19.533 C 3.591,17.833 2.638,15.423 2.57,14.709 C 1.684,11.559 2.132,10.118 3.741,10.118 C 5.132,10.118 5.528,11.927 6.093,13.622 C 6.258,14.52 7.505,16.934 7.788,18.233 C 8.038,19.088 8.897,21.556 9.437,21.727 C 9.75,21.784 10.151,21.523 10.291,21.043 C 10.52,20.26 9.818,18.945 9.539,15.26 C 9.087,12.343 9.17,10.139 9.116,8.949 C 8.653,5.424 9.133,3.598 10.693,3.598 C 12.176,3.598 12.568,4.455 13.02,7.936 C 13.189,9.518 13.754,12.095 14.037,14.864 C 14.213,16.364 14.639,18.601 14.98,19.17 C 15.285,19.503 15.919,19.198 15.9,18.848 C 15.894,16.377 15.732,14.977 15.958,12.999 C 15.845,10.287 16.219,7.823 16.219,6.467 C 16.219,3.494 16.502,1.473 18.358,1.473 C 20.333,1.473 20.287,3.776 20.287,6.806 C 20.399,7.545 20.456,10.087 20.569,13.286 z"
+ clip-rule="evenodd" />
+ </g>
+<g
+ style="display:inline"
+ inkscape:label="Base"
+ id="layer1"
+ transform="matrix(-1,0,0,1,92.903403,2.6102791)" /></svg> \ No newline at end of file
diff --git a/capplets/about-me/icons/right-thumb.png b/capplets/about-me/icons/right-thumb.png
new file mode 100644
index 00000000..1c967d61
--- /dev/null
+++ b/capplets/about-me/icons/right-thumb.png
Binary files differ
diff --git a/capplets/about-me/icons/right-thumb.svg b/capplets/about-me/icons/right-thumb.svg
new file mode 100644
index 00000000..0aa0f2e4
--- /dev/null
+++ b/capplets/about-me/icons/right-thumb.svg
@@ -0,0 +1,182 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.0"
+ x="0px"
+ y="0px"
+ width="48"
+ height="48"
+ viewBox="0 0 40.425 46.214"
+ enable-background="new 0 0 40.425 46.214"
+ xml:space="preserve"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ sodipodi:docname="right-thumb.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ inkscape:export-filename="/Users/mlanglie/Desktop/Fingerprint Enrollment Icons/Vector/left-pinky-finger.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"><metadata
+ id="metadata44"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
+ id="defs42"><inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 23.107 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="40.424999 : 23.107 : 1"
+ inkscape:persp3d-origin="20.2125 : 15.404667 : 1"
+ id="perspective46" />
+
+
+
+
+
+
+<radialGradient
+ r="8.341651"
+ fy="9.3411446"
+ fx="38.658855"
+ cy="9.3411446"
+ cx="38.658855"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient2479"
+ xlink:href="#linearGradient2378"
+ inkscape:collect="always" /><linearGradient
+ id="linearGradient2378"><stop
+ id="stop2386"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" /><stop
+ style="stop-color:#27dc16;stop-opacity:1;"
+ offset="1"
+ id="stop2382" /></linearGradient><linearGradient
+ id="linearGradient3702"><stop
+ id="stop3704"
+ offset="0"
+ style="stop-color:black;stop-opacity:0;" /><stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0.5"
+ id="stop3710" /><stop
+ id="stop3706"
+ offset="1"
+ style="stop-color:black;stop-opacity:0;" /></linearGradient><linearGradient
+ id="linearGradient6732"><stop
+ id="stop6734"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" /><stop
+ id="stop6736"
+ offset="1"
+ style="stop-color:#dddddd;stop-opacity:1;" /></linearGradient><linearGradient
+ id="linearGradient4585"><stop
+ id="stop4587"
+ offset="0"
+ style="stop-color:#9e9e9e;stop-opacity:1;" /><stop
+ id="stop4589"
+ offset="1"
+ style="stop-color:#dddddd;stop-opacity:0;" /></linearGradient><inkscape:perspective
+ id="perspective2516"
+ inkscape:persp3d-origin="24 : 16 : 1"
+ inkscape:vp_z="48 : 24 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 24 : 1"
+ sodipodi:type="inkscape:persp3d" /><radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2378"
+ id="radialGradient86956"
+ cx="26.49"
+ cy="5.5700002"
+ fx="26.49"
+ fy="5.5700002"
+ r="4.0552225"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)" /><radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2378"
+ id="radialGradient86964"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)"
+ cx="26.49"
+ cy="5.5700002"
+ fx="26.49"
+ fy="5.5700002"
+ r="4.0552225" /><radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2378"
+ id="radialGradient86966"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.0059869,5.3782029e-7,-9.45767e-7,1.1767077,-0.1585918,-0.9842761)"
+ cx="26.49"
+ cy="5.5700002"
+ fx="26.49"
+ fy="5.5700002"
+ r="4.0552225" /></defs><sodipodi:namedview
+ inkscape:window-height="933"
+ inkscape:window-width="1054"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ guidetolerance="10.0"
+ gridtolerance="10.0"
+ objecttolerance="10.0"
+ borderopacity="1.0"
+ bordercolor="#666666"
+ pagecolor="#ffffff"
+ id="base"
+ showgrid="false"
+ inkscape:zoom="11.122171"
+ inkscape:cx="22.316511"
+ inkscape:cy="30.299841"
+ inkscape:window-x="116"
+ inkscape:window-y="117"
+ inkscape:current-layer="svg2" />
+<g
+ id="g35"
+ style="fill:url(#radialGradient86956);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ transform="matrix(-1.1916623,0,0,1.4021101,35.910183,14.334323)">
+ <circle
+ style="fill:url(#radialGradient86964);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ sodipodi:ry="3.829"
+ sodipodi:rx="3.829"
+ sodipodi:cy="5.5700002"
+ sodipodi:cx="26.49"
+ id="circle37"
+ r="3.829"
+ cy="5.5700002"
+ cx="26.49"
+ stroke-miterlimit="3.8637" />
+ <path
+ style="fill:url(#radialGradient86966);fill-opacity:1;stroke:#31ae00;stroke-width:0.45244551;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path39"
+ stroke-miterlimit="3.8637"
+ d="" />
+ </g><g
+ id="Background"
+ transform="matrix(-1,0,0,1,40.436756,0)">
+</g>
+<g
+ id="Guides"
+ display="none"
+ style="display:none">
+</g>
+<g
+ id="g7"
+ style="fill:#2f2f2f;fill-opacity:1"
+ transform="matrix(-1,0,0,1,40.436756,0)">
+ <path
+ style="fill:#2f2f2f;fill-opacity:1;fill-rule:evenodd"
+ id="path9"
+ d="M 20.569,13.286 C 20.843,15.459 20.791,17.834 20.82,18.542 C 20.865,18.917 21.913,19.241 22.094,18.877 C 22.301,17.514 22.586,14.847 22.92,13.455 C 23.372,9.917 23.886,8.247 24.072,7.257 C 24.58,4.567 25.014,3.12 26.762,3.12 C 28.384,3.12 28.623,5.167 28.153,8.165 C 28.025,9.379 28.036,12.24 27.433,14.894 C 27.165,16.691 26.962,21.278 27.139,24.981 C 27.189,26.045 27.669,27.315 28.242,27.945 C 29.462,27.773 30.379,24.377 31.988,22.847 C 32.809,21.464 34.883,19.299 36.951,19.299 C 39.243,19.299 39.292,21 38.345,22.262 C 37.187,23.806 36.525,24.528 36.079,25.802 C 35.633,27.076 33.758,29.778 33.471,31.209 C 32.902,34.054 32.471,35.105 29.284,37.661 C 27.783,38.865 27.302,39.637 26.855,40.401 C 26.347,41.273 26.409,44.721 26.409,46.212 L 10.64,46.212 C 10.64,46.212 10.767,43.587 10.513,42.058 C 10.461,41.746 10.105,39.613 9.176,38.231 C 8.317,36.954 5.902,32.306 5.902,26.836 C 5.902,24.026 4.39,21.718 3.854,19.533 C 3.591,17.833 2.638,15.423 2.57,14.709 C 1.684,11.559 2.132,10.118 3.741,10.118 C 5.132,10.118 5.528,11.927 6.093,13.622 C 6.258,14.52 7.505,16.934 7.788,18.233 C 8.038,19.088 8.897,21.556 9.437,21.727 C 9.75,21.784 10.151,21.523 10.291,21.043 C 10.52,20.26 9.818,18.945 9.539,15.26 C 9.087,12.343 9.17,10.139 9.116,8.949 C 8.653,5.424 9.133,3.598 10.693,3.598 C 12.176,3.598 12.568,4.455 13.02,7.936 C 13.189,9.518 13.754,12.095 14.037,14.864 C 14.213,16.364 14.639,18.601 14.98,19.17 C 15.285,19.503 15.919,19.198 15.9,18.848 C 15.894,16.377 15.732,14.977 15.958,12.999 C 15.845,10.287 16.219,7.823 16.219,6.467 C 16.219,3.494 16.502,1.473 18.358,1.473 C 20.333,1.473 20.287,3.776 20.287,6.806 C 20.399,7.545 20.456,10.087 20.569,13.286 z"
+ clip-rule="evenodd" />
+ </g>
+<g
+ style="display:inline"
+ inkscape:label="Base"
+ id="layer1"
+ transform="matrix(-1,0,0,1,92.903403,2.6102791)" /></svg> \ No newline at end of file
diff --git a/capplets/about-me/mate-about-me-dialog.ui b/capplets/about-me/mate-about-me-dialog.ui
new file mode 100644
index 00000000..fdf79b6e
--- /dev/null
+++ b/capplets/about-me/mate-about-me-dialog.ui
@@ -0,0 +1,1622 @@
+<?xml version="1.0"?>
+<interface>
+ <requires lib="gtk+" version="2.16"/>
+ <!-- interface-naming-policy toplevel-contextual -->
+ <object class="GtkDialog" id="about-me-dialog">
+ <property name="border_width">5</property>
+ <property name="title" translatable="yes">About Me</property>
+ <property name="type_hint">dialog</property>
+ <property name="has_separator">False</property>
+ <child internal-child="vbox">
+ <object class="GtkVBox" id="dialog-vbox2">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">2</property>
+ <child>
+ <object class="GtkVBox" id="vbox55">
+ <property name="visible">True</property>
+ <property name="border_width">5</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkHBox" id="hbox58">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkHBox" id="hbox59">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkButton" id="button-image">
+ <property name="width_request">80</property>
+ <property name="height_request">80</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="tooltip_text" translatable="yes">Select your photo</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="fullname">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Full Name</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="buttons_vbox">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkHBox" id="hbox60">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="label1012">
+ <property name="visible">True</property>
+ <property name="yalign">0</property>
+ <property name="label" translatable="yes">User name:</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="login">
+ <property name="visible">True</property>
+ <property name="yalign">0</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="password">
+ <property name="label" translatable="yes">Change Passwo_rd...</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="enable_fingerprint_button">
+ <property name="label" translatable="yes">Enable _Fingerprint Login...</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="disable_fingerprint_button">
+ <property name="label" translatable="yes">Disable _Fingerprint Login...</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox61">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkNotebook" id="notebook2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <child>
+ <object class="GtkVBox" id="vbox57">
+ <property name="visible">True</property>
+ <property name="border_width">12</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">18</property>
+ <child>
+ <object class="GtkVBox" id="vbox62">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label1017">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Email</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox62">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkLabel" id="label1058">
+ <property name="visible">True</property>
+ <property name="label"> </property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkTable" id="table121">
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label1015">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Work:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">email-work-e</property>
+ </object>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label1016">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes" comments="Home vs Work (email)">_Home:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">email-home-e</property>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="email-work-e">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="email-home-e">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox63">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label1021">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Telephone</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox63">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkLabel" id="label1059">
+ <property name="visible">True</property>
+ <property name="label"> </property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkTable" id="table122">
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">4</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label1018">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Wor_k:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">phone-work-e</property>
+ </object>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label1019">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes" comments="Home vs Work (phone)">Hom_e:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">phone-home-e</property>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="phone-work-e">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="phone-home-e">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="phone-mobile-e">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="right_attach">4</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="phone-work-fax-e">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="right_attach">4</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label1020">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Mobile:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">phone-mobile-e</property>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label1057">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Work _fax:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">phone-work-fax-e</property>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox64">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label1023">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Instant Messaging</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox64">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkLabel" id="label1060">
+ <property name="visible">True</property>
+ <property name="label"> </property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkTable" id="table123">
+ <property name="visible">True</property>
+ <property name="n_rows">3</property>
+ <property name="n_columns">4</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label1022">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_XMPP:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">im-jabber-e</property>
+ </object>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="im-jabber-e">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="im-msn-e">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label1052">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Yahoo:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">im-yahoo-e</property>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label1053">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">M_SN:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">im-msn-e</property>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label1054">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">IC_Q:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">im-icq-e</property>
+ </object>
+ <packing>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label1055">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">A_IM/iChat:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">im-aim-e</property>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label1056">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_GroupWise:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">im-groupwise-e</property>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="im-icq-e">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="im-yahoo-e">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="right_attach">4</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="im-aim-e">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="right_attach">4</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="im-groupwise-e">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="right_attach">4</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="label1024">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Contact</property>
+ </object>
+ <packing>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox60">
+ <property name="visible">True</property>
+ <property name="border_width">12</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">18</property>
+ <child>
+ <object class="GtkVBox" id="vbox61">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkVBox" id="vbox65">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel" id="label1043">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes" comments="Home vs Work (address)">Home</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox65">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkLabel" id="label1061">
+ <property name="visible">True</property>
+ <property name="label"> </property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkTable" id="addr-table-1">
+ <property name="visible">True</property>
+ <property name="n_rows">4</property>
+ <property name="n_columns">4</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label1037">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Address:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">addr-street-1</property>
+ </object>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="addr-scrolledwindow-1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">automatic</property>
+ <property name="vscrollbar_policy">never</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkTextView" id="addr-street-1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="accepts_tab">False</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label1038">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">C_ity:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">addr-locality-1</property>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label1039">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_ZIP/Postal code:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">addr-code-1</property>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label1040">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_State/Province:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">addr-region-1</property>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label1041">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Co_untry:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">addr-country-1</property>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label1042">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">P._O. box:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">addr-po-1</property>
+ </object>
+ <packing>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="addr-po-1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="addr-locality-1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="right_attach">4</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="addr-code-1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="right_attach">4</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="addr-country-1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="right_attach">4</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="addr-region-1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="right_attach">4</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox66">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label1050">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Work</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox66">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkLabel" id="label1062">
+ <property name="visible">True</property>
+ <property name="label"> </property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkTable" id="addr-table-2">
+ <property name="visible">True</property>
+ <property name="n_rows">4</property>
+ <property name="n_columns">4</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label1044">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">A_ddress:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">addr-street-2</property>
+ </object>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="addr-scrolledwindow-2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">automatic</property>
+ <property name="vscrollbar_policy">never</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkTextView" id="addr-street-2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="accepts_tab">False</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label1045">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">ZIP/_Postal code:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">addr-code-2</property>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label1046">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">State/Pro_vince:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">addr-region-2</property>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label1047">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Cou_ntry:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">addr-country-2</property>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label1048">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">P.O. _box:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">addr-po-2</property>
+ </object>
+ <packing>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label1049">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Ci_ty:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">addr-locality-2</property>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="addr-po-2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="addr-locality-2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="right_attach">4</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="addr-code-2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="right_attach">4</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="addr-region-2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="right_attach">4</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="addr-country-2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="right_attach">4</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="label1051">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Address</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox59">
+ <property name="visible">True</property>
+ <property name="border_width">12</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">18</property>
+ <child>
+ <object class="GtkVBox" id="vbox67">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label1028">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Web</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox67">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkLabel" id="label1063">
+ <property name="visible">True</property>
+ <property name="label"> </property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkTable" id="table124">
+ <property name="visible">True</property>
+ <property name="n_rows">3</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label1025">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Home page:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">web-homepage-e</property>
+ </object>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label1026">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Web _log:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">web-weblog-e</property>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label1027">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Cale_ndar:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">web-calendar-e</property>
+ </object>
+ <packing>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="web-homepage-e">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="web-weblog-e">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="web-calendar-e">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox68">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label1035">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Job</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox68">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkLabel" id="label1064">
+ <property name="visible">True</property>
+ <property name="label"> </property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkTable" id="table125">
+ <property name="visible">True</property>
+ <property name="n_rows">6</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label1029">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Profession:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">job-profession-e</property>
+ </object>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label1030">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">C_ompany:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">job-company-e</property>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label1031">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Manager:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">job-manager-e</property>
+ </object>
+ <packing>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label1032">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Title:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">job-title-e</property>
+ </object>
+ <packing>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label1033">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Department:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">job-dept-e</property>
+ </object>
+ <packing>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label1034">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">A_ssistant:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">job-assistant-e</property>
+ </object>
+ <packing>
+ <property name="top_attach">5</property>
+ <property name="bottom_attach">6</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="job-profession-e">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="job-company-e">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="job-manager-e">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="job-title-e">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="job-dept-e">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="job-assistant-e">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">5</property>
+ <property name="bottom_attach">6</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="label1036">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Personal Info</property>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <object class="GtkHButtonBox" id="dialog-action_area2">
+ <property name="visible">True</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="closebutton1">
+ <property name="label">gtk-close</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-7">closebutton1</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/capplets/about-me/mate-about-me-fingerprint.c b/capplets/about-me/mate-about-me-fingerprint.c
new file mode 100644
index 00000000..0d6e40ae
--- /dev/null
+++ b/capplets/about-me/mate-about-me-fingerprint.c
@@ -0,0 +1,624 @@
+/* mate-about-me-fingerprint.h
+ * Copyright (C) 2008 Bastien Nocera <[email protected]>
+ *
+ * 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, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <dbus/dbus-glib-bindings.h>
+
+#include "fingerprint-strings.h"
+#include "capplet-util.h"
+
+/* This must match the number of images on the 2nd page in the UI file */
+#define MAX_ENROLL_STAGES 5
+
+/* Translate fprintd strings */
+#define TR(s) dgettext("fprintd", s)
+
+static DBusGProxy *manager = NULL;
+static DBusGConnection *connection = NULL;
+static gboolean is_disable = FALSE;
+
+enum {
+ STATE_NONE,
+ STATE_CLAIMED,
+ STATE_ENROLLING
+};
+
+typedef struct {
+ GtkWidget *enable;
+ GtkWidget *disable;
+
+ GtkWidget *ass;
+ GtkBuilder *dialog;
+
+ DBusGProxy *device;
+ gboolean is_swipe;
+ int num_enroll_stages;
+ int num_stages_done;
+ char *name;
+ const char *finger;
+ gint state;
+} EnrollData;
+
+static void create_manager (void)
+{
+ GError *error = NULL;
+
+ connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
+ if (connection == NULL) {
+ g_warning ("Failed to connect to session bus: %s", error->message);
+ return;
+ }
+
+ manager = dbus_g_proxy_new_for_name (connection,
+ "net.reactivated.Fprint",
+ "/net/reactivated/Fprint/Manager",
+ "net.reactivated.Fprint.Manager");
+}
+
+static DBusGProxy *
+get_first_device (void)
+{
+ DBusGProxy *device;
+ char *device_str;
+
+ if (!dbus_g_proxy_call (manager, "GetDefaultDevice", NULL, G_TYPE_INVALID,
+ DBUS_TYPE_G_OBJECT_PATH, &device_str, G_TYPE_INVALID)) {
+ return NULL;
+ }
+
+ device = dbus_g_proxy_new_for_name(connection,
+ "net.reactivated.Fprint",
+ device_str,
+ "net.reactivated.Fprint.Device");
+
+ g_free (device_str);
+
+ return device;
+}
+
+static const char *
+get_reason_for_error (const char *dbus_error)
+{
+ if (g_str_equal (dbus_error, "net.reactivated.Fprint.Error.PermissionDenied"))
+ return N_("You are not allowed to access the device. Contact your system administrator.");
+ if (g_str_equal (dbus_error, "net.reactivated.Fprint.Error.AlreadyInUse"))
+ return N_("The device is already in use.");
+ if (g_str_equal (dbus_error, "net.reactivated.Fprint.Error.Internal"))
+ return N_("An internal error occured");
+
+ return NULL;
+}
+
+static GtkWidget *
+get_error_dialog (const char *title,
+ const char *dbus_error,
+ GtkWindow *parent)
+{
+ GtkWidget *error_dialog;
+ const char *reason;
+
+ if (dbus_error == NULL)
+ g_warning ("get_error_dialog called with reason == NULL");
+
+ error_dialog =
+ gtk_message_dialog_new (parent,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ "%s", title);
+ reason = get_reason_for_error (dbus_error);
+ gtk_message_dialog_format_secondary_text
+ (GTK_MESSAGE_DIALOG (error_dialog), "%s", reason ? _(reason) : _(dbus_error));
+
+ gtk_window_set_title (GTK_WINDOW (error_dialog), ""); /* as per HIG */
+ gtk_container_set_border_width (GTK_CONTAINER (error_dialog), 5);
+ gtk_dialog_set_default_response (GTK_DIALOG (error_dialog),
+ GTK_RESPONSE_OK);
+ gtk_window_set_modal (GTK_WINDOW (error_dialog), TRUE);
+ gtk_window_set_position (GTK_WINDOW (error_dialog), GTK_WIN_POS_CENTER_ON_PARENT);
+
+ return error_dialog;
+}
+
+void
+set_fingerprint_label (GtkWidget *enable, GtkWidget *disable)
+{
+ char **fingers;
+ DBusGProxy *device;
+ GError *error = NULL;
+
+ gtk_widget_set_no_show_all (enable, TRUE);
+ gtk_widget_set_no_show_all (disable, TRUE);
+
+ if (manager == NULL) {
+ create_manager ();
+ if (manager == NULL) {
+ gtk_widget_hide (enable);
+ gtk_widget_hide (disable);
+ return;
+ }
+ }
+
+ device = get_first_device ();
+ if (device == NULL) {
+ gtk_widget_hide (enable);
+ gtk_widget_hide (disable);
+ return;
+ }
+
+ if (!dbus_g_proxy_call (device, "ListEnrolledFingers", &error, G_TYPE_STRING, "", G_TYPE_INVALID,
+ G_TYPE_STRV, &fingers, G_TYPE_INVALID)) {
+ if (dbus_g_error_has_name (error, "net.reactivated.Fprint.Error.NoEnrolledPrints") == FALSE) {
+ gtk_widget_hide (enable);
+ gtk_widget_hide (disable);
+ g_object_unref (device);
+ return;
+ }
+ fingers = NULL;
+ }
+
+ if (fingers == NULL || g_strv_length (fingers) == 0) {
+ gtk_widget_hide (disable);
+ gtk_widget_show (enable);
+ is_disable = FALSE;
+ } else {
+ gtk_widget_hide (enable);
+ gtk_widget_show (disable);
+ is_disable = TRUE;
+ }
+
+ g_strfreev (fingers);
+ g_object_unref (device);
+}
+
+static void
+delete_fingerprints (void)
+{
+ DBusGProxy *device;
+
+ if (manager == NULL) {
+ create_manager ();
+ if (manager == NULL)
+ return;
+ }
+
+ device = get_first_device ();
+ if (device == NULL)
+ return;
+
+ dbus_g_proxy_call (device, "DeleteEnrolledFingers", NULL, G_TYPE_STRING, "", G_TYPE_INVALID, G_TYPE_INVALID);
+
+ g_object_unref (device);
+}
+
+static void
+delete_fingerprints_question (GtkBuilder *dialog, GtkWidget *enable, GtkWidget *disable)
+{
+ GtkWidget *question;
+ GtkWidget *button;
+
+ question = gtk_message_dialog_new (GTK_WINDOW (WID ("about-me-dialog")),
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_NONE,
+ _("Delete registered fingerprints?"));
+ gtk_dialog_add_button (GTK_DIALOG (question), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
+
+ button = gtk_button_new_with_mnemonic (_("_Delete Fingerprints"));
+ gtk_button_set_image (GTK_BUTTON (button), gtk_image_new_from_stock (GTK_STOCK_DELETE, GTK_ICON_SIZE_BUTTON));
+ gtk_widget_set_can_default (button, TRUE);
+ gtk_widget_show (button);
+ gtk_dialog_add_action_widget (GTK_DIALOG (question), button, GTK_RESPONSE_OK);
+
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (question),
+ _("Do you want to delete your registered fingerprints so fingerprint login is disabled?"));
+ gtk_container_set_border_width (GTK_CONTAINER (question), 5);
+ gtk_dialog_set_default_response (GTK_DIALOG (question), GTK_RESPONSE_OK);
+ gtk_window_set_position (GTK_WINDOW (question), GTK_WIN_POS_CENTER_ON_PARENT);
+ gtk_window_set_modal (GTK_WINDOW (question), TRUE);
+
+ if (gtk_dialog_run (GTK_DIALOG (question)) == GTK_RESPONSE_OK) {
+ delete_fingerprints ();
+ set_fingerprint_label (enable, disable);
+ }
+
+ gtk_widget_destroy (question);
+}
+
+static void
+enroll_data_destroy (EnrollData *data)
+{
+ switch (data->state) {
+ case STATE_ENROLLING:
+ dbus_g_proxy_call(data->device, "EnrollStop", NULL, G_TYPE_INVALID, G_TYPE_INVALID);
+ /* fall-through */
+ case STATE_CLAIMED:
+ dbus_g_proxy_call(data->device, "Release", NULL, G_TYPE_INVALID, G_TYPE_INVALID);
+ /* fall-through */
+ case STATE_NONE:
+ g_free (data->name);
+ g_object_unref (data->device);
+ g_object_unref (data->dialog);
+ gtk_widget_destroy (data->ass);
+
+ g_free (data);
+ }
+}
+
+static const char *
+selected_finger (GtkBuilder *dialog)
+{
+ int index;
+
+ if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (WID ("radiobutton1")))) {
+ gtk_widget_set_sensitive (WID ("finger_combobox"), FALSE);
+ return "right-index-finger";
+ }
+ if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (WID ("radiobutton2")))) {
+ gtk_widget_set_sensitive (WID ("finger_combobox"), FALSE);
+ return "left-index-finger";
+ }
+ gtk_widget_set_sensitive (WID ("finger_combobox"), TRUE);
+ index = gtk_combo_box_get_active (GTK_COMBO_BOX (WID ("finger_combobox")));
+ switch (index) {
+ case 0:
+ return "left-thumb";
+ case 1:
+ return "left-middle-finger";
+ case 2:
+ return "left-ring-finger";
+ case 3:
+ return "left-little-finger";
+ case 4:
+ return "right-thumb";
+ case 5:
+ return "right-middle-finger";
+ case 6:
+ return "right-ring-finger";
+ case 7:
+ return "right-little-finger";
+ default:
+ g_assert_not_reached ();
+ }
+
+ return NULL;
+}
+
+static void
+finger_radio_button_toggled (GtkToggleButton *button, EnrollData *data)
+{
+ GtkBuilder *dialog = data->dialog;
+ char *msg;
+
+ data->finger = selected_finger (data->dialog);
+
+ msg = g_strdup_printf (TR(finger_str_to_msg (data->finger, data->is_swipe)), data->name);
+ gtk_label_set_text (GTK_LABEL (WID("enroll-label")), msg);
+ g_free (msg);
+}
+
+static void
+finger_combobox_changed (GtkComboBox *combobox, EnrollData *data)
+{
+ GtkBuilder *dialog = data->dialog;
+ char *msg;
+
+ data->finger = selected_finger (data->dialog);
+
+ msg = g_strdup_printf (TR(finger_str_to_msg (data->finger, data->is_swipe)), data->name);
+ gtk_label_set_text (GTK_LABEL (WID("enroll-label")), msg);
+ g_free (msg);
+}
+
+static void
+assistant_cancelled (GtkAssistant *ass, EnrollData *data)
+{
+ GtkWidget *enable, *disable;
+
+ enable = data->enable;
+ disable = data->disable;
+
+ enroll_data_destroy (data);
+ set_fingerprint_label (enable, disable);
+}
+
+static void
+enroll_result (GObject *object, const char *result, gboolean done, EnrollData *data)
+{
+ GtkBuilder *dialog = data->dialog;
+ char *msg;
+
+ if (g_str_equal (result, "enroll-completed") || g_str_equal (result, "enroll-stage-passed")) {
+ char *name, *path;
+
+ data->num_stages_done++;
+ name = g_strdup_printf ("image%d", data->num_stages_done);
+ path = g_build_filename (MATECC_PIXMAP_DIR, "print_ok.png", NULL);
+ gtk_image_set_from_file (GTK_IMAGE (WID (name)), path);
+ g_free (name);
+ g_free (path);
+ }
+ if (g_str_equal (result, "enroll-completed")) {
+ gtk_label_set_text (GTK_LABEL (WID ("status-label")), _("Done!"));
+ gtk_assistant_set_page_complete (GTK_ASSISTANT (data->ass), WID ("page2"), TRUE);
+ }
+
+ if (done != FALSE) {
+ dbus_g_proxy_call(data->device, "EnrollStop", NULL, G_TYPE_INVALID, G_TYPE_INVALID);
+ data->state = STATE_CLAIMED;
+ if (g_str_equal (result, "enroll-completed") == FALSE) {
+ /* The enrollment failed, restart it */
+ dbus_g_proxy_call(data->device, "EnrollStart", NULL, G_TYPE_STRING, data->finger, G_TYPE_INVALID, G_TYPE_INVALID);
+ data->state = STATE_ENROLLING;
+ result = "enroll-retry-scan";
+ } else {
+ return;
+ }
+ }
+
+ msg = g_strdup_printf (TR(enroll_result_str_to_msg (result, data->is_swipe)), data->name);
+ gtk_label_set_text (GTK_LABEL (WID ("status-label")), msg);
+ g_free (msg);
+}
+
+static void
+assistant_prepare (GtkAssistant *ass, GtkWidget *page, EnrollData *data)
+{
+ const char *name;
+
+ name = g_object_get_data (G_OBJECT (page), "name");
+ if (name == NULL)
+ return;
+
+ if (g_str_equal (name, "enroll")) {
+ DBusGProxy *p;
+ GError *error = NULL;
+ GtkBuilder *dialog = data->dialog;
+ char *path;
+ guint i;
+ GValue value = { 0, };
+
+ if (!dbus_g_proxy_call (data->device, "Claim", &error, G_TYPE_STRING, "", G_TYPE_INVALID, G_TYPE_INVALID)) {
+ GtkWidget *d;
+ char *msg;
+
+ /* translators:
+ * The variable is the name of the device, for example:
+ * "Could you not access "Digital Persona U.are.U 4000/4000B" device */
+ msg = g_strdup_printf (_("Could not access '%s' device"), data->name);
+ d = get_error_dialog (msg, dbus_g_error_get_name (error), GTK_WINDOW (data->ass));
+ g_error_free (error);
+ gtk_dialog_run (GTK_DIALOG (d));
+ gtk_widget_destroy (d);
+ g_free (msg);
+
+ enroll_data_destroy (data);
+
+ return;
+ }
+ data->state = STATE_CLAIMED;
+
+ p = dbus_g_proxy_new_from_proxy (data->device, "org.freedesktop.DBus.Properties", NULL);
+ if (!dbus_g_proxy_call (p, "Get", NULL, G_TYPE_STRING, "net.reactivated.Fprint.Device", G_TYPE_STRING, "num-enroll-stages", G_TYPE_INVALID,
+ G_TYPE_VALUE, &value, G_TYPE_INVALID) || g_value_get_int (&value) < 1) {
+ GtkWidget *d;
+ char *msg;
+
+ /* translators:
+ * The variable is the name of the device, for example:
+ * "Could you not access "Digital Persona U.are.U 4000/4000B" device */
+ msg = g_strdup_printf (_("Could not access '%s' device"), data->name);
+ d = get_error_dialog (msg, "net.reactivated.Fprint.Error.Internal", GTK_WINDOW (data->ass));
+ gtk_dialog_run (GTK_DIALOG (d));
+ gtk_widget_destroy (d);
+ g_free (msg);
+
+ enroll_data_destroy (data);
+
+ g_object_unref (p);
+ return;
+ }
+ g_object_unref (p);
+
+ data->num_enroll_stages = g_value_get_int (&value);
+
+ /* Hide the extra "bulbs" if not needed */
+ for (i = MAX_ENROLL_STAGES; i > data->num_enroll_stages; i--) {
+ char *name;
+
+ name = g_strdup_printf ("image%d", i);
+ gtk_widget_hide (WID (name));
+ g_free (name);
+ }
+ /* And set the right image */
+ {
+ char *filename;
+
+ filename = g_strdup_printf ("%s.png", data->finger);
+ path = g_build_filename (MATECC_PIXMAP_DIR, filename, NULL);
+ g_free (filename);
+ }
+ for (i = 1; i <= data->num_enroll_stages; i++) {
+ char *name;
+ name = g_strdup_printf ("image%d", i);
+ gtk_image_set_from_file (GTK_IMAGE (WID (name)), path);
+ g_free (name);
+ }
+ g_free (path);
+
+ dbus_g_proxy_add_signal(data->device, "EnrollStatus", G_TYPE_STRING, G_TYPE_BOOLEAN, NULL);
+ dbus_g_proxy_connect_signal(data->device, "EnrollStatus", G_CALLBACK(enroll_result), data, NULL);
+
+ if (!dbus_g_proxy_call(data->device, "EnrollStart", &error, G_TYPE_STRING, data->finger, G_TYPE_INVALID, G_TYPE_INVALID)) {
+ GtkWidget *d;
+ char *msg;
+
+ /* translators:
+ * The variable is the name of the device, for example:
+ * "Could you not access "Digital Persona U.are.U 4000/4000B" device */
+ msg = g_strdup_printf (_("Could not start finger capture on '%s' device"), data->name);
+ d = get_error_dialog (msg, dbus_g_error_get_name (error), GTK_WINDOW (data->ass));
+ g_error_free (error);
+ gtk_dialog_run (GTK_DIALOG (d));
+ gtk_widget_destroy (d);
+ g_free (msg);
+
+ enroll_data_destroy (data);
+
+ return;
+ }
+ data->state = STATE_ENROLLING;;
+ } else {
+ if (data->state == STATE_ENROLLING) {
+ dbus_g_proxy_call(data->device, "EnrollStop", NULL, G_TYPE_INVALID, G_TYPE_INVALID);
+ data->state = STATE_CLAIMED;
+ }
+ if (data->state == STATE_CLAIMED) {
+ dbus_g_proxy_call(data->device, "Release", NULL, G_TYPE_INVALID, G_TYPE_INVALID);
+ data->state = STATE_NONE;
+ }
+ }
+}
+
+static void
+enroll_fingerprints (GtkWindow *parent, GtkWidget *enable, GtkWidget *disable)
+{
+ DBusGProxy *device, *p;
+ GHashTable *props;
+ GtkBuilder *dialog;
+ EnrollData *data;
+ GtkWidget *ass;
+ char *msg;
+
+ device = NULL;
+
+ if (manager == NULL) {
+ create_manager ();
+ if (manager != NULL)
+ device = get_first_device ();
+ } else {
+ device = get_first_device ();
+ }
+
+ if (manager == NULL || device == NULL) {
+ GtkWidget *d;
+
+ d = get_error_dialog (_("Could not access any fingerprint readers"),
+ _("Please contact your system administrator for help."),
+ parent);
+ gtk_dialog_run (GTK_DIALOG (d));
+ gtk_widget_destroy (d);
+ return;
+ }
+
+ data = g_new0 (EnrollData, 1);
+ data->device = device;
+ data->enable = enable;
+ data->disable = disable;
+
+ /* Get some details about the device */
+ p = dbus_g_proxy_new_from_proxy (device, "org.freedesktop.DBus.Properties", NULL);
+ if (dbus_g_proxy_call (p, "GetAll", NULL, G_TYPE_STRING, "net.reactivated.Fprint.Device", G_TYPE_INVALID,
+ dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE), &props, G_TYPE_INVALID)) {
+ const char *scan_type;
+ data->name = g_value_dup_string (g_hash_table_lookup (props, "name"));
+ scan_type = g_value_dup_string (g_hash_table_lookup (props, "scan-type"));
+ if (g_str_equal (scan_type, "swipe"))
+ data->is_swipe = TRUE;
+ g_hash_table_destroy (props);
+ }
+ g_object_unref (p);
+
+ dialog = gtk_builder_new ();
+ gtk_builder_add_from_file (dialog, MATECC_UI_DIR "/mate-about-me-fingerprint.ui", NULL);
+ data->dialog = dialog;
+
+ ass = WID ("assistant");
+ gtk_window_set_title (GTK_WINDOW (ass), _("Enable Fingerprint Login"));
+ gtk_window_set_transient_for (GTK_WINDOW (ass), parent);
+ gtk_window_set_position (GTK_WINDOW (ass), GTK_WIN_POS_CENTER_ON_PARENT);
+ g_signal_connect (G_OBJECT (ass), "cancel",
+ G_CALLBACK (assistant_cancelled), data);
+ g_signal_connect (G_OBJECT (ass), "close",
+ G_CALLBACK (assistant_cancelled), data);
+ g_signal_connect (G_OBJECT (ass), "prepare",
+ G_CALLBACK (assistant_prepare), data);
+
+ /* Page 1 */
+ gtk_combo_box_set_active (GTK_COMBO_BOX (WID ("finger_combobox")), 0);
+
+ g_signal_connect (G_OBJECT (WID ("radiobutton1")), "toggled",
+ G_CALLBACK (finger_radio_button_toggled), data);
+ g_signal_connect (G_OBJECT (WID ("radiobutton2")), "toggled",
+ G_CALLBACK (finger_radio_button_toggled), data);
+ g_signal_connect (G_OBJECT (WID ("radiobutton3")), "toggled",
+ G_CALLBACK (finger_radio_button_toggled), data);
+ g_signal_connect (G_OBJECT (WID ("finger_combobox")), "changed",
+ G_CALLBACK (finger_combobox_changed), data);
+
+ data->finger = selected_finger (dialog);
+
+ g_object_set_data (G_OBJECT (WID("page1")), "name", "intro");
+
+ /* translators:
+ * The variable is the name of the device, for example:
+ * "To enable fingerprint login, you need to save one of your fingerprints, using the
+ * 'Digital Persona U.are.U 4000/4000B' device." */
+ msg = g_strdup_printf (_("To enable fingerprint login, you need to save one of your fingerprints, using the '%s' device."),
+ data->name);
+ gtk_label_set_text (GTK_LABEL (WID("intro-label")), msg);
+ g_free (msg);
+
+ gtk_assistant_set_page_complete (GTK_ASSISTANT (ass), WID("page1"), TRUE);
+
+ /* Page 2 */
+ if (data->is_swipe != FALSE)
+ gtk_assistant_set_page_title (GTK_ASSISTANT (ass), WID("page2"), _("Swipe finger on reader"));
+ else
+ gtk_assistant_set_page_title (GTK_ASSISTANT (ass), WID("page2"), _("Place finger on reader"));
+
+ g_object_set_data (G_OBJECT (WID("page2")), "name", "enroll");
+
+ msg = g_strdup_printf (TR(finger_str_to_msg (data->finger, data->is_swipe)), data->name);
+ gtk_label_set_text (GTK_LABEL (WID("enroll-label")), msg);
+ g_free (msg);
+
+ /* Page 3 */
+ g_object_set_data (G_OBJECT (WID("page3")), "name", "summary");
+
+ data->ass = ass;
+ gtk_widget_show_all (ass);
+}
+
+void
+fingerprint_button_clicked (GtkBuilder *dialog,
+ GtkWidget *enable,
+ GtkWidget *disable)
+{
+ bindtextdomain ("fprintd", MATELOCALEDIR);
+ bind_textdomain_codeset ("fprintd", "UTF-8");
+
+ if (is_disable != FALSE) {
+ delete_fingerprints_question (dialog, enable, disable);
+ } else {
+ enroll_fingerprints (GTK_WINDOW (WID ("about-me-dialog")), enable, disable);
+ }
+}
+
diff --git a/capplets/about-me/mate-about-me-fingerprint.h b/capplets/about-me/mate-about-me-fingerprint.h
new file mode 100644
index 00000000..c60ca358
--- /dev/null
+++ b/capplets/about-me/mate-about-me-fingerprint.h
@@ -0,0 +1,27 @@
+/* mate-about-me-fingerprint.h
+ * Copyright (C) 2008 Bastien Nocera <[email protected]>
+ *
+ * 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, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <gtk/gtk.h>
+
+void set_fingerprint_label (GtkWidget *enable,
+ GtkWidget *disable);
+void fingerprint_button_clicked (GtkBuilder *dialog,
+ GtkWidget *enable,
+ GtkWidget *disable);
+
diff --git a/capplets/about-me/mate-about-me-fingerprint.ui b/capplets/about-me/mate-about-me-fingerprint.ui
new file mode 100644
index 00000000..7f154336
--- /dev/null
+++ b/capplets/about-me/mate-about-me-fingerprint.ui
@@ -0,0 +1,276 @@
+<?xml version="1.0"?>
+<interface>
+ <requires lib="gtk+" version="2.16"/>
+ <!-- interface-naming-policy toplevel-contextual -->
+ <object class="GtkListStore" id="model1">
+ <columns>
+ <!-- column-name gchararray -->
+ <column type="gchararray"/>
+ </columns>
+ <data>
+ <row>
+ <col id="0" translatable="yes">Left thumb</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">Left middle finger</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">Left ring finger</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">Left little finger</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">Right thumb</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">Right middle finger</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">Right ring finger</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">Right little finger</col>
+ </row>
+ </data>
+ </object>
+ <object class="GtkAssistant" id="assistant">
+ <property name="border_width">12</property>
+ <property name="title" translatable="yes">Enable Fingerprint Login</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <object class="GtkVBox" id="page1">
+ <property name="visible">True</property>
+ <property name="border_width">12</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkHBox" id="hbox74">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkImage" id="image">
+ <property name="visible">True</property>
+ <property name="stock">gtk-dialog-info</property>
+ <property name="icon-size">6</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="intro-label">
+ <property name="visible">True</property>
+ <property name="label">To enable fingerprint login, you need to save one of your fingerprints, using the Acme Foobar 5000.</property>
+ <property name="wrap">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox70">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkRadioButton" id="radiobutton1">
+ <property name="label" translatable="yes">Right index finger</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="radiobutton2">
+ <property name="label" translatable="yes">Left index finger</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">radiobutton1</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox77">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkRadioButton" id="radiobutton3">
+ <property name="label" translatable="yes">Other finger: </property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">radiobutton1</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBox" id="finger_combobox">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="model">model1</property>
+ <child>
+ <object class="GtkCellRendererText" id="renderer1"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="title" translatable="yes">Select finger</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="page2">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel" id="enroll-label">
+ <property name="visible">True</property>
+ <property name="label">In order to save your fingerprints, you need to swipe your thumb on the "Acme foobar" device.</property>
+ <property name="wrap">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="enroll_hbox">
+ <property name="visible">True</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <object class="GtkImage" id="image1">
+ <property name="visible">True</property>
+ <property name="stock">gtk-no</property>
+ <property name="icon-size">6</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkImage" id="image2">
+ <property name="visible">True</property>
+ <property name="stock">gtk-no</property>
+ <property name="icon-size">6</property>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkImage" id="image3">
+ <property name="visible">True</property>
+ <property name="stock">gtk-no</property>
+ <property name="icon-size">6</property>
+ </object>
+ <packing>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkImage" id="image4">
+ <property name="visible">True</property>
+ <property name="stock">gtk-no</property>
+ <property name="icon-size">6</property>
+ </object>
+ <packing>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkImage" id="image5">
+ <property name="visible">True</property>
+ <property name="stock">gtk-no</property>
+ <property name="icon-size">6</property>
+ </object>
+ <packing>
+ <property name="position">5</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="status-label">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="title">Swipe finger on reader</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="page3">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Your fingerprint was successfully saved. You should now be able to log in using your fingerprint reader.</property>
+ <property name="wrap">True</property>
+ </object>
+ <packing>
+ <property name="page_type">summary</property>
+ <property name="title" translatable="yes">Done!</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/capplets/about-me/mate-about-me-password.c b/capplets/about-me/mate-about-me-password.c
new file mode 100644
index 00000000..0699c28d
--- /dev/null
+++ b/capplets/about-me/mate-about-me-password.c
@@ -0,0 +1,1136 @@
+/* mate-about-me.c
+ * Copyright (C) 2002 Diego Gonzalez
+ * Copyright (C) 2006 Johannes H. Jensen
+ *
+ * Written by: Diego Gonzalez <[email protected]>
+ * Modified by: Johannes H. Jensen <[email protected]>
+ *
+ * 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, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Parts of this code come from Mate-System-Tools.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Are all of these needed? */
+#include <gdk/gdkkeysyms.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/wait.h>
+
+#if __sun
+#include <sys/types.h>
+#include <signal.h>
+#endif
+
+#include "capplet-util.h"
+#include "eel-alert-dialog.h"
+
+/* Passwd states */
+typedef enum {
+ PASSWD_STATE_NONE, /* Passwd is not asking for anything */
+ PASSWD_STATE_AUTH, /* Passwd is asking for our current password */
+ PASSWD_STATE_NEW, /* Passwd is asking for our new password */
+ PASSWD_STATE_RETYPE, /* Passwd is asking for our retyped new password */
+ PASSWD_STATE_ERR /* Passwd reported an error but has not yet exited */
+} PasswdState;
+
+typedef struct {
+ GtkBuilder *ui;
+
+ /* Commonly used widgets */
+ GtkEntry *current_password;
+ GtkEntry *new_password;
+ GtkEntry *retyped_password;
+ GtkImage *dialog_image;
+ GtkLabel *status_label;
+
+ /* Whether we have authenticated */
+ gboolean authenticated;
+
+ /* Communication with the passwd program */
+ GPid backend_pid;
+
+ GIOChannel *backend_stdin;
+ GIOChannel *backend_stdout;
+
+ GQueue *backend_stdin_queue; /* Write queue to backend_stdin */
+
+ /* GMainLoop IDs */
+ guint backend_child_watch_id; /* g_child_watch_add (PID) */
+ guint backend_stdout_watch_id; /* g_io_add_watch (stdout) */
+
+ /* State of the passwd program */
+ PasswdState backend_state;
+
+} PasswordDialog;
+
+/* Buffer size for backend output */
+#define BUFSIZE 64
+
+/*
+ * Error handling {{
+ */
+#define PASSDLG_ERROR (mate_about_me_password_error_quark())
+
+GQuark mate_about_me_password_error_quark(void)
+{
+ static GQuark q = 0;
+
+ if (q == 0) {
+ q = g_quark_from_static_string("mate_about_me_password_error");
+ }
+
+ return q;
+}
+
+/* error codes */
+enum {
+ PASSDLG_ERROR_NONE,
+ PASSDLG_ERROR_NEW_PASSWORD_EMPTY,
+ PASSDLG_ERROR_RETYPED_PASSWORD_EMPTY,
+ PASSDLG_ERROR_PASSWORDS_NOT_EQUAL,
+ PASSDLG_ERROR_BACKEND, /* Backend error */
+ PASSDLG_ERROR_USER, /* Generic user error */
+ PASSDLG_ERROR_FAILED /* Fatal failure, error->message should explain */
+};
+
+/*
+ * }} Error handling
+ */
+
+/*
+ * Prototypes {{
+ */
+static void
+stop_passwd (PasswordDialog *pdialog);
+
+static void
+free_passwd_resources (PasswordDialog *pdialog);
+
+static gboolean
+io_watch_stdout (GIOChannel *source, GIOCondition condition, PasswordDialog *pdialog);
+
+static void
+passdlg_set_auth_state (PasswordDialog *pdialog, gboolean state);
+
+static void
+passdlg_set_status (PasswordDialog *pdialog, gchar *msg);
+
+static void
+passdlg_set_busy (PasswordDialog *pdialog, gboolean busy);
+
+static void
+passdlg_clear (PasswordDialog *pdialog);
+
+static guint
+passdlg_refresh_password_state (PasswordDialog *pdialog);
+
+/*
+ * }} Prototypes
+ */
+
+/*
+ * Spawning and closing of backend {{
+ */
+
+/* Child watcher */
+static void
+child_watch_cb (GPid pid, gint status, PasswordDialog *pdialog)
+{
+ if (WIFEXITED (status)) {
+ if (WEXITSTATUS (status) >= 255) {
+ g_warning (_("Child exited unexpectedly"));
+ }
+ }
+
+ free_passwd_resources (pdialog);
+}
+
+/* Spawn passwd backend
+ * Returns: TRUE on success, FALSE otherwise and sets error appropriately */
+static gboolean
+spawn_passwd (PasswordDialog *pdialog, GError **error)
+{
+ gchar *argv[2];
+ gchar *envp[1];
+ gint my_stdin, my_stdout, my_stderr;
+
+ argv[0] = "/usr/bin/passwd"; /* Is it safe to rely on a hard-coded path? */
+ argv[1] = NULL;
+
+ envp[0] = NULL; /* If we pass an empty array as the environment,
+ * will the childs environment be empty, and the
+ * locales set to the C default? From the manual:
+ * "If envp is NULL, the child inherits its
+ * parent'senvironment."
+ * If I'm wrong here, we somehow have to set
+ * the locales here.
+ */
+
+ if (!g_spawn_async_with_pipes (NULL, /* Working directory */
+ argv, /* Argument vector */
+ envp, /* Environment */
+ G_SPAWN_DO_NOT_REAP_CHILD, /* Flags */
+ NULL, /* Child setup */
+ NULL, /* Data to child setup */
+ &pdialog->backend_pid, /* PID */
+ &my_stdin, /* Stdin */
+ &my_stdout, /* Stdout */
+ &my_stderr, /* Stderr */
+ error)) { /* GError */
+
+ /* An error occured */
+ free_passwd_resources (pdialog);
+
+ return FALSE;
+ }
+
+ /* 2>&1 */
+ if (dup2 (my_stderr, my_stdout) == -1) {
+ /* Failed! */
+ g_set_error (error,
+ PASSDLG_ERROR,
+ PASSDLG_ERROR_BACKEND,
+ strerror (errno));
+
+ /* Clean up */
+ stop_passwd (pdialog);
+
+ return FALSE;
+ }
+
+ /* Open IO Channels */
+ pdialog->backend_stdin = g_io_channel_unix_new (my_stdin);
+ pdialog->backend_stdout = g_io_channel_unix_new (my_stdout);
+
+ /* Set raw encoding */
+ /* Set nonblocking mode */
+ if (g_io_channel_set_encoding (pdialog->backend_stdin, NULL, error) != G_IO_STATUS_NORMAL ||
+ g_io_channel_set_encoding (pdialog->backend_stdout, NULL, error) != G_IO_STATUS_NORMAL ||
+ g_io_channel_set_flags (pdialog->backend_stdin, G_IO_FLAG_NONBLOCK, error) != G_IO_STATUS_NORMAL ||
+ g_io_channel_set_flags (pdialog->backend_stdout, G_IO_FLAG_NONBLOCK, error) != G_IO_STATUS_NORMAL ) {
+
+ /* Clean up */
+ stop_passwd (pdialog);
+ return FALSE;
+ }
+
+ /* Turn off buffering */
+ g_io_channel_set_buffered (pdialog->backend_stdin, FALSE);
+ g_io_channel_set_buffered (pdialog->backend_stdout, FALSE);
+
+ /* Add IO Channel watcher */
+ pdialog->backend_stdout_watch_id = g_io_add_watch (pdialog->backend_stdout,
+ G_IO_IN | G_IO_PRI,
+ (GIOFunc) io_watch_stdout, pdialog);
+
+ /* Add child watcher */
+ pdialog->backend_child_watch_id = g_child_watch_add (pdialog->backend_pid, (GChildWatchFunc) child_watch_cb, pdialog);
+
+ /* Success! */
+
+ return TRUE;
+}
+
+/* Stop passwd backend */
+static void
+stop_passwd (PasswordDialog *pdialog)
+{
+ /* This is the standard way of returning from the dialog with passwd.
+ * If we return this way we can safely kill passwd as it has completed
+ * its task.
+ */
+
+ if (pdialog->backend_pid != -1) {
+ kill (pdialog->backend_pid, 9);
+ }
+
+ /* We must run free_passwd_resources here and not let our child
+ * watcher do it, since it will access invalid memory after the
+ * dialog has been closed and cleaned up.
+ *
+ * If we had more than a single thread we'd need to remove
+ * the child watch before trying to kill the child.
+ */
+ free_passwd_resources (pdialog);
+}
+
+/* Clean up passwd resources */
+static void
+free_passwd_resources (PasswordDialog *pdialog)
+{
+ GError *error = NULL;
+
+ /* Remove the child watcher */
+ if (pdialog->backend_child_watch_id != 0) {
+
+ g_source_remove (pdialog->backend_child_watch_id);
+
+ pdialog->backend_child_watch_id = 0;
+ }
+
+
+ /* Close IO channels (internal file descriptors are automatically closed) */
+ if (pdialog->backend_stdin != NULL) {
+
+ if (g_io_channel_shutdown (pdialog->backend_stdin, TRUE, &error) != G_IO_STATUS_NORMAL) {
+ g_warning (_("Could not shutdown backend_stdin IO channel: %s"), error->message);
+ g_error_free (error);
+ error = NULL;
+ }
+
+ g_io_channel_unref (pdialog->backend_stdin);
+
+ pdialog->backend_stdin = NULL;
+ }
+
+ if (pdialog->backend_stdout != NULL) {
+
+ if (g_io_channel_shutdown (pdialog->backend_stdout, TRUE, &error) != G_IO_STATUS_NORMAL) {
+ g_warning (_("Could not shutdown backend_stdout IO channel: %s"), error->message);
+ g_error_free (error);
+ error = NULL;
+ }
+
+ g_io_channel_unref (pdialog->backend_stdout);
+
+ pdialog->backend_stdout = NULL;
+ }
+
+ /* Remove IO watcher */
+ if (pdialog->backend_stdout_watch_id != 0) {
+
+ g_source_remove (pdialog->backend_stdout_watch_id);
+
+ pdialog->backend_stdout_watch_id = 0;
+ }
+
+ /* Close PID */
+ if (pdialog->backend_pid != -1) {
+
+ g_spawn_close_pid (pdialog->backend_pid);
+
+ pdialog->backend_pid = -1;
+ }
+
+ /* Clear backend state */
+ pdialog->backend_state = PASSWD_STATE_NONE;
+}
+
+/*
+ * }} Spawning and closing of backend
+ */
+
+/*
+ * Backend communication code {{
+ */
+
+/* Write the first element of queue through channel */
+static void
+io_queue_pop (GQueue *queue, GIOChannel *channel)
+{
+ gchar *buf;
+ gsize bytes_written;
+ GError *error = NULL;
+
+ buf = g_queue_pop_head (queue);
+
+ if (buf != NULL) {
+
+ if (g_io_channel_write_chars (channel, buf, -1, &bytes_written, &error) != G_IO_STATUS_NORMAL) {
+ g_warning ("Could not write queue element \"%s\" to channel: %s", buf, error->message);
+ g_error_free (error);
+ }
+
+ g_free (buf);
+ }
+}
+
+/* Goes through the argument list, checking if one of them occurs in str
+ * Returns: TRUE as soon as an element is found to match, FALSE otherwise */
+static gboolean
+is_string_complete (gchar *str, ...)
+{
+ va_list ap;
+ gchar *arg;
+
+ if (strlen (str) == 0) {
+ return FALSE;
+ }
+
+ va_start (ap, str);
+
+ while ((arg = va_arg (ap, char *)) != NULL) {
+ if (g_strrstr (str, arg) != NULL) {
+ va_end (ap);
+ return TRUE;
+ }
+ }
+
+ va_end (ap);
+
+ return FALSE;
+}
+
+/* Authentication attempt succeeded. Update the GUI accordingly. */
+static void
+authenticated_user (PasswordDialog *pdialog)
+{
+ pdialog->backend_state = PASSWD_STATE_NEW;
+
+ if (pdialog->authenticated) {
+ /* This is a re-authentication
+ * It succeeded, so pop our new password from the queue */
+ io_queue_pop (pdialog->backend_stdin_queue, pdialog->backend_stdin);
+ }
+
+ /* Update UI state */
+ passdlg_set_auth_state (pdialog, TRUE);
+ passdlg_set_status (pdialog, _("Authenticated!"));
+
+ /* Check to see if the passwords are valid
+ * (They might be non-empty if the user had to re-authenticate,
+ * and thus we need to enable the change-password-button) */
+ passdlg_refresh_password_state (pdialog);
+}
+
+/*
+ * IO watcher for stdout, called whenever there is data to read from the backend.
+ * This is where most of the actual IO handling happens.
+ */
+static gboolean
+io_watch_stdout (GIOChannel *source, GIOCondition condition, PasswordDialog *pdialog)
+{
+ static GString *str = NULL; /* Persistent buffer */
+
+ gchar buf[BUFSIZE]; /* Temporary buffer */
+ gsize bytes_read;
+ GError *error = NULL;
+
+ gchar *msg = NULL; /* Status error message */
+ GtkBuilder *dialog;
+
+ gboolean reinit = FALSE;
+
+ /* Initialize buffer */
+ if (str == NULL) {
+ str = g_string_new ("");
+ }
+
+ dialog = pdialog->ui;
+
+ if (g_io_channel_read_chars (source, buf, BUFSIZE, &bytes_read, &error) != G_IO_STATUS_NORMAL) {
+ g_warning ("IO Channel read error: %s", error->message);
+ g_error_free (error);
+
+ return TRUE;
+ }
+
+ str = g_string_append_len (str, buf, bytes_read);
+
+ /* In which state is the backend? */
+ switch (pdialog->backend_state) {
+ case PASSWD_STATE_AUTH:
+ /* Passwd is asking for our current password */
+
+ if (is_string_complete (str->str, "assword: ", "failure", "wrong", "error", NULL)) {
+ /* Which response did we get? */
+ passdlg_set_busy (pdialog, FALSE);
+
+ if (g_strrstr (str->str, "assword: ") != NULL) {
+ /* Authentication successful */
+
+ authenticated_user (pdialog);
+
+ } else {
+ /* Authentication failed */
+
+ if (pdialog->authenticated) {
+ /* This is a re-auth, and it failed.
+ * The password must have been changed in the meantime!
+ * Ask the user to re-authenticate
+ */
+
+ /* Update status message and auth state */
+ passdlg_set_status (pdialog, _("Your password has been changed since you initially authenticated! Please re-authenticate."));
+ } else {
+ passdlg_set_status (pdialog, _("That password was incorrect."));
+ }
+
+ /* Focus current password */
+ gtk_widget_grab_focus (GTK_WIDGET (pdialog->current_password));
+ }
+
+ reinit = TRUE;
+ }
+ break;
+ case PASSWD_STATE_NEW:
+ /* Passwd is asking for our new password */
+
+ if (is_string_complete (str->str, "assword: ", NULL)) {
+ /* Advance to next state */
+ pdialog->backend_state = PASSWD_STATE_RETYPE;
+
+ /* Pop retyped password from queue and into IO channel */
+ io_queue_pop (pdialog->backend_stdin_queue, pdialog->backend_stdin);
+
+ reinit = TRUE;
+ }
+ break;
+ case PASSWD_STATE_RETYPE:
+ /* Passwd is asking for our retyped new password */
+
+ if (is_string_complete (str->str, "successfully",
+ "short",
+ "longer",
+ "palindrome",
+ "dictionary",
+ "simpl", /* catches both simple and simplistic */
+ "similar",
+ "different",
+ "case",
+ "wrapped",
+ "recovered",
+ "recent"
+ "unchanged",
+ "match",
+ "1 numeric or special",
+ "failure",
+ NULL)) {
+
+ /* What response did we get? */
+ passdlg_set_busy (pdialog, FALSE);
+
+ if (g_strrstr (str->str, "successfully") != NULL) {
+ /* Hooray! */
+
+ passdlg_clear (pdialog);
+ passdlg_set_status (pdialog, _("Your password has been changed."));
+ } else {
+ /* Ohnoes! */
+
+ /* Focus new password */
+ gtk_widget_grab_focus (GTK_WIDGET (pdialog->new_password));
+
+ if (g_strrstr (str->str, "recovered") != NULL) {
+ /* What does this indicate?
+ * "Authentication information cannot be recovered?" from libpam? */
+ msg = g_strdup_printf (_("System error: %s."), str->str);
+ } else if (g_strrstr (str->str, "short") != NULL ||
+ g_strrstr (str->str, "longer") != NULL) {
+ msg = g_strdup (_("The password is too short."));
+ } else if (g_strrstr (str->str, "palindrome") != NULL ||
+ g_strrstr (str->str, "simpl") != NULL ||
+ g_strrstr (str->str, "dictionary") != NULL) {
+ msg = g_strdup (_("The password is too simple."));
+ } else if (g_strrstr (str->str, "similar") != NULL ||
+ g_strrstr (str->str, "different") != NULL ||
+ g_strrstr (str->str, "case") != NULL ||
+ g_strrstr (str->str, "wrapped") != NULL) {
+ msg = g_strdup (_("The old and new passwords are too similar."));
+ } else if (g_strrstr (str->str, "1 numeric or special") != NULL) {
+ msg = g_strdup (_("The new password must contain numeric or special character(s)."));
+ } else if (g_strrstr (str->str, "unchanged") != NULL ||
+ g_strrstr (str->str, "match") != NULL) {
+ msg = g_strdup (_("The old and new passwords are the same."));
+ } else if (g_strrstr (str->str, "recent") != NULL) {
+ msg = g_strdup (_("The new password has already been used recently."));
+ } else if (g_strrstr (str->str, "failure") != NULL) {
+ /* Authentication failure */
+ msg = g_strdup (_("Your password has been changed since you initially authenticated! Please re-authenticate."));
+
+ passdlg_set_auth_state (pdialog, FALSE);
+ }
+ }
+
+ reinit = TRUE;
+
+ if (msg != NULL) {
+ /* An error occured! */
+ passdlg_set_status (pdialog, msg);
+ g_free (msg);
+
+ /* At this point, passwd might have exited, in which case
+ * child_watch_cb should clean up for us and remove this watcher.
+ * On some error conditions though, passwd just re-prompts us
+ * for our new password. */
+
+ pdialog->backend_state = PASSWD_STATE_ERR;
+ }
+
+ /* child_watch_cb should clean up for us now */
+ }
+ break;
+ case PASSWD_STATE_NONE:
+ /* Passwd is not asking for anything yet */
+ if (is_string_complete (str->str, "assword: ", NULL)) {
+
+ /* If the user does not have a password set,
+ * passwd will immediately ask for the new password,
+ * so skip the AUTH phase */
+ if (is_string_complete (str->str, "new", "New", NULL)) {
+ gchar *pw;
+
+ pdialog->backend_state = PASSWD_STATE_NEW;
+
+ passdlg_set_busy (pdialog, FALSE);
+ authenticated_user (pdialog);
+
+ /* since passwd didn't ask for our old password
+ * in this case, simply remove it from the queue */
+ pw = g_queue_pop_head (pdialog->backend_stdin_queue);
+ g_free (pw);
+ } else {
+
+ pdialog->backend_state = PASSWD_STATE_AUTH;
+
+ /* Pop the IO queue, i.e. send current password */
+ io_queue_pop (pdialog->backend_stdin_queue, pdialog->backend_stdin);
+ }
+
+ reinit = TRUE;
+ }
+ break;
+ default:
+ /* Passwd has returned an error */
+ reinit = TRUE;
+ break;
+ }
+
+ if (reinit) {
+ g_string_free (str, TRUE);
+ str = NULL;
+ }
+
+ /* Continue calling us */
+ return TRUE;
+}
+
+/*
+ * }} Backend communication code
+ */
+
+/* Adds the current password to the IO queue */
+static void
+authenticate (PasswordDialog *pdialog)
+{
+ gchar *s;
+
+ s = g_strdup_printf ("%s\n", gtk_entry_get_text (pdialog->current_password));
+
+ g_queue_push_tail (pdialog->backend_stdin_queue, s);
+}
+
+/* Adds the new password twice to the IO queue */
+static void
+update_password (PasswordDialog *pdialog)
+{
+ gchar *s;
+
+ s = g_strdup_printf ("%s\n", gtk_entry_get_text (pdialog->new_password));
+
+ g_queue_push_tail (pdialog->backend_stdin_queue, s);
+ /* We need to allocate new space because io_queue_pop() g_free()s
+ * every element of the queue after it's done */
+ g_queue_push_tail (pdialog->backend_stdin_queue, g_strdup (s));
+}
+
+/* Sets dialog busy state according to busy
+ *
+ * When busy:
+ * Sets the cursor to busy
+ * Disables the interface to prevent that the user interferes
+ * Reverts all this when non-busy
+ *
+ * Note that this function takes into account the
+ * authentication state of the dialog. So setting the
+ * dialog to busy and then back to normal should leave
+ * the dialog unchanged.
+ */
+static void
+passdlg_set_busy (PasswordDialog *pdialog, gboolean busy)
+{
+ GtkBuilder *dialog;
+ GtkWidget *toplevel;
+ GdkCursor *cursor = NULL;
+ GdkDisplay *display;
+
+ dialog = pdialog->ui;
+
+ /* Set cursor */
+ toplevel = WID ("change-password");
+ display = gtk_widget_get_display (toplevel);
+ if (busy) {
+ cursor = gdk_cursor_new_for_display (display, GDK_WATCH);
+ }
+
+ gdk_window_set_cursor (gtk_widget_get_window (toplevel), cursor);
+ gdk_display_flush (display);
+
+ if (busy) {
+ gdk_cursor_unref (cursor);
+ }
+
+ /* Disable/Enable UI */
+ if (pdialog->authenticated) {
+ /* Authenticated state */
+
+ /* Enable/disable new password section */
+ g_object_set (pdialog->new_password, "sensitive", !busy, NULL);
+ g_object_set (pdialog->retyped_password, "sensitive", !busy, NULL);
+ g_object_set (WID ("new-password-label"), "sensitive", !busy, NULL);
+ g_object_set (WID ("retyped-password-label"), "sensitive", !busy, NULL);
+
+ /* Enable/disable change password button */
+ g_object_set (WID ("change-password-button"), "sensitive", !busy, NULL);
+
+ } else {
+ /* Not-authenticated state */
+
+ /* Enable/disable auth section state */
+ g_object_set (pdialog->current_password, "sensitive", !busy, NULL);
+ g_object_set (WID ("authenticate-button"), "sensitive", !busy, NULL);
+ g_object_set (WID ("current-password-label"), "sensitive", !busy, NULL);
+ }
+}
+
+/* Launch an error dialog */
+static void
+passdlg_error_dialog (GtkWindow *parent, const gchar *title,
+ const gchar *msg, const gchar *details)
+{
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new (parent, GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
+ msg);
+ if (title)
+ gtk_window_set_title (GTK_WINDOW (dialog), title);
+
+ if (details)
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ details);
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+}
+
+/* Set authenticated state of dialog according to state
+ *
+ * When in authenticated state:
+ * Disables authentication-part of interface
+ * Enables new-password-part of interface
+ * When in not-authenticated state:
+ * Enables authentication-part of interface
+ * Disables new-password-part of interface
+ * Disables the change-password-button
+ */
+static void
+passdlg_set_auth_state (PasswordDialog *pdialog, gboolean state)
+{
+ GtkBuilder *dialog;
+
+ dialog = pdialog->ui;
+
+ /* Widgets which require a not-authenticated state to be accessible */
+ g_object_set (pdialog->current_password, "sensitive", !state, NULL);
+ g_object_set (WID ("current-password-label"), "sensitive", !state, NULL);
+ g_object_set (WID ("authenticate-button"), "sensitive", !state, NULL);
+
+ /* Widgets which require authentication to be accessible */
+ g_object_set (pdialog->new_password, "sensitive", state, NULL);
+ g_object_set (pdialog->retyped_password, "sensitive", state, NULL);
+ g_object_set (WID ("new-password-label"), "sensitive", state, NULL);
+ g_object_set (WID ("retyped-password-label"), "sensitive", state, NULL);
+
+ if (!state) {
+ /* Disable change-password-button when in not-authenticated state */
+ g_object_set (WID ("change-password-button"), "sensitive", FALSE, NULL);
+ }
+
+ pdialog->authenticated = state;
+
+ if (state) {
+ /* Authenticated state */
+
+ /* Focus new password */
+ gtk_widget_grab_focus (GTK_WIDGET (pdialog->new_password));
+
+ /* Set open lock image */
+ gtk_image_set_from_icon_name (GTK_IMAGE (pdialog->dialog_image), "changes-allow", GTK_ICON_SIZE_DIALOG);
+ } else {
+ /* Not authenticated state */
+
+ /* Focus current password */
+ gtk_widget_grab_focus (GTK_WIDGET (pdialog->current_password));
+
+ /* Set closed lock image */
+ gtk_image_set_from_icon_name (GTK_IMAGE (pdialog->dialog_image), "changes-prevent", GTK_ICON_SIZE_DIALOG);
+ }
+}
+
+/* Set status field message */
+static void
+passdlg_set_status (PasswordDialog *pdialog, gchar *msg)
+{
+ g_object_set (pdialog->status_label, "label", msg, NULL);
+}
+
+/* Clear dialog (except the status message) */
+static void
+passdlg_clear (PasswordDialog *pdialog)
+{
+ /* Set non-authenticated state */
+ passdlg_set_auth_state (pdialog, FALSE);
+
+ /* Clear password entries */
+ gtk_entry_set_text (pdialog->current_password, "");
+ gtk_entry_set_text (pdialog->new_password, "");
+ gtk_entry_set_text (pdialog->retyped_password, "");
+}
+
+/* Start backend and handle errors
+ * If backend is already running, stop it
+ * If an error occurs, show error dialog */
+static gboolean
+passdlg_spawn_passwd (PasswordDialog *pdialog)
+{
+ GError *error = NULL;
+ gchar *details;
+
+ /* If backend is running, stop it */
+ stop_passwd (pdialog);
+
+ /* Spawn backend */
+ if (!spawn_passwd (pdialog, &error)) {
+ GtkWidget *parent = GTK_WIDGET (gtk_builder_get_object (pdialog->ui, "change-password"));
+
+ /* translators: Unable to launch <program>: <error message> */
+ details = g_strdup_printf (_("Unable to launch %s: %s"),
+ "/usr/bin/passwd", error->message);
+
+ passdlg_error_dialog (GTK_WINDOW (parent),
+ _("Unable to launch backend"),
+ _("A system error has occurred"),
+ details);
+
+ g_free (details);
+ g_error_free (error);
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* Called when the "Authenticate" button is clicked */
+static void
+passdlg_authenticate (GtkButton *button, PasswordDialog *pdialog)
+{
+ /* Set busy as this can be a long process */
+ passdlg_set_busy (pdialog, TRUE);
+
+ /* Update status message */
+ passdlg_set_status (pdialog, _("Checking password..."));
+
+ /* Spawn backend */
+ if (!passdlg_spawn_passwd (pdialog)) {
+ passdlg_set_busy (pdialog, FALSE);
+ return;
+ }
+
+ authenticate (pdialog);
+
+ /* Our IO watcher should now handle the rest */
+}
+
+/* Validate passwords
+ * Returns:
+ * PASSDLG_ERROR_NONE (0) if passwords are valid
+ * PASSDLG_ERROR_NEW_PASSWORD_EMPTY
+ * PASSDLG_ERROR_RETYPED_PASSWORD_EMPTY
+ * PASSDLG_ERROR_PASSWORDS_NOT_EQUAL
+ */
+static guint
+passdlg_validate_passwords (PasswordDialog *pdialog)
+{
+ GtkBuilder *dialog;
+ const gchar *new_password, *retyped_password;
+ glong nlen, rlen;
+
+ dialog = pdialog->ui;
+
+ new_password = gtk_entry_get_text (pdialog->new_password);
+ retyped_password = gtk_entry_get_text (pdialog->retyped_password);
+
+ nlen = g_utf8_strlen (new_password, -1);
+ rlen = g_utf8_strlen (retyped_password, -1);
+
+ if (nlen == 0) {
+ /* New password empty */
+ return PASSDLG_ERROR_NEW_PASSWORD_EMPTY;
+ }
+
+ if (rlen == 0) {
+ /* Retyped password empty */
+ return PASSDLG_ERROR_RETYPED_PASSWORD_EMPTY;
+ }
+
+ if (nlen != rlen || strncmp (new_password, retyped_password, nlen) != 0) {
+ /* Passwords not equal */
+ return PASSDLG_ERROR_PASSWORDS_NOT_EQUAL;
+ }
+
+ /* Success */
+ return PASSDLG_ERROR_NONE;
+}
+
+/* Refresh the valid password UI state, i.e. re-validate
+ * and enable/disable the Change Password button.
+ * Returns: Return value of passdlg_validate_passwords */
+static guint
+passdlg_refresh_password_state (PasswordDialog *pdialog)
+{
+ GtkBuilder *dialog;
+ guint ret;
+ gboolean valid = FALSE;
+
+ dialog = pdialog->ui;
+
+ ret = passdlg_validate_passwords (pdialog);
+
+ if (ret == PASSDLG_ERROR_NONE) {
+ valid = TRUE;
+ }
+
+ g_object_set (WID ("change-password-button"), "sensitive", valid, NULL);
+
+ return ret;
+}
+
+/* Called whenever any of the new password fields have changed */
+static void
+passdlg_check_password (GtkEntry *entry, PasswordDialog *pdialog)
+{
+ guint ret;
+
+ ret = passdlg_refresh_password_state (pdialog);
+
+ switch (ret) {
+ case PASSDLG_ERROR_NONE:
+ passdlg_set_status (pdialog, _("Click <b>Change password</b> to change your password."));
+ break;
+ case PASSDLG_ERROR_NEW_PASSWORD_EMPTY:
+ passdlg_set_status (pdialog, _("Please type your password in the <b>New password</b> field."));
+ break;
+ case PASSDLG_ERROR_RETYPED_PASSWORD_EMPTY:
+ passdlg_set_status (pdialog, _("Please type your password again in the <b>Retype new password</b> field."));
+ break;
+ case PASSDLG_ERROR_PASSWORDS_NOT_EQUAL:
+ passdlg_set_status (pdialog, _("The two passwords are not equal."));
+ break;
+ default:
+ g_warning ("Unknown passdlg_check_password error: %d", ret);
+ break;
+ }
+}
+
+/* Called when the "Change password" dialog-button is clicked
+ * Returns: TRUE if we want to keep the dialog running, FALSE otherwise */
+static gboolean
+passdlg_process_response (PasswordDialog *pdialog, gint response_id)
+{
+
+ if (response_id == GTK_RESPONSE_OK) {
+ /* Set busy as this can be a long process */
+ passdlg_set_busy (pdialog, TRUE);
+
+ /* Stop passwd if an error occured and it is still running */
+ if (pdialog->backend_state == PASSWD_STATE_ERR) {
+
+ /* Stop passwd, free resources */
+ stop_passwd (pdialog);
+ }
+
+ /* Check that the backend is still running, or that an error
+ * hass occured but it has not yet exited */
+ if (pdialog->backend_pid == -1) {
+ /* If it is not, re-run authentication */
+
+ /* Spawn backend */
+ if (!passdlg_spawn_passwd (pdialog)) {
+ return TRUE;
+ }
+
+ /* Add current and new passwords to queue */
+ authenticate (pdialog);
+ update_password (pdialog);
+ } else {
+ /* Only add new passwords to queue */
+ update_password (pdialog);
+
+ /* Pop new password through the backend */
+ io_queue_pop (pdialog->backend_stdin_queue, pdialog->backend_stdin);
+ }
+
+ /* Our IO watcher should now handle the rest */
+
+ /* Keep the dialog running */
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/* Activates (moves focus or activates) widget w */
+static void
+passdlg_activate (GtkEntry *entry, GtkWidget *w)
+{
+ if (GTK_IS_BUTTON (w)) {
+ gtk_widget_activate (w);
+ } else {
+ gtk_widget_grab_focus (w);
+ }
+}
+
+/* Initialize password dialog */
+static void
+passdlg_init (PasswordDialog *pdialog, GtkWindow *parent)
+{
+ GtkBuilder *dialog;
+ GtkWidget *wpassdlg;
+ GtkAccelGroup *group;
+
+ /* Initialize dialog */
+ dialog = gtk_builder_new ();
+ gtk_builder_add_from_file (dialog, MATECC_UI_DIR "/mate-about-me-password.ui", NULL);
+ pdialog->ui = dialog;
+
+ wpassdlg = WID ("change-password");
+ capplet_set_icon (wpassdlg, "user-info");
+
+ group = gtk_accel_group_new ();
+
+ /*
+ * Initialize backend
+ */
+
+ /* Initialize backend_pid. -1 means the backend is not running */
+ pdialog->backend_pid = -1;
+
+ /* Initialize IO Channels */
+ pdialog->backend_stdin = NULL;
+ pdialog->backend_stdout = NULL;
+
+ /* Initialize write queue */
+ pdialog->backend_stdin_queue = g_queue_new ();
+
+ /* Initialize watchers */
+ pdialog->backend_child_watch_id = 0;
+ pdialog->backend_stdout_watch_id = 0;
+
+ /* Initialize backend state */
+ pdialog->backend_state = PASSWD_STATE_NONE;
+
+ /*
+ * Initialize UI
+ */
+
+ /* Initialize pdialog widgets */
+ pdialog->current_password = GTK_ENTRY (WID ("current-password"));
+ pdialog->new_password = GTK_ENTRY (WID ("new-password"));
+ pdialog->retyped_password = GTK_ENTRY (WID ("retyped-password"));
+ pdialog->dialog_image = GTK_IMAGE (WID ("dialog-image"));
+ pdialog->status_label = GTK_LABEL (WID ("status-label"));
+
+ /* Initialize accelerators */
+ gtk_widget_add_accelerator (GTK_WIDGET (pdialog->current_password),
+ "activate", group,
+ GDK_Return, 0,
+ 0);
+
+ gtk_widget_add_accelerator (GTK_WIDGET (pdialog->new_password),
+ "activate", group,
+ GDK_Return, 0,
+ 0);
+
+ /* Activate authenticate-button when enter is pressed in current-password */
+ g_signal_connect (G_OBJECT (pdialog->current_password), "activate",
+ G_CALLBACK (passdlg_activate), WID ("authenticate-button"));
+
+ /* Activate retyped-password when enter is pressed in new-password */
+ g_signal_connect (G_OBJECT (pdialog->new_password), "activate",
+ G_CALLBACK (passdlg_activate), pdialog->retyped_password);
+
+ /* Clear status message */
+ passdlg_set_status (pdialog, "");
+
+ /* Set non-authenticated state */
+ passdlg_set_auth_state (pdialog, FALSE);
+
+ /* Connect signal handlers */
+ g_signal_connect (G_OBJECT (WID ("authenticate-button")), "clicked",
+ G_CALLBACK (passdlg_authenticate), pdialog);
+
+ /* Verify new passwords on-the-fly */
+ g_signal_connect (G_OBJECT (WID ("new-password")), "changed",
+ G_CALLBACK (passdlg_check_password), pdialog);
+ g_signal_connect (G_OBJECT (WID ("retyped-password")), "changed",
+ G_CALLBACK (passdlg_check_password), pdialog);
+
+ /* Set misc dialog properties */
+ gtk_window_set_resizable (GTK_WINDOW (wpassdlg), FALSE);
+ gtk_window_set_transient_for (GTK_WINDOW (wpassdlg), GTK_WINDOW (parent));
+}
+
+/* Main */
+void
+mate_about_me_password (GtkWindow *parent)
+{
+ PasswordDialog *pdialog;
+ GtkBuilder *dialog;
+ GtkWidget *wpassdlg;
+
+ gint result;
+ gboolean response;
+
+ /* Initialize dialog */
+ pdialog = g_new0 (PasswordDialog, 1);
+ passdlg_init (pdialog, parent);
+
+ dialog = pdialog->ui;
+ wpassdlg = WID ("change-password");
+
+ /* Go! */
+ gtk_widget_show_all (wpassdlg);
+
+ do {
+ result = gtk_dialog_run (GTK_DIALOG (wpassdlg));
+ response = passdlg_process_response (pdialog, result);
+ } while (response);
+
+ /* Clean up */
+ stop_passwd (pdialog);
+ gtk_widget_destroy (wpassdlg);
+ g_queue_free (pdialog->backend_stdin_queue);
+ g_object_unref (dialog);
+ g_free (pdialog);
+}
diff --git a/capplets/about-me/mate-about-me-password.h b/capplets/about-me/mate-about-me-password.h
new file mode 100644
index 00000000..39f67cd8
--- /dev/null
+++ b/capplets/about-me/mate-about-me-password.h
@@ -0,0 +1,9 @@
+#ifndef __MATE_ABOUT_ME_PASSWORD_H__
+#define __MATE_ABOUT_ME_PASSWORD_H__
+
+#include <gtk/gtk.h>
+
+void
+mate_about_me_password (GtkWindow *parent);
+
+#endif /* __MATE_ABOUT_ME_PASSWORD_H__ */
diff --git a/capplets/about-me/mate-about-me-password.ui b/capplets/about-me/mate-about-me-password.ui
new file mode 100644
index 00000000..b9c433a5
--- /dev/null
+++ b/capplets/about-me/mate-about-me-password.ui
@@ -0,0 +1,319 @@
+<?xml version="1.0"?>
+<interface>
+ <requires lib="gtk+" version="2.16"/>
+ <!-- interface-naming-policy toplevel-contextual -->
+ <object class="GtkDialog" id="change-password">
+ <property name="border_width">6</property>
+ <property name="title" translatable="yes">Change password</property>
+ <property name="resizable">False</property>
+ <property name="type_hint">dialog</property>
+ <property name="has_separator">False</property>
+ <child internal-child="vbox">
+ <object class="GtkVBox" id="dialog-vbox">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkHBox" id="container-hbox">
+ <property name="visible">True</property>
+ <property name="border_width">6</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkImage" id="dialog-image">
+ <property name="visible">True</property>
+ <property name="yalign">0</property>
+ <property name="icon_name">gtk-dialog-authentication</property>
+ <property name="icon-size">6</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="main-vbox">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="header-label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Change your password</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ <attribute name="scale" value="1.2"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="description-label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0</property>
+ <property name="label" translatable="yes">To change your password, enter your current password in the field below and click &lt;b&gt;Authenticate&lt;/b&gt;.
+After you have authenticated, enter your new password, retype it for verification and click &lt;b&gt;Change password&lt;/b&gt;.</property>
+ <property name="use_markup">True</property>
+ <property name="wrap">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="entry-hbox">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkVBox" id="entry-labels-vbox">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <property name="homogeneous">True</property>
+ <child>
+ <object class="GtkLabel" id="current-password-label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Current _password:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">current-password</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="new-password-label">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_New password:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">new-password</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="retyped-password-label">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Retype new password:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">retyped-password</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="entry-vbox">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <property name="homogeneous">True</property>
+ <child>
+ <object class="GtkHBox" id="auth-hbox">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkEntry" id="current-password">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="visibility">False</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="authenticate-button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <child>
+ <object class="GtkAlignment" id="alignment1">
+ <property name="visible">True</property>
+ <property name="xscale">0</property>
+ <property name="yscale">0</property>
+ <child>
+ <object class="GtkHBox" id="hbox73">
+ <property name="visible">True</property>
+ <property name="spacing">2</property>
+ <child>
+ <object class="GtkImage" id="image2">
+ <property name="visible">True</property>
+ <property name="stock">gtk-apply</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label1070">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Authenticate</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="new-password">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="visibility">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="retyped-password">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="visibility">False</property>
+ <property name="activates_default">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="status-label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Please type your password again in the &lt;b&gt;Retype new password&lt;/b&gt; field.</property>
+ <property name="use_markup">True</property>
+ <property name="justify">center</property>
+ <property name="wrap">True</property>
+ </object>
+ <packing>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <object class="GtkHButtonBox" id="dialog-action-area">
+ <property name="visible">True</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="cancel-button">
+ <property name="label">gtk-close</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="change-password-button">
+ <property name="label" translatable="yes">Change pa_ssword</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-7">cancel-button</action-widget>
+ <action-widget response="-5">change-password-button</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/capplets/about-me/mate-about-me.c b/capplets/about-me/mate-about-me.c
new file mode 100644
index 00000000..0935ab51
--- /dev/null
+++ b/capplets/about-me/mate-about-me.c
@@ -0,0 +1,1005 @@
+/* mate-about-me.c
+ * Copyright (C) 2002 Diego Gonzalez
+ *
+ * Written by: Diego Gonzalez <[email protected]>
+ *
+ * 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, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <glib/gstdio.h>
+#include <gio/gio.h>
+#include <mateconf/mateconf-client.h>
+#include <unistd.h>
+#include <libebook/e-book.h>
+#include <dbus/dbus-glib-bindings.h>
+
+#define MATE_DESKTOP_USE_UNSTABLE_API
+#include <libmateui/mate-desktop-thumbnail.h>
+
+#include "e-image-chooser.h"
+#include "mate-about-me-password.h"
+#include "mate-about-me-fingerprint.h"
+#include "marshal.h"
+
+#include "capplet-util.h"
+
+#define MAX_HEIGHT 150
+#define MAX_WIDTH 150
+
+#define EMAIL_SLOTS 4
+
+typedef struct {
+ EContact *contact;
+ EBook *book;
+
+ GtkBuilder *dialog;
+ GtkWidget *enable_fingerprint_button;
+ GtkWidget *disable_fingerprint_button;
+ GtkWidget *image_chooser;
+
+ GdkScreen *screen;
+ GtkIconTheme *theme;
+ MateDesktopThumbnailFactory *thumbs;
+
+ EContactAddress *addr1;
+ EContactAddress *addr2;
+ gchar *email[EMAIL_SLOTS];
+ const gchar *email_types[EMAIL_SLOTS];
+
+ gboolean have_image;
+ gboolean image_changed;
+ gboolean create_self;
+
+ gchar *person;
+ gchar *login;
+ gchar *username;
+
+ guint commit_timeout_id;
+} MateAboutMe;
+
+static MateAboutMe *me = NULL;
+
+struct WidToCid {
+ gchar *wid;
+ guint cid;
+};
+
+enum {
+ ADDRESS_STREET = 1,
+ ADDRESS_POBOX,
+ ADDRESS_LOCALITY,
+ ADDRESS_CODE,
+ ADDRESS_REGION,
+ ADDRESS_COUNTRY
+};
+
+#define EMAIL_WORK 0
+#define EMAIL_HOME 1
+#define ADDRESS_HOME 21
+#define ADDRESS_WORK 27
+
+struct WidToCid ids[] = {
+
+ { "email-work-e", 0 }, /* 00 */
+ { "email-home-e", 1 }, /* 01 */
+
+ { "phone-home-e", E_CONTACT_PHONE_HOME }, /* 02 */
+ { "phone-mobile-e", E_CONTACT_PHONE_MOBILE }, /* 03 */
+ { "phone-work-e", E_CONTACT_PHONE_BUSINESS }, /* 04 */
+ { "phone-work-fax-e", E_CONTACT_PHONE_BUSINESS_FAX }, /* 05 */
+
+ { "im-jabber-e", E_CONTACT_IM_JABBER_HOME_1 }, /* 06 */
+ { "im-msn-e", E_CONTACT_IM_MSN_HOME_1 }, /* 07 */
+ { "im-icq-e", E_CONTACT_IM_ICQ_HOME_1 }, /* 08 */
+ { "im-yahoo-e", E_CONTACT_IM_YAHOO_HOME_1 }, /* 09 */
+ { "im-aim-e", E_CONTACT_IM_AIM_HOME_1 }, /* 10 */
+ { "im-groupwise-e", E_CONTACT_IM_GROUPWISE_HOME_1 }, /* 11 */
+
+ { "web-homepage-e", E_CONTACT_HOMEPAGE_URL }, /* 12 */
+ { "web-calendar-e", E_CONTACT_CALENDAR_URI }, /* 13 */
+ { "web-weblog-e", E_CONTACT_BLOG_URL }, /* 14 */
+
+ { "job-profession-e", E_CONTACT_ROLE }, /* 15 */
+ { "job-title-e", E_CONTACT_TITLE }, /* 16 */
+ { "job-dept-e", E_CONTACT_ORG_UNIT }, /* 17 */
+ { "job-assistant-e", E_CONTACT_ASSISTANT }, /* 18 */
+ { "job-company-e", E_CONTACT_ORG }, /* 19 */
+ { "job-manager-e", E_CONTACT_MANAGER }, /* 20 */
+
+ { "addr-street-1", ADDRESS_STREET }, /* 21 */
+ { "addr-po-1", ADDRESS_POBOX }, /* 22 */
+ { "addr-locality-1", ADDRESS_LOCALITY }, /* 23 */
+ { "addr-code-1", ADDRESS_CODE }, /* 24 */
+ { "addr-region-1", ADDRESS_REGION }, /* 25 */
+ { "addr-country-1", ADDRESS_COUNTRY }, /* 26 */
+
+ { "addr-street-2", ADDRESS_STREET }, /* 27 */
+ { "addr-po-2", ADDRESS_POBOX }, /* 28 */
+ { "addr-locality-2", ADDRESS_LOCALITY }, /* 29 */
+ { "addr-code-2", ADDRESS_CODE }, /* 30 */
+ { "addr-region-2", ADDRESS_REGION }, /* 31 */
+ { "addr-country-2", ADDRESS_COUNTRY }, /* 32 */
+
+ { NULL, 0 }
+};
+
+#define ATTRIBUTE_HOME "HOME"
+#define ATTRIBUTE_WORK "WORK"
+#define ATTRIBUTE_OTHER "OTHER"
+
+static void about_me_set_address_field (EContactAddress *, guint, gchar *);
+
+
+/*** Utility functions ***/
+static void
+about_me_error (GtkWindow *parent, gchar *str)
+{
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new (parent,
+ GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK, str);
+
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+}
+
+/********************/
+static void
+about_me_destroy (void)
+{
+ e_contact_address_free (me->addr1);
+ e_contact_address_free (me->addr2);
+
+ if (me->contact)
+ g_object_unref (me->contact);
+ if (me->book)
+ g_object_unref (me->book);
+ if (me->dialog)
+ g_object_unref (me->dialog);
+
+ g_free (me->email[0]);
+ g_free (me->email[1]);
+ g_free (me->email[2]);
+ g_free (me->email[3]);
+
+ g_free (me->person);
+ g_free (me->login);
+ g_free (me->username);
+ g_free (me);
+ me = NULL;
+}
+
+static void
+about_me_update_email (MateAboutMe *me)
+{
+ GList *attrs = NULL;
+ gint i;
+
+ for (i = 0; i < EMAIL_SLOTS; ++i) {
+ if (me->email[i] != NULL) {
+ EVCardAttribute *attr;
+ const gchar *type = me->email_types[i];
+
+ attr = e_vcard_attribute_new (NULL, EVC_EMAIL);
+
+ e_vcard_attribute_add_param_with_value (attr,
+ e_vcard_attribute_param_new (EVC_TYPE),
+ type ? type : ATTRIBUTE_OTHER);
+
+ e_vcard_attribute_add_value (attr, me->email[i]);
+ attrs = g_list_append (attrs, attr);
+ }
+ }
+
+ e_contact_set_attributes (me->contact, E_CONTACT_EMAIL, attrs);
+
+ g_list_foreach (attrs, (GFunc) e_vcard_attribute_free, NULL);
+ g_list_free (attrs);
+}
+
+static void
+about_me_commit (MateAboutMe *me)
+{
+ EContactName *name;
+
+ char *strings[4], **stringptr;
+ char *fileas;
+
+ name = NULL;
+
+ if (me->create_self) {
+ if (me->username == NULL)
+ fileas = g_strdup ("Myself");
+ else {
+ name = e_contact_name_from_string (me->username);
+
+ stringptr = strings;
+ if (name->family && *name->family)
+ *(stringptr++) = name->family;
+ if (name->given && *name->given)
+ *(stringptr++) = name->given;
+ *stringptr = NULL;
+ fileas = g_strjoinv (", ", strings);
+ }
+
+ e_contact_set (me->contact, E_CONTACT_FILE_AS, fileas);
+ e_contact_set (me->contact, E_CONTACT_NICKNAME, me->login);
+ e_contact_set (me->contact, E_CONTACT_FULL_NAME, me->username);
+
+ e_contact_name_free (name);
+ g_free (fileas);
+ }
+
+ about_me_update_email (me);
+
+ if (me->create_self) {
+ e_book_add_contact (me->book, me->contact, NULL);
+ e_book_set_self (me->book, me->contact, NULL);
+ } else {
+ if (!e_book_commit_contact (me->book, me->contact, NULL))
+ g_warning ("Could not save contact information");
+ }
+
+ me->create_self = FALSE;
+}
+
+static gboolean
+about_me_commit_from_timeout (MateAboutMe *me)
+{
+ about_me_commit (me);
+
+ return FALSE;
+}
+
+static gboolean
+about_me_focus_out (GtkWidget *widget, GdkEventFocus *event, MateAboutMe *unused)
+{
+ gchar *str;
+ const gchar *wid;
+ gint i;
+
+ if (me == NULL)
+ return FALSE;
+
+ wid = gtk_buildable_get_name (GTK_BUILDABLE (widget));
+
+ if (wid == NULL)
+ return FALSE;
+
+ for (i = 0; ids[i].wid != NULL; i++)
+ if (strcmp (ids[i].wid, wid) == 0)
+ break;
+
+ if (GTK_IS_ENTRY (widget)) {
+ str = gtk_editable_get_chars (GTK_EDITABLE (widget), 0, -1);
+ } else if (GTK_IS_TEXT_VIEW (widget)) {
+ GtkTextBuffer *buffer;
+ GtkTextIter iter_start;
+ GtkTextIter iter_end;
+
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
+ gtk_text_buffer_get_start_iter (buffer, &iter_start);
+ iter_end = iter_start;
+ gtk_text_iter_forward_to_end (&iter_end);
+ str = gtk_text_iter_get_text (&iter_start, &iter_end);
+ } else {
+ return FALSE;
+ }
+
+ if (i == EMAIL_HOME || i == EMAIL_WORK) {
+
+ g_free (me->email[ids[i].cid]);
+ if (str[0] == '\0')
+ me->email[ids[i].cid] = NULL;
+ else
+ me->email[ids[i].cid] = g_strdup (str);
+ me->email_types[ids[i].cid] = (i == EMAIL_HOME) ? ATTRIBUTE_HOME : ATTRIBUTE_WORK;
+ /* FIXME: i'm getting an empty address field in evolution */
+ } else if (i >= ADDRESS_HOME && i < ADDRESS_WORK) {
+ about_me_set_address_field (me->addr1, ids[i].cid, str);
+ e_contact_set (me->contact, E_CONTACT_ADDRESS_HOME, me->addr1);
+ } else if (i >= ADDRESS_WORK) {
+ about_me_set_address_field (me->addr2, ids[i].cid, str);
+ e_contact_set (me->contact, E_CONTACT_ADDRESS_WORK, me->addr2);
+ } else {
+ e_contact_set (me->contact, ids[i].cid, str);
+ }
+
+ g_free (str);
+
+ if (me->commit_timeout_id) {
+ g_source_remove (me->commit_timeout_id);
+ }
+
+ me->commit_timeout_id = g_timeout_add (600, (GSourceFunc) about_me_commit_from_timeout, me);
+
+ return FALSE;
+}
+
+/*
+ * Helpers
+ */
+
+static gchar *
+about_me_get_address_field (EContactAddress *addr, guint cid)
+{
+ gchar *str;
+
+ if (addr == NULL) {
+ return NULL;
+ }
+
+ switch (cid) {
+ case ADDRESS_STREET:
+ str = addr->street;
+ break;
+ case ADDRESS_POBOX:
+ str = addr->po;
+ break;
+ case ADDRESS_LOCALITY:
+ str = addr->locality;
+ break;
+ case ADDRESS_CODE:
+ str = addr->code;
+ break;
+ case ADDRESS_REGION:
+ str = addr->region;
+ break;
+ case ADDRESS_COUNTRY:
+ str = addr->country;
+ break;
+ default:
+ str = NULL;
+ break;
+ }
+
+ return str;
+}
+
+static void
+about_me_set_address_field (EContactAddress *addr, guint cid, gchar *str)
+{
+ switch (cid) {
+ case ADDRESS_STREET:
+ g_free (addr->street);
+ addr->street = g_strdup (str);
+ break;
+ case ADDRESS_POBOX:
+ g_free (addr->po);
+ addr->po = g_strdup (str);
+ break;
+ case ADDRESS_LOCALITY:
+ g_free (addr->locality);
+ addr->locality = g_strdup (str);
+ break;
+ case ADDRESS_CODE:
+ g_free (addr->code);
+ addr->code = g_strdup (str);
+ break;
+ case ADDRESS_REGION:
+ g_free (addr->region);
+ addr->region = g_strdup (str);
+ break;
+ case ADDRESS_COUNTRY:
+ g_free (addr->country);
+ addr->country = g_strdup (str);
+ break;
+ }
+}
+
+static void
+about_me_setup_email (MateAboutMe *me)
+{
+ GList *attrs, *la;
+ gboolean has_home = FALSE, has_work = FALSE;
+ guint i;
+
+ attrs = e_contact_get_attributes (me->contact, E_CONTACT_EMAIL);
+
+ for (la = attrs, i = 0; la; la = la->next, ++i) {
+ EVCardAttribute *a = la->data;
+
+ me->email[i] = e_vcard_attribute_get_value (a);
+ if (e_vcard_attribute_has_type (a, ATTRIBUTE_HOME)) {
+ me->email_types[i] = ATTRIBUTE_HOME;
+ if (!has_home) {
+ ids[EMAIL_HOME].cid = i;
+ has_home = TRUE;
+ }
+ } else if (e_vcard_attribute_has_type (a, ATTRIBUTE_WORK)) {
+ me->email_types[i] = ATTRIBUTE_WORK;
+ if (!has_work) {
+ ids[EMAIL_WORK].cid = i;
+ has_work = TRUE;
+ }
+ } else {
+ me->email_types[i] = ATTRIBUTE_OTHER;
+ }
+
+ e_vcard_attribute_free (a);
+ }
+
+ g_list_free (attrs);
+
+ if (ids[EMAIL_HOME].cid == ids[EMAIL_WORK].cid) {
+ if (has_home)
+ ids[EMAIL_WORK].cid = 1;
+ else
+ ids[EMAIL_HOME].cid = 0;
+ }
+
+ me->email_types[ids[EMAIL_WORK].cid] = ATTRIBUTE_WORK;
+ me->email_types[ids[EMAIL_HOME].cid] = ATTRIBUTE_HOME;
+}
+
+/**
+ * about_me_load_string_field:
+ *
+ * wid: UI widget name
+ * cid: id of the field (EDS id)
+ * aid: position in the array WidToCid
+ **/
+
+static void
+about_me_load_string_field (MateAboutMe *me, const gchar *wid, guint cid, guint aid)
+{
+ GtkWidget *widget;
+ GtkBuilder *dialog;
+ const gchar *str;
+
+ dialog = me->dialog;
+
+ widget = WID (wid);
+
+ if (me->create_self == TRUE) {
+ g_signal_connect (widget, "focus-out-event", G_CALLBACK (about_me_focus_out), me);
+ return;
+ }
+
+ if (aid == EMAIL_HOME || aid == EMAIL_WORK) {
+ str = e_contact_get_const (me->contact, E_CONTACT_EMAIL_1 + cid);
+ } else if (aid >= ADDRESS_HOME && aid < ADDRESS_WORK) {
+ str = about_me_get_address_field (me->addr1, cid);
+ } else if (aid >= ADDRESS_WORK) {
+ str = about_me_get_address_field (me->addr2, cid);
+ } else {
+ str = e_contact_get_const (me->contact, cid);
+ }
+
+ str = str ? str : "";
+
+ if (GTK_IS_ENTRY (widget)) {
+ gtk_entry_set_text (GTK_ENTRY (widget), str);
+ } else if (GTK_IS_TEXT_VIEW (widget)) {
+ GtkTextBuffer *buffer;
+
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
+ gtk_text_buffer_set_text (buffer, str, -1);
+ }
+
+ g_signal_connect (widget, "focus-out-event", G_CALLBACK (about_me_focus_out), me);
+}
+
+static void
+about_me_load_photo (MateAboutMe *me, EContact *contact)
+{
+ GtkBuilder *dialog;
+ EContactPhoto *photo;
+
+ dialog = me->dialog;
+
+ if (me->person)
+ e_image_chooser_set_from_file (E_IMAGE_CHOOSER (me->image_chooser), me->person);
+
+ photo = e_contact_get (contact, E_CONTACT_PHOTO);
+
+ if (photo && photo->type == E_CONTACT_PHOTO_TYPE_INLINED) {
+ me->have_image = TRUE;
+ e_image_chooser_set_image_data (E_IMAGE_CHOOSER (me->image_chooser),
+ (char *) photo->data.inlined.data, photo->data.inlined.length);
+ e_contact_photo_free (photo);
+ } else {
+ me->have_image = FALSE;
+ }
+}
+
+static void
+about_me_update_photo (MateAboutMe *me)
+{
+ GtkBuilder *dialog;
+ EContactPhoto *photo;
+ gchar *file;
+ GError *error;
+
+ guchar *data;
+ gsize length;
+
+ dialog = me->dialog;
+
+
+ if (me->image_changed && me->have_image) {
+ GdkPixbufLoader *loader = gdk_pixbuf_loader_new ();
+ GdkPixbuf *pixbuf, *scaled;
+ int height, width;
+ gboolean do_scale = FALSE;
+ float scale;
+
+ e_image_chooser_get_image_data (E_IMAGE_CHOOSER (me->image_chooser), (char **) &data, &length);
+
+ /* Before updating the image in EDS scale it to a reasonable size
+ so that the user doesn't get an application that does not respond
+ or that takes 100% CPU */
+ gdk_pixbuf_loader_write (loader, data, length, NULL);
+ gdk_pixbuf_loader_close (loader, NULL);
+
+ pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
+
+ if (pixbuf)
+ g_object_ref (pixbuf);
+
+ g_object_unref (loader);
+
+ height = gdk_pixbuf_get_height (pixbuf);
+ width = gdk_pixbuf_get_width (pixbuf);
+
+ if (height >= width && height > MAX_HEIGHT) {
+ scale = (float)MAX_HEIGHT/height;
+ do_scale = TRUE;
+ } else if (width > height && width > MAX_WIDTH) {
+ scale = (float)MAX_WIDTH/width;
+ do_scale = TRUE;
+ }
+
+ if (do_scale) {
+ char *scaled_data = NULL;
+ gsize scaled_length;
+
+ scaled = gdk_pixbuf_scale_simple (pixbuf, width*scale, height*scale, GDK_INTERP_BILINEAR);
+ gdk_pixbuf_save_to_buffer (scaled, &scaled_data, &scaled_length, "png", NULL,
+ "compression", "9", NULL);
+
+ g_free (data);
+ data = (guchar *) scaled_data;
+ length = scaled_length;
+ }
+
+ photo = g_new0 (EContactPhoto, 1);
+ photo->type = E_CONTACT_PHOTO_TYPE_INLINED;
+ photo->data.inlined.data = data;
+ photo->data.inlined.length = length;
+ e_contact_set (me->contact, E_CONTACT_PHOTO, photo);
+
+ /* Save the image for MDM */
+ /* FIXME: I would have to read the default used by the mdmgreeter program */
+ error = NULL;
+ file = g_build_filename (g_get_home_dir (), ".face", NULL);
+ if (g_file_set_contents (file,
+ (gchar *) photo->data.inlined.data,
+ photo->data.inlined.length,
+ &error) != FALSE) {
+ g_chmod (file, 0644);
+ } else {
+ g_warning ("Could not create %s: %s", file, error->message);
+ g_error_free (error);
+ }
+
+ g_free (file);
+
+ e_contact_photo_free (photo);
+
+ } else if (me->image_changed && !me->have_image) {
+ /* Update the image in the card */
+ e_contact_set (me->contact, E_CONTACT_PHOTO, NULL);
+
+ file = g_build_filename (g_get_home_dir (), ".face", NULL);
+
+ g_unlink (file);
+
+ g_free (file);
+ }
+
+ about_me_commit (me);
+}
+
+static void
+about_me_load_info (MateAboutMe *me)
+{
+ gint i;
+
+ if (me->create_self == FALSE) {
+ me->addr1 = e_contact_get (me->contact, E_CONTACT_ADDRESS_HOME);
+ if (me->addr1 == NULL)
+ me->addr1 = g_new0 (EContactAddress, 1);
+ me->addr2 = e_contact_get (me->contact, E_CONTACT_ADDRESS_WORK);
+ if (me->addr2 == NULL)
+ me->addr2 = g_new0 (EContactAddress, 1);
+ } else {
+ me->addr1 = g_new0 (EContactAddress, 1);
+ me->addr2 = g_new0 (EContactAddress, 1);
+ }
+
+ for (i = 0; ids[i].wid != NULL; i++) {
+ about_me_load_string_field (me, ids[i].wid, ids[i].cid, i);
+ }
+
+ set_fingerprint_label (me->enable_fingerprint_button,
+ me->disable_fingerprint_button);
+}
+
+static void
+about_me_update_preview (GtkFileChooser *chooser,
+ MateAboutMe *me)
+{
+ gchar *uri;
+
+ uri = gtk_file_chooser_get_preview_uri (chooser);
+
+ if (uri) {
+ GtkWidget *image;
+ GdkPixbuf *pixbuf = NULL;
+ GFile *file;
+ GFileInfo *file_info;
+
+ if (!me->thumbs)
+ me->thumbs = mate_desktop_thumbnail_factory_new (MATE_DESKTOP_THUMBNAIL_SIZE_NORMAL);
+
+ file = g_file_new_for_uri (uri);
+ file_info = g_file_query_info (file,
+ G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+ G_FILE_QUERY_INFO_NONE,
+ NULL, NULL);
+ g_object_unref (file);
+
+ if (file_info != NULL) {
+ const gchar *content_type;
+
+ content_type = g_file_info_get_content_type (file_info);
+ if (content_type) {
+ gchar *mime_type;
+
+ mime_type = g_content_type_get_mime_type (content_type);
+
+ pixbuf = mate_desktop_thumbnail_factory_generate_thumbnail (me->thumbs,
+ uri,
+ mime_type);
+ g_free (mime_type);
+ }
+ g_object_unref (file_info);
+ }
+
+ image = gtk_file_chooser_get_preview_widget (chooser);
+
+ if (pixbuf != NULL) {
+ gtk_image_set_from_pixbuf (GTK_IMAGE (image), pixbuf);
+ g_object_unref (pixbuf);
+ } else {
+ gtk_image_set_from_stock (GTK_IMAGE (image),
+ "gtk-dialog-question",
+ GTK_ICON_SIZE_DIALOG);
+ }
+ }
+ gtk_file_chooser_set_preview_widget_active (chooser, TRUE);
+}
+
+static void
+about_me_image_clicked_cb (GtkWidget *button, MateAboutMe *me)
+{
+ GtkFileChooser *chooser_dialog;
+ gint response;
+ GtkBuilder *dialog;
+ GtkWidget *image;
+ const gchar *chooser_dir = DATADIR"/pixmaps/faces";
+ const gchar *pics_dir;
+ GtkFileFilter *filter;
+
+ dialog = me->dialog;
+
+ chooser_dialog = GTK_FILE_CHOOSER (
+ gtk_file_chooser_dialog_new (_("Select Image"), GTK_WINDOW (WID ("about-me-dialog")),
+ GTK_FILE_CHOOSER_ACTION_OPEN,
+ _("No Image"), GTK_RESPONSE_NO,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
+ NULL));
+ gtk_window_set_modal (GTK_WINDOW (chooser_dialog), TRUE);
+ gtk_dialog_set_default_response (GTK_DIALOG (chooser_dialog), GTK_RESPONSE_ACCEPT);
+
+ gtk_file_chooser_add_shortcut_folder (chooser_dialog, chooser_dir, NULL);
+ pics_dir = g_get_user_special_dir (G_USER_DIRECTORY_PICTURES);
+ if (pics_dir != NULL)
+ gtk_file_chooser_add_shortcut_folder (chooser_dialog, pics_dir, NULL);
+
+ if (!g_file_test (chooser_dir, G_FILE_TEST_IS_DIR))
+ chooser_dir = g_get_home_dir ();
+
+ gtk_file_chooser_set_current_folder (chooser_dialog, chooser_dir);
+ gtk_file_chooser_set_use_preview_label (chooser_dialog, FALSE);
+
+ image = gtk_image_new ();
+ gtk_file_chooser_set_preview_widget (chooser_dialog, image);
+ gtk_widget_set_size_request (image, 128, -1);
+
+ gtk_widget_show (image);
+
+ g_signal_connect (chooser_dialog, "update-preview",
+ G_CALLBACK (about_me_update_preview), me);
+
+ filter = gtk_file_filter_new ();
+ gtk_file_filter_set_name (filter, _("Images"));
+ gtk_file_filter_add_pixbuf_formats (filter);
+ gtk_file_chooser_add_filter (chooser_dialog, filter);
+ filter = gtk_file_filter_new ();
+ gtk_file_filter_set_name (filter, _("All Files"));
+ gtk_file_filter_add_pattern(filter, "*");
+ gtk_file_chooser_add_filter (chooser_dialog, filter);
+
+ response = gtk_dialog_run (GTK_DIALOG (chooser_dialog));
+
+ if (response == GTK_RESPONSE_ACCEPT) {
+ gchar* filename;
+
+ filename = gtk_file_chooser_get_filename (chooser_dialog);
+ me->have_image = TRUE;
+ me->image_changed = TRUE;
+
+ e_image_chooser_set_from_file (E_IMAGE_CHOOSER (me->image_chooser), filename);
+ g_free (filename);
+ about_me_update_photo (me);
+ } else if (response == GTK_RESPONSE_NO) {
+ me->have_image = FALSE;
+ me->image_changed = TRUE;
+ e_image_chooser_set_from_file (E_IMAGE_CHOOSER (me->image_chooser), me->person);
+ about_me_update_photo (me);
+ }
+
+ gtk_widget_destroy (GTK_WIDGET (chooser_dialog));
+}
+
+static void
+about_me_image_changed_cb (GtkWidget *widget, MateAboutMe *me)
+{
+ me->have_image = TRUE;
+ me->image_changed = TRUE;
+ about_me_update_photo (me);
+}
+
+/* About Me Dialog Callbacks */
+
+static void
+about_me_icon_theme_changed (GtkWindow *window,
+ GtkIconTheme *theme)
+{
+ GtkIconInfo *icon;
+
+ icon = gtk_icon_theme_lookup_icon (me->theme, "stock_person", 80, 0);
+ if (icon == NULL) {
+ g_debug ("Icon not found");
+ }
+ g_free (me->person);
+ me->person = g_strdup (gtk_icon_info_get_filename (icon));
+
+ gtk_icon_info_free (icon);
+
+ if (me->have_image)
+ e_image_chooser_set_from_file (E_IMAGE_CHOOSER (me->image_chooser), me->person);
+}
+
+static void
+about_me_button_clicked_cb (GtkDialog *dialog, gint response_id, MateAboutMe *me)
+{
+ if (response_id == GTK_RESPONSE_HELP)
+ g_print ("Help goes here");
+ else {
+ if (me->commit_timeout_id) {
+ g_source_remove (me->commit_timeout_id);
+ about_me_commit (me);
+ }
+
+ about_me_destroy ();
+ gtk_main_quit ();
+ }
+}
+
+static void
+about_me_passwd_clicked_cb (GtkWidget *button, MateAboutMe *me)
+{
+ GtkBuilder *dialog;
+
+ dialog = me->dialog;
+ mate_about_me_password (GTK_WINDOW (WID ("about-me-dialog")));
+}
+
+static void
+about_me_fingerprint_button_clicked_cb (GtkWidget *button, MateAboutMe *me)
+{
+ fingerprint_button_clicked (me->dialog,
+ me->enable_fingerprint_button,
+ me->disable_fingerprint_button);
+}
+
+static gint
+about_me_setup_dialog (void)
+{
+ GtkWidget *widget;
+ GtkWidget *main_dialog;
+ GtkIconInfo *icon;
+ GtkBuilder *dialog;
+ GError *error = NULL;
+ GList *chain;
+ gchar *str;
+
+ me = g_new0 (MateAboutMe, 1);
+
+ dialog = gtk_builder_new ();
+ gtk_builder_add_from_file (dialog, MATECC_UI_DIR "/mate-about-me-dialog.ui", NULL);
+
+ me->image_chooser = e_image_chooser_new ();
+ gtk_container_add (GTK_CONTAINER (WID ("button-image")), me->image_chooser);
+
+ if (dialog == NULL) {
+ about_me_destroy ();
+ return -1;
+ }
+
+ me->dialog = dialog;
+
+ /* Connect the close button signal */
+ main_dialog = WID ("about-me-dialog");
+ g_signal_connect (main_dialog, "response",
+ G_CALLBACK (about_me_button_clicked_cb), me);
+
+ gtk_window_set_resizable (GTK_WINDOW (main_dialog), FALSE);
+ capplet_set_icon (main_dialog, "user-info");
+
+ /* Setup theme details */
+ me->screen = gtk_window_get_screen (GTK_WINDOW (main_dialog));
+ me->theme = gtk_icon_theme_get_for_screen (me->screen);
+
+ icon = gtk_icon_theme_lookup_icon (me->theme, "stock_person", 80, 0);
+ if (icon != NULL) {
+ me->person = g_strdup (gtk_icon_info_get_filename (icon));
+ gtk_icon_info_free (icon);
+ }
+
+ g_signal_connect_object (me->theme, "changed",
+ G_CALLBACK (about_me_icon_theme_changed),
+ main_dialog,
+ G_CONNECT_SWAPPED);
+
+ /* Get the self contact */
+ if (!e_book_get_self (&me->contact, &me->book, &error)) {
+ if (error->code == E_BOOK_ERROR_PROTOCOL_NOT_SUPPORTED) {
+ about_me_error (NULL, _("There was an error while trying to get the addressbook information\n" \
+ "Evolution Data Server can't handle the protocol"));
+ g_clear_error (&error);
+ about_me_destroy ();
+ return -1;
+ }
+
+ g_clear_error (&error);
+
+ me->create_self = TRUE;
+ me->contact = e_contact_new ();
+
+ if (me->book == NULL) {
+ me->book = e_book_new_system_addressbook (&error);
+ if (me->book == NULL || error != NULL) {
+ g_error ("%s", error->message);
+ g_clear_error (&error);
+ }
+
+ if (e_book_open (me->book, FALSE, NULL) == FALSE) {
+ about_me_error (GTK_WINDOW (main_dialog),
+ _("Unable to open address book"));
+ g_clear_error (&error);
+ }
+ }
+ } else {
+ about_me_setup_email (me);
+ }
+
+ me->login = g_strdup (g_get_user_name ());
+ me->username = g_strdup (g_get_real_name ());
+
+ /* Contact Tab */
+ about_me_load_photo (me, me->contact);
+
+ widget = WID ("fullname");
+ str = g_strdup_printf ("<b><span size=\"xx-large\">%s</span></b>", me->username);
+
+ gtk_label_set_markup (GTK_LABEL (widget), str);
+ g_free (str);
+
+ widget = WID ("login");
+ gtk_label_set_text (GTK_LABEL (widget), me->login);
+
+ str = g_strdup_printf (_("About %s"), me->username);
+ gtk_window_set_title (GTK_WINDOW (main_dialog), str);
+ g_free (str);
+
+ widget = WID ("password");
+ g_signal_connect (widget, "clicked",
+ G_CALLBACK (about_me_passwd_clicked_cb), me);
+
+ widget = WID ("button-image");
+ g_signal_connect (widget, "clicked",
+ G_CALLBACK (about_me_image_clicked_cb), me);
+
+ me->enable_fingerprint_button = WID ("enable_fingerprint_button");
+ me->disable_fingerprint_button = WID ("disable_fingerprint_button");
+
+ g_signal_connect (me->enable_fingerprint_button, "clicked",
+ G_CALLBACK (about_me_fingerprint_button_clicked_cb), me);
+ g_signal_connect (me->disable_fingerprint_button, "clicked",
+ G_CALLBACK (about_me_fingerprint_button_clicked_cb), me);
+
+ g_signal_connect (me->image_chooser, "changed",
+ G_CALLBACK (about_me_image_changed_cb), me);
+
+ /* Address tab: set up the focus chains */
+ chain = g_list_prepend (NULL, WID ("addr-country-1"));
+ chain = g_list_prepend (chain, WID ("addr-po-1"));
+ chain = g_list_prepend (chain, WID ("addr-region-1"));
+ chain = g_list_prepend (chain, WID ("addr-code-1"));
+ chain = g_list_prepend (chain, WID ("addr-locality-1"));
+ chain = g_list_prepend (chain, WID ("addr-scrolledwindow-1"));
+ widget = WID ("addr-table-1");
+ gtk_container_set_focus_chain (GTK_CONTAINER (widget), chain);
+ g_list_free (chain);
+
+ chain = g_list_prepend (NULL, WID ("addr-country-2"));
+ chain = g_list_prepend (chain, WID ("addr-po-2"));
+ chain = g_list_prepend (chain, WID ("addr-region-2"));
+ chain = g_list_prepend (chain, WID ("addr-code-2"));
+ chain = g_list_prepend (chain, WID ("addr-locality-2"));
+ chain = g_list_prepend (chain, WID ("addr-scrolledwindow-2"));
+ widget = WID ("addr-table-2");
+ gtk_container_set_focus_chain (GTK_CONTAINER (widget), chain);
+ g_list_free (chain);
+
+ about_me_load_info (me);
+
+ gtk_widget_show_all (main_dialog);
+
+ return 0;
+}
+
+int
+main (int argc, char **argv)
+{
+ int rc = 0;
+
+ capplet_init (NULL, &argc, &argv);
+
+ if (!g_thread_supported ())
+ g_thread_init (NULL);
+
+ dbus_g_object_register_marshaller (fprintd_marshal_VOID__STRING_BOOLEAN,
+ G_TYPE_NONE, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_INVALID);
+
+ rc = about_me_setup_dialog ();
+
+ if (rc != -1) {
+ gtk_main ();
+ }
+
+ return rc;
+}
diff --git a/capplets/about-me/mate-about-me.desktop.in.in b/capplets/about-me/mate-about-me.desktop.in.in
new file mode 100644
index 00000000..e8393304
--- /dev/null
+++ b/capplets/about-me/mate-about-me.desktop.in.in
@@ -0,0 +1,14 @@
+[Desktop Entry]
+_Name=About Me
+_Comment=Set your personal information
+Exec=mate-about-me
+Icon=user-info
+Terminal=false
+Type=Application
+StartupNotify=true
+Categories=MATE;GTK;Settings;X-MATE-PersonalSettings;
+OnlyShowIn=MATE;
+X-MATE-Bugzilla-Bugzilla=MATE
+X-MATE-Bugzilla-Product=mate-control-center
+X-MATE-Bugzilla-Component=about-me
+X-MATE-Bugzilla-Version=@VERSION@
diff --git a/capplets/accessibility/Makefile.am b/capplets/accessibility/Makefile.am
new file mode 100644
index 00000000..4c96fba7
--- /dev/null
+++ b/capplets/accessibility/Makefile.am
@@ -0,0 +1,3 @@
+SUBDIRS = at-properties
+
+-include $(top_srcdir)/git.mk
diff --git a/capplets/accessibility/at-properties/Makefile.am b/capplets/accessibility/at-properties/Makefile.am
new file mode 100644
index 00000000..c24d0181
--- /dev/null
+++ b/capplets/accessibility/at-properties/Makefile.am
@@ -0,0 +1,31 @@
+bin_PROGRAMS = mate-at-properties
+
+mate_at_properties_LDADD = $(AT_CAPPLET_LIBS) $(MATECC_CAPPLETS_LIBS) $(top_builddir)/capplets/common/libcommon.la
+mate_at_properties_SOURCES = \
+ main.c
+mate_at_properties_LDFLAGS = -export-dynamic
+
+@INTLTOOL_DESKTOP_RULE@
+
+desktopdir = $(datadir)/applications
+Desktop_in_files = at-properties.desktop.in
+desktop_DATA = $(Desktop_in_files:.desktop.in=.desktop)
+
+pixmapdir = $(pkgdatadir)/pixmaps
+pixmap_DATA = \
+ at-startup.png \
+ at-support.png
+
+uidir = $(pkgdatadir)/ui
+ui_DATA = at-enable-dialog.ui
+
+INCLUDES = $(AT_CAPPLET_CFLAGS) \
+ $(MATECC_CAPPLETS_CFLAGS) \
+ -DUIDIR=\""$(uidir)"\" \
+ -DPIXMAPDIR=\""$(pixmapdir)"\" \
+ -DMATECC_DATA_DIR="\"$(pkgdatadir)\"" \
+ -DMATELOCALEDIR="\"$(datadir)/locale\""
+CLEANFILES = $(MATECC_CAPPLETS_CLEANFILES) $(Desktop_in_files) $(desktop_DATA)
+EXTRA_DIST = $(ui_DATA) $(pixmap_DATA)
+
+-include $(top_srcdir)/git.mk
diff --git a/capplets/accessibility/at-properties/Makefile.in b/capplets/accessibility/at-properties/Makefile.in
new file mode 100644
index 00000000..f4dbe405
--- /dev/null
+++ b/capplets/accessibility/at-properties/Makefile.in
@@ -0,0 +1,753 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+bin_PROGRAMS = mate-at-properties$(EXEEXT)
+subdir = capplets/accessibility/at-properties
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+ $(srcdir)/at-properties.desktop.in.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/intltool.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/mate-doc-utils.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES = at-properties.desktop.in
+CONFIG_CLEAN_VPATH_FILES =
+am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(desktopdir)" \
+ "$(DESTDIR)$(pixmapdir)" "$(DESTDIR)$(uidir)"
+PROGRAMS = $(bin_PROGRAMS)
+am_mate_at_properties_OBJECTS = main.$(OBJEXT)
+mate_at_properties_OBJECTS = $(am_mate_at_properties_OBJECTS)
+am__DEPENDENCIES_1 =
+mate_at_properties_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) \
+ $(top_builddir)/capplets/common/libcommon.la
+AM_V_lt = $(am__v_lt_$(V))
+am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
+am__v_lt_0 = --silent
+mate_at_properties_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mate_at_properties_LDFLAGS) \
+ $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_$(V))
+am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY))
+am__v_CC_0 = @echo " CC " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_$(V))
+am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY))
+am__v_CCLD_0 = @echo " CCLD " $@;
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+SOURCES = $(mate_at_properties_SOURCES)
+DIST_SOURCES = $(mate_at_properties_SOURCES)
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+DATA = $(desktop_DATA) $(pixmap_DATA) $(ui_DATA)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+ALL_LINGUAS = @ALL_LINGUAS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+APP_INDICATOR_CFLAGS = @APP_INDICATOR_CFLAGS@
+APP_INDICATOR_LIBS = @APP_INDICATOR_LIBS@
+AR = @AR@
+AT_CAPPLET_CFLAGS = @AT_CAPPLET_CFLAGS@
+AT_CAPPLET_LIBS = @AT_CAPPLET_LIBS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CAPPLET_CFLAGS = @CAPPLET_CFLAGS@
+CAPPLET_LIBS = @CAPPLET_LIBS@
+CATALOGS = @CATALOGS@
+CATOBJEXT = @CATOBJEXT@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DATADIRNAME = @DATADIRNAME@
+DBUS_CFLAGS = @DBUS_CFLAGS@
+DBUS_LIBS = @DBUS_LIBS@
+DEFAULT_APPLICATIONS_CAPPLET_CFLAGS = @DEFAULT_APPLICATIONS_CAPPLET_CFLAGS@
+DEFAULT_APPLICATIONS_CAPPLET_LIBS = @DEFAULT_APPLICATIONS_CAPPLET_LIBS@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISABLE_DEPRECATED = @DISABLE_DEPRECATED@
+DISPLAY_CAPPLET_CFLAGS = @DISPLAY_CAPPLET_CFLAGS@
+DISPLAY_CAPPLET_LIBS = @DISPLAY_CAPPLET_LIBS@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOC_USER_FORMATS = @DOC_USER_FORMATS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXTERNAL_LIBSLAB_CFLAGS = @EXTERNAL_LIBSLAB_CFLAGS@
+EXTERNAL_LIBSLAB_LIBS = @EXTERNAL_LIBSLAB_LIBS@
+FGREP = @FGREP@
+FONT_CAPPLET_CFLAGS = @FONT_CAPPLET_CFLAGS@
+FONT_CAPPLET_LIBS = @FONT_CAPPLET_LIBS@
+FONT_VIEWER_CFLAGS = @FONT_VIEWER_CFLAGS@
+FONT_VIEWER_LIBS = @FONT_VIEWER_LIBS@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GIO_CFLAGS = @GIO_CFLAGS@
+GIO_LIBS = @GIO_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GMOFILES = @GMOFILES@
+GMSGFMT = @GMSGFMT@
+GREP = @GREP@
+GSD_DBUS_CFLAGS = @GSD_DBUS_CFLAGS@
+GSD_DBUS_LIBS = @GSD_DBUS_LIBS@
+GTK_ENGINE_DIR = @GTK_ENGINE_DIR@
+HELP_DIR = @HELP_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INSTOBJEXT = @INSTOBJEXT@
+INTLLIBS = @INTLLIBS@
+INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
+INTLTOOL_MERGE = @INTLTOOL_MERGE@
+INTLTOOL_PERL = @INTLTOOL_PERL@
+INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBCANBERRA_GTK_CFLAGS = @LIBCANBERRA_GTK_CFLAGS@
+LIBCANBERRA_GTK_LIBS = @LIBCANBERRA_GTK_LIBS@
+LIBEBOOK_CFLAGS = @LIBEBOOK_CFLAGS@
+LIBEBOOK_LIBS = @LIBEBOOK_LIBS@
+LIBMATEKBDUI_CFLAGS = @LIBMATEKBDUI_CFLAGS@
+LIBMATEKBDUI_LIBS = @LIBMATEKBDUI_LIBS@
+LIBMATEKBD_CFLAGS = @LIBMATEKBD_CFLAGS@
+LIBMATEKBD_LIBS = @LIBMATEKBD_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBSLAB_CFLAGS = @LIBSLAB_CFLAGS@
+LIBSLAB_LIBS = @LIBSLAB_LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MARCO_CFLAGS = @MARCO_CFLAGS@
+MARCO_LIBS = @MARCO_LIBS@
+MATECC_CAPPLETS_CFLAGS = @MATECC_CAPPLETS_CFLAGS@
+MATECC_CAPPLETS_CLEANFILES = @MATECC_CAPPLETS_CLEANFILES@
+MATECC_CAPPLETS_EXTRA_DIST = @MATECC_CAPPLETS_EXTRA_DIST@
+MATECC_CAPPLETS_LIBS = @MATECC_CAPPLETS_LIBS@
+MATECC_CFLAGS = @MATECC_CFLAGS@
+MATECC_LIBS = @MATECC_LIBS@
+MATECC_SHELL_CFLAGS = @MATECC_SHELL_CFLAGS@
+MATECC_SHELL_LIBS = @MATECC_SHELL_LIBS@
+MATECONFTOOL = @MATECONFTOOL@
+MATECONF_SCHEMA_CONFIG_SOURCE = @MATECONF_SCHEMA_CONFIG_SOURCE@
+MATECONF_SCHEMA_FILE_DIR = @MATECONF_SCHEMA_FILE_DIR@
+MATE_DESKTOP_CFLAGS = @MATE_DESKTOP_CFLAGS@
+MATE_DESKTOP_LIBS = @MATE_DESKTOP_LIBS@
+MKDIR_P = @MKDIR_P@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MSGFMT = @MSGFMT@
+MSGFMT_OPTS = @MSGFMT_OPTS@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OMF_DIR = @OMF_DIR@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+POFILES = @POFILES@
+POSUB = @POSUB@
+PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@
+PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@
+RANLIB = @RANLIB@
+SCREENSAVER_LIBS = @SCREENSAVER_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+TYPING_BREAK = @TYPING_BREAK@
+TYPING_CFLAGS = @TYPING_CFLAGS@
+TYPING_LIBS = @TYPING_LIBS@
+UPDATE_MIME_DATABASE = @UPDATE_MIME_DATABASE@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+WARN_CFLAGS = @WARN_CFLAGS@
+XCURSOR_CFLAGS = @XCURSOR_CFLAGS@
+XCURSOR_LIBS = @XCURSOR_LIBS@
+XF86MISC_LIBS = @XF86MISC_LIBS@
+XGETTEXT = @XGETTEXT@
+XINPUT_CFLAGS = @XINPUT_CFLAGS@
+XINPUT_LIBS = @XINPUT_LIBS@
+XMKMF = @XMKMF@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+mate_at_properties_LDADD = $(AT_CAPPLET_LIBS) $(MATECC_CAPPLETS_LIBS) $(top_builddir)/capplets/common/libcommon.la
+mate_at_properties_SOURCES = \
+ main.c
+
+mate_at_properties_LDFLAGS = -export-dynamic
+desktopdir = $(datadir)/applications
+Desktop_in_files = at-properties.desktop.in
+desktop_DATA = $(Desktop_in_files:.desktop.in=.desktop)
+pixmapdir = $(pkgdatadir)/pixmaps
+pixmap_DATA = \
+ at-startup.png \
+ at-support.png
+
+uidir = $(pkgdatadir)/ui
+ui_DATA = at-enable-dialog.ui
+INCLUDES = $(AT_CAPPLET_CFLAGS) \
+ $(MATECC_CAPPLETS_CFLAGS) \
+ -DUIDIR=\""$(uidir)"\" \
+ -DPIXMAPDIR=\""$(pixmapdir)"\" \
+ -DMATECC_DATA_DIR="\"$(pkgdatadir)\"" \
+ -DMATELOCALEDIR="\"$(datadir)/locale\""
+
+CLEANFILES = $(MATECC_CAPPLETS_CLEANFILES) $(Desktop_in_files) $(desktop_DATA)
+EXTRA_DIST = $(ui_DATA) $(pixmap_DATA)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu capplets/accessibility/at-properties/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu capplets/accessibility/at-properties/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+at-properties.desktop.in: $(top_builddir)/config.status $(srcdir)/at-properties.desktop.in.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p || test -f $$p1; \
+ then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(bindir)" && rm -f $$files
+
+clean-binPROGRAMS:
+ @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+mate-at-properties$(EXEEXT): $(mate_at_properties_OBJECTS) $(mate_at_properties_DEPENDENCIES)
+ @rm -f mate-at-properties$(EXEEXT)
+ $(AM_V_CCLD)$(mate_at_properties_LINK) $(mate_at_properties_OBJECTS) $(mate_at_properties_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-desktopDATA: $(desktop_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(desktopdir)" || $(MKDIR_P) "$(DESTDIR)$(desktopdir)"
+ @list='$(desktop_DATA)'; test -n "$(desktopdir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(desktopdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(desktopdir)" || exit $$?; \
+ done
+
+uninstall-desktopDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(desktop_DATA)'; test -n "$(desktopdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(desktopdir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(desktopdir)" && rm -f $$files
+install-pixmapDATA: $(pixmap_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(pixmapdir)" || $(MKDIR_P) "$(DESTDIR)$(pixmapdir)"
+ @list='$(pixmap_DATA)'; test -n "$(pixmapdir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pixmapdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(pixmapdir)" || exit $$?; \
+ done
+
+uninstall-pixmapDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pixmap_DATA)'; test -n "$(pixmapdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(pixmapdir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(pixmapdir)" && rm -f $$files
+install-uiDATA: $(ui_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(uidir)" || $(MKDIR_P) "$(DESTDIR)$(uidir)"
+ @list='$(ui_DATA)'; test -n "$(uidir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(uidir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(uidir)" || exit $$?; \
+ done
+
+uninstall-uiDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(ui_DATA)'; test -n "$(uidir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(uidir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(uidir)" && rm -f $$files
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS) $(DATA)
+installdirs:
+ for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(desktopdir)" "$(DESTDIR)$(pixmapdir)" "$(DESTDIR)$(uidir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-desktopDATA install-pixmapDATA install-uiDATA
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-binPROGRAMS
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS uninstall-desktopDATA \
+ uninstall-pixmapDATA uninstall-uiDATA
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \
+ clean-generic clean-libtool ctags distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-binPROGRAMS install-data install-data-am \
+ install-desktopDATA install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-pixmapDATA install-ps install-ps-am install-strip \
+ install-uiDATA installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags uninstall uninstall-am \
+ uninstall-binPROGRAMS uninstall-desktopDATA \
+ uninstall-pixmapDATA uninstall-uiDATA
+
+
+@INTLTOOL_DESKTOP_RULE@
+
+-include $(top_srcdir)/git.mk
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/capplets/accessibility/at-properties/at-enable-dialog.ui b/capplets/accessibility/at-properties/at-enable-dialog.ui
new file mode 100644
index 00000000..721c45c8
--- /dev/null
+++ b/capplets/accessibility/at-properties/at-enable-dialog.ui
@@ -0,0 +1,351 @@
+<?xml version="1.0"?>
+<interface>
+ <requires lib="gtk+" version="2.16"/>
+ <!-- interface-naming-policy toplevel-contextual -->
+ <object class="GtkDialog" id="at_properties_dialog">
+ <property name="border_width">5</property>
+ <property name="title" translatable="yes">Assistive Technologies Preferences</property>
+ <property name="resizable">False</property>
+ <property name="type_hint">dialog</property>
+ <property name="has_separator">False</property>
+ <child internal-child="vbox">
+ <object class="GtkVBox" id="dialog-vbox1">
+ <property name="visible">True</property>
+ <property name="spacing">2</property>
+ <child>
+ <object class="GtkVBox" id="vbox1">
+ <property name="visible">True</property>
+ <property name="border_width">5</property>
+ <property name="spacing">18</property>
+ <child>
+ <object class="GtkVBox" id="at_support_frame">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkVBox" id="vbox2">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Assistive Technologies</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox2">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkImage" id="at_enable_image">
+ <property name="visible">True</property>
+ <property name="yalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox3">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkButton" id="at_pref_button">
+ <property name="label" translatable="yes">_Preferred Applications</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="image">pref_button_img</property>
+ <property name="use_underline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="at_pref_button-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes">Jump to Preferred Applications dialog</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="at_enable_toggle">
+ <property name="label" translatable="yes">_Enable assistive technologies</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="at_enable_toggle-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes">Changes to enable assistive technologies will not take effect until your next log in.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="at_applications_frame">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkVBox" id="vbox7">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="pref_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Preferences</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox3">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkImage" id="at_applications_image">
+ <property name="visible">True</property>
+ <property name="yalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox5">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkVBox" id="vbox8">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkButton" id="keyboard_button">
+ <property name="label" translatable="yes">_Keyboard Accessibility</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="image">keyboard_button_img</property>
+ <property name="use_underline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="keyboard_button-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes">Jump to the Keyboard Accessibility dialog</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="padding">5</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="mouse_button">
+ <property name="label" translatable="yes">_Mouse Accessibility</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="image">mouse_button_img</property>
+ <property name="use_underline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="mouse_button-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes">Jump to the Mouse Accessibility dialog</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="padding">5</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="login_button">
+ <property name="label" translatable="yes">Accessible Lo_gin</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="image">login_button_img</property>
+ <property name="use_underline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="login_button-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes">Jump to the Accessible Login dialog</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="padding">5</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <object class="GtkHButtonBox" id="dialog-action_area1">
+ <property name="visible">True</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="at_help_button">
+ <property name="label">gtk-help</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="at_close_logout_button">
+ <property name="label" translatable="yes">Close and _Log Out</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="receives_default">False</property>
+ <property name="image">close_logout_button_img</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="at_close_button">
+ <property name="label">gtk-close</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-11">at_help_button</action-widget>
+ <action-widget response="0">at_close_logout_button</action-widget>
+ <action-widget response="-7">at_close_button</action-widget>
+ </action-widgets>
+ </object>
+ <object class="GtkImage" id="close_logout_button_img">
+ <property name="visible">True</property>
+ <property name="stock">gtk-quit</property>
+ </object>
+ <object class="GtkImage" id="pref_button_img">
+ <property name="visible">True</property>
+ <property name="stock">gtk-jump-to</property>
+ </object>
+ <object class="GtkImage" id="keyboard_button_img">
+ <property name="visible">True</property>
+ <property name="stock">gtk-jump-to</property>
+ </object>
+ <object class="GtkImage" id="mouse_button_img">
+ <property name="visible">True</property>
+ <property name="stock">gtk-jump-to</property>
+ </object>
+ <object class="GtkImage" id="login_button_img">
+ <property name="visible">True</property>
+ <property name="stock">gtk-jump-to</property>
+ </object>
+</interface>
diff --git a/capplets/accessibility/at-properties/at-properties.desktop.in.in b/capplets/accessibility/at-properties/at-properties.desktop.in.in
new file mode 100644
index 00000000..f79b4bcf
--- /dev/null
+++ b/capplets/accessibility/at-properties/at-properties.desktop.in.in
@@ -0,0 +1,14 @@
+[Desktop Entry]
+_Name=Assistive Technologies
+_Comment=Choose which accessibility features to enable when you log in
+Exec=mate-at-properties
+Icon=preferences-desktop-accessibility
+Terminal=false
+Type=Application
+StartupNotify=true
+Categories=MATE;GTK;Settings;X-MATE-PersonalSettings;
+OnlyShowIn=MATE;
+X-MATE-Bugzilla-Bugzilla=MATE
+X-MATE-Bugzilla-Product=mate-control-center
+X-MATE-Bugzilla-Component=Assistive Technology Preferences
+X-MATE-Bugzilla-Version=@VERSION@
diff --git a/capplets/accessibility/at-properties/at-startup.png b/capplets/accessibility/at-properties/at-startup.png
new file mode 100644
index 00000000..c09f8d49
--- /dev/null
+++ b/capplets/accessibility/at-properties/at-startup.png
Binary files differ
diff --git a/capplets/accessibility/at-properties/at-support.png b/capplets/accessibility/at-properties/at-support.png
new file mode 100644
index 00000000..1a350a8e
--- /dev/null
+++ b/capplets/accessibility/at-properties/at-support.png
Binary files differ
diff --git a/capplets/accessibility/at-properties/main.c b/capplets/accessibility/at-properties/main.c
new file mode 100644
index 00000000..766c473b
--- /dev/null
+++ b/capplets/accessibility/at-properties/main.c
@@ -0,0 +1,293 @@
+#include <config.h>
+#include <gtk/gtk.h>
+#include <mateconf/mateconf-client.h>
+
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#define GSM_SERVICE_DBUS "org.mate.SessionManager"
+#define GSM_PATH_DBUS "/org/mate/SessionManager"
+#define GSM_INTERFACE_DBUS "org.mate.SessionManager"
+
+enum {
+ GSM_LOGOUT_MODE_NORMAL = 0,
+ GSM_LOGOUT_MODE_NO_CONFIRMATION,
+ GSM_LOGOUT_MODE_FORCE
+};
+
+#include "capplet-util.h"
+#include "mateconf-property-editor.h"
+#include "activate-settings-daemon.h"
+
+#define ACCESSIBILITY_KEY "/desktop/mate/interface/accessibility"
+#define ACCESSIBILITY_KEY_DIR "/desktop/mate/interface"
+
+static gboolean initial_state;
+
+static GtkBuilder *
+create_builder (void)
+{
+ GtkBuilder *builder;
+ GError *error = NULL;
+ static const gchar *uifile = UIDIR "/at-enable-dialog.ui";
+
+ builder = gtk_builder_new ();
+
+ if (gtk_builder_add_from_file (builder, uifile, &error)) {
+ GObject *object;
+ gchar *prog;
+
+ object = gtk_builder_get_object (builder, "at_enable_image");
+ gtk_image_set_from_file (GTK_IMAGE (object),
+ PIXMAPDIR "/at-startup.png");
+
+ object = gtk_builder_get_object (builder,
+ "at_applications_image");
+ gtk_image_set_from_file (GTK_IMAGE (object),
+ PIXMAPDIR "/at-support.png");
+
+ prog = g_find_program_in_path ("mdmsetup");
+ if (prog == NULL) {
+ object = gtk_builder_get_object (builder,
+ "login_button");
+ gtk_widget_hide (GTK_WIDGET (object));
+ }
+
+ g_free (prog);
+ } else {
+ g_warning ("Could not load UI: %s", error->message);
+ g_error_free (error);
+ g_object_unref (builder);
+ builder = NULL;
+ }
+
+ return builder;
+}
+
+static void
+cb_at_preferences (GtkDialog *dialog, gint response_id)
+{
+ g_spawn_command_line_async ("mate-default-applications-properties --show-page=a11y", NULL);
+}
+
+static void
+cb_keyboard_preferences (GtkDialog *dialog, gint response_id)
+{
+ g_spawn_command_line_async ("mate-keyboard-properties --a11y", NULL);
+}
+
+static void
+cb_mouse_preferences (GtkDialog *dialog, gint response_id)
+{
+ g_spawn_command_line_async ("mate-mouse-properties --show-page=accessibility", NULL);
+}
+
+static void
+cb_login_preferences (GtkDialog *dialog, gint response_id)
+{
+ g_spawn_command_line_async ("mdmsetup", NULL);
+}
+
+/* get_session_bus(), get_sm_proxy(), and do_logout() are all
+ * based on code from mate-session-save.c from mate-session.
+ */
+static DBusGConnection *
+get_session_bus (void)
+{
+ DBusGConnection *bus;
+ GError *error = NULL;
+
+ bus = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+
+ if (bus == NULL) {
+ g_warning ("Couldn't connect to session bus: %s", error->message);
+ g_error_free (error);
+ }
+
+ return bus;
+}
+
+static DBusGProxy *
+get_sm_proxy (void)
+{
+ DBusGConnection *connection;
+ DBusGProxy *sm_proxy;
+
+ if (!(connection = get_session_bus ()))
+ return NULL;
+
+ sm_proxy = dbus_g_proxy_new_for_name (connection,
+ GSM_SERVICE_DBUS,
+ GSM_PATH_DBUS,
+ GSM_INTERFACE_DBUS);
+
+ return sm_proxy;
+}
+
+static gboolean
+do_logout (GError **err)
+{
+ DBusGProxy *sm_proxy;
+ GError *error;
+ gboolean res;
+
+ sm_proxy = get_sm_proxy ();
+ if (sm_proxy == NULL)
+ return FALSE;
+
+ res = dbus_g_proxy_call (sm_proxy,
+ "Logout",
+ &error,
+ G_TYPE_UINT, 0, /* '0' means 'log out normally' */
+ G_TYPE_INVALID,
+ G_TYPE_INVALID);
+
+ if (sm_proxy)
+ g_object_unref (sm_proxy);
+
+ return res;
+}
+
+static void
+cb_dialog_response (GtkDialog *dialog, gint response_id)
+{
+ if (response_id == GTK_RESPONSE_HELP)
+ capplet_help (GTK_WINDOW (dialog),
+ "goscustaccess-11");
+ else if (response_id == GTK_RESPONSE_CLOSE || response_id == GTK_RESPONSE_DELETE_EVENT)
+ gtk_main_quit ();
+ else {
+ g_message ("CLOSE AND LOGOUT!");
+
+ if (!do_logout (NULL))
+ gtk_main_quit ();
+ }
+}
+
+static void
+close_logout_update (GtkBuilder *builder)
+{
+ MateConfClient *client = mateconf_client_get_default ();
+ gboolean curr_state = mateconf_client_get_bool (client, ACCESSIBILITY_KEY, NULL);
+ GObject *btn = gtk_builder_get_object (builder,
+ "at_close_logout_button");
+
+ gtk_widget_set_sensitive (GTK_WIDGET (btn), initial_state != curr_state);
+ g_object_unref (client);
+}
+
+static void
+at_enable_toggled (GtkToggleButton *toggle_button,
+ GtkBuilder *builder)
+{
+ MateConfClient *client = mateconf_client_get_default ();
+ gboolean is_enabled = gtk_toggle_button_get_active (toggle_button);
+
+ mateconf_client_set_bool (client, ACCESSIBILITY_KEY,
+ is_enabled,
+ NULL);
+ g_object_unref (client);
+}
+
+static void
+at_enable_update (MateConfClient *client,
+ GtkBuilder *builder)
+{
+ gboolean is_enabled = mateconf_client_get_bool (client, ACCESSIBILITY_KEY, NULL);
+ GObject *btn = gtk_builder_get_object (builder, "at_enable_toggle");
+
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (btn),
+ is_enabled);
+}
+
+static void
+at_enable_changed (MateConfClient *client,
+ guint cnxn_id,
+ MateConfEntry *entry,
+ gpointer user_data)
+{
+ at_enable_update (client, user_data);
+ close_logout_update (user_data);
+}
+
+static void
+setup_dialog (GtkBuilder *builder)
+{
+ MateConfClient *client;
+ GtkWidget *widget;
+ GObject *object;
+ GObject *peditor;
+
+ client = mateconf_client_get_default ();
+
+ mateconf_client_add_dir (client, ACCESSIBILITY_KEY_DIR,
+ MATECONF_CLIENT_PRELOAD_ONELEVEL, NULL);
+
+ object = gtk_builder_get_object (builder, "at_enable_toggle");
+ g_signal_connect (object, "toggled",
+ G_CALLBACK (at_enable_toggled),
+ builder);
+
+ peditor = mateconf_peditor_new_boolean (NULL, ACCESSIBILITY_KEY,
+ GTK_WIDGET (object),
+ NULL);
+
+ initial_state = mateconf_client_get_bool (client, ACCESSIBILITY_KEY, NULL);
+
+ at_enable_update (client, builder);
+
+ mateconf_client_notify_add (client, ACCESSIBILITY_KEY_DIR,
+ at_enable_changed,
+ builder, NULL, NULL);
+
+ object = gtk_builder_get_object (builder, "at_pref_button");
+ g_signal_connect (object, "clicked",
+ G_CALLBACK (cb_at_preferences), NULL);
+
+ object = gtk_builder_get_object (builder, "keyboard_button");
+ g_signal_connect (object, "clicked",
+ G_CALLBACK (cb_keyboard_preferences), NULL);
+
+ object = gtk_builder_get_object (builder, "mouse_button");
+ g_signal_connect (object, "clicked",
+ G_CALLBACK (cb_mouse_preferences), NULL);
+
+ object = gtk_builder_get_object (builder, "login_button");
+ g_signal_connect (object, "clicked",
+ G_CALLBACK (cb_login_preferences), NULL);
+
+ widget = GTK_WIDGET (gtk_builder_get_object (builder,
+ "at_properties_dialog"));
+ capplet_set_icon (widget, "preferences-desktop-accessibility");
+
+ g_signal_connect (G_OBJECT (widget),
+ "response",
+ G_CALLBACK (cb_dialog_response), NULL);
+
+ gtk_widget_show (widget);
+
+ g_object_unref (client);
+}
+
+int
+main (int argc, char *argv[])
+{
+ GtkBuilder *builder;
+
+ capplet_init (NULL, &argc, &argv);
+
+ activate_settings_daemon ();
+
+ builder = create_builder ();
+
+ if (builder) {
+
+ setup_dialog (builder);
+
+ gtk_main ();
+
+ g_object_unref (builder);
+ }
+
+ return 0;
+}
diff --git a/capplets/appearance/Makefile.am b/capplets/appearance/Makefile.am
new file mode 100644
index 00000000..5c5dc2ca
--- /dev/null
+++ b/capplets/appearance/Makefile.am
@@ -0,0 +1,58 @@
+SUBDIRS = data
+
+# This is used in MATECC_CAPPLETS_CFLAGS
+cappletname = appearance
+
+bin_PROGRAMS = mate-appearance-properties
+
+mate_appearance_properties_SOURCES = \
+ appearance.h \
+ appearance-desktop.c \
+ appearance-desktop.h \
+ appearance-font.c \
+ appearance-font.h \
+ appearance-main.c \
+ appearance-themes.c \
+ appearance-themes.h \
+ appearance-style.c \
+ appearance-style.h \
+ mate-wp-info.c \
+ mate-wp-info.h \
+ mate-wp-item.c \
+ mate-wp-item.h \
+ mate-wp-xml.c \
+ mate-wp-xml.h \
+ theme-installer.c \
+ theme-installer.h \
+ theme-save.c \
+ theme-save.h \
+ theme-util.c \
+ theme-util.h
+
+AM_CFLAGS = -DMATE_DESKTOP_USE_UNSTABLE_API
+
+mate_appearance_properties_LDADD = \
+ $(top_builddir)/libwindow-settings/libmate-window-settings.la \
+ $(top_builddir)/capplets/common/libcommon.la \
+ $(MATECC_CAPPLETS_LIBS) \
+ $(FONT_CAPPLET_LIBS) \
+ $(MARCO_LIBS)
+mate_appearance_properties_LDFLAGS = -export-dynamic
+
+gtkbuilderdir = $(pkgdatadir)/ui
+pixmapdir = $(pkgdatadir)/pixmaps
+wallpaperdir = $(datadir)/mate-background-properties
+
+INCLUDES = \
+ $(MARCO_CFLAGS) \
+ $(MATECC_CAPPLETS_CFLAGS) \
+ $(FONT_CAPPLET_CFLAGS) \
+ -DMATELOCALEDIR="\"$(datadir)/locale\"" \
+ -DMATECC_DATA_DIR="\"$(pkgdatadir)\"" \
+ -DMATECC_GTKBUILDER_DIR="\"$(gtkbuilderdir)\"" \
+ -DMATECC_PIXMAP_DIR="\"$(pixmapdir)\"" \
+ -DWALLPAPER_DATADIR="\"$(wallpaperdir)\""
+
+CLEANFILES = $(MATECC_CAPPLETS_CLEANFILES)
+
+-include $(top_srcdir)/git.mk
diff --git a/capplets/appearance/appearance-desktop.c b/capplets/appearance/appearance-desktop.c
new file mode 100644
index 00000000..f0dc803e
--- /dev/null
+++ b/capplets/appearance/appearance-desktop.c
@@ -0,0 +1,1400 @@
+/*
+ * Copyright (C) 2007,2008 The MATE Foundation
+ * Written by Rodney Dawes <[email protected]>
+ * Denis Washington <[email protected]>
+ * Thomas Wood <[email protected]>
+ * All Rights Reserved
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "appearance.h"
+#include "mate-wp-info.h"
+#include "mate-wp-item.h"
+#include "mate-wp-xml.h"
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+#include <string.h>
+#include <mateconf/mateconf-client.h>
+#include <libmateui/mate-desktop-thumbnail.h>
+#include <libmateui/mate-bg.h>
+
+enum {
+ TARGET_URI_LIST,
+ TARGET_BGIMAGE
+};
+
+static const GtkTargetEntry drop_types[] = {
+ {"text/uri-list", 0, TARGET_URI_LIST},
+ {"property/bgimage", 0, TARGET_BGIMAGE}
+};
+
+static const GtkTargetEntry drag_types[] = {
+ {"text/uri-list", GTK_TARGET_OTHER_WIDGET, TARGET_URI_LIST}
+};
+
+
+static void wp_update_preview(GtkFileChooser* chooser, AppearanceData* data);
+
+static void select_item(AppearanceData* data, MateWPItem* item, gboolean scroll)
+{
+ GtkTreePath* path;
+
+ g_return_if_fail(data != NULL);
+
+ if (item == NULL)
+ return;
+
+ path = gtk_tree_row_reference_get_path(item->rowref);
+
+ gtk_icon_view_select_path(data->wp_view, path);
+
+ if (scroll)
+ {
+ gtk_icon_view_scroll_to_path(data->wp_view, path, FALSE, 0.5, 0.0);
+ }
+
+ gtk_tree_path_free(path);
+}
+
+static MateWPItem* get_selected_item(AppearanceData* data, GtkTreeIter* iter)
+{
+ MateWPItem* item = NULL;
+ GList* selected;
+
+ selected = gtk_icon_view_get_selected_items (data->wp_view);
+
+ if (selected != NULL)
+ {
+ GtkTreeIter sel_iter;
+
+ gtk_tree_model_get_iter(data->wp_model, &sel_iter, selected->data);
+
+ g_list_foreach(selected, (GFunc) gtk_tree_path_free, NULL);
+ g_list_free(selected);
+
+ if (iter)
+ *iter = sel_iter;
+
+ gtk_tree_model_get(data->wp_model, &sel_iter, 1, &item, -1);
+ }
+
+ return item;
+}
+
+static gboolean predicate (gpointer key, gpointer value, gpointer data)
+{
+ MateBG *bg = data;
+ MateWPItem *item = value;
+
+ return item->bg == bg;
+}
+
+static void on_item_changed (MateBG *bg, AppearanceData *data) {
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GtkTreePath *path;
+ MateWPItem *item;
+
+ item = g_hash_table_find (data->wp_hash, predicate, bg);
+
+ if (!item)
+ return;
+
+ model = gtk_tree_row_reference_get_model (item->rowref);
+ path = gtk_tree_row_reference_get_path (item->rowref);
+
+ if (gtk_tree_model_get_iter (model, &iter, path)) {
+ GdkPixbuf *pixbuf;
+
+ g_signal_handlers_block_by_func (bg, G_CALLBACK (on_item_changed), data);
+
+ pixbuf = mate_wp_item_get_thumbnail (item,
+ data->thumb_factory,
+ data->thumb_width,
+ data->thumb_height);
+ if (pixbuf) {
+ gtk_list_store_set (GTK_LIST_STORE (data->wp_model), &iter, 0, pixbuf, -1);
+ g_object_unref (pixbuf);
+ }
+
+ g_signal_handlers_unblock_by_func (bg, G_CALLBACK (on_item_changed), data);
+ }
+}
+
+static void
+wp_props_load_wallpaper (gchar *key,
+ MateWPItem *item,
+ AppearanceData *data)
+{
+ GtkTreeIter iter;
+ GtkTreePath *path;
+ GdkPixbuf *pixbuf;
+
+ if (item->deleted == TRUE)
+ return;
+
+ gtk_list_store_append (GTK_LIST_STORE (data->wp_model), &iter);
+
+ pixbuf = mate_wp_item_get_thumbnail (item, data->thumb_factory,
+ data->thumb_width,
+ data->thumb_height);
+ mate_wp_item_update_description (item);
+
+ gtk_list_store_set (GTK_LIST_STORE (data->wp_model), &iter,
+ 0, pixbuf,
+ 1, item,
+ -1);
+
+ if (pixbuf != NULL)
+ g_object_unref (pixbuf);
+
+ path = gtk_tree_model_get_path (data->wp_model, &iter);
+ item->rowref = gtk_tree_row_reference_new (data->wp_model, path);
+ g_signal_connect (item->bg, "changed", G_CALLBACK (on_item_changed), data);
+ gtk_tree_path_free (path);
+}
+
+static MateWPItem *
+wp_add_image (AppearanceData *data,
+ const gchar *filename)
+{
+ MateWPItem *item;
+
+ if (!filename)
+ return NULL;
+
+ item = g_hash_table_lookup (data->wp_hash, filename);
+
+ if (item != NULL)
+ {
+ if (item->deleted)
+ {
+ item->deleted = FALSE;
+ wp_props_load_wallpaper (item->filename, item, data);
+ }
+ }
+ else
+ {
+ item = mate_wp_item_new (filename, data->wp_hash, data->thumb_factory);
+
+ if (item != NULL)
+ {
+ wp_props_load_wallpaper (item->filename, item, data);
+ }
+ }
+
+ return item;
+}
+
+static void
+wp_add_images (AppearanceData *data,
+ GSList *images)
+{
+ GdkWindow *window;
+ GtkWidget *w;
+ GdkCursor *cursor;
+ MateWPItem *item;
+
+ w = appearance_capplet_get_widget (data, "appearance_window");
+ window = gtk_widget_get_window (w);
+
+ item = NULL;
+ cursor = gdk_cursor_new_for_display (gdk_display_get_default (),
+ GDK_WATCH);
+ gdk_window_set_cursor (window, cursor);
+ gdk_cursor_unref (cursor);
+
+ while (images != NULL)
+ {
+ gchar *uri = images->data;
+
+ item = wp_add_image (data, uri);
+ images = g_slist_remove (images, uri);
+ g_free (uri);
+ }
+
+ gdk_window_set_cursor (window, NULL);
+
+ if (item != NULL)
+ {
+ select_item (data, item, TRUE);
+ }
+}
+
+static void
+wp_option_menu_set (AppearanceData *data,
+ int value,
+ gboolean shade_type)
+{
+ if (shade_type)
+ {
+ gtk_combo_box_set_active (GTK_COMBO_BOX (data->wp_color_menu),
+ value);
+
+ if (value == MATE_BG_COLOR_SOLID)
+ gtk_widget_hide (data->wp_scpicker);
+ else
+ gtk_widget_show (data->wp_scpicker);
+ }
+ else
+ {
+ gtk_combo_box_set_active (GTK_COMBO_BOX (data->wp_style_menu),
+ value);
+ }
+}
+
+static void
+wp_set_sensitivities (AppearanceData *data)
+{
+ MateWPItem *item;
+ gchar *filename = NULL;
+
+ item = get_selected_item (data, NULL);
+
+ if (item != NULL)
+ filename = item->filename;
+
+ if (!mateconf_client_key_is_writable (data->client, WP_OPTIONS_KEY, NULL)
+ || (filename && !strcmp (filename, "(none)")))
+ gtk_widget_set_sensitive (data->wp_style_menu, FALSE);
+ else
+ gtk_widget_set_sensitive (data->wp_style_menu, TRUE);
+
+ if (!mateconf_client_key_is_writable (data->client, WP_SHADING_KEY, NULL))
+ gtk_widget_set_sensitive (data->wp_color_menu, FALSE);
+ else
+ gtk_widget_set_sensitive (data->wp_color_menu, TRUE);
+
+ if (!mateconf_client_key_is_writable (data->client, WP_PCOLOR_KEY, NULL))
+ gtk_widget_set_sensitive (data->wp_pcpicker, FALSE);
+ else
+ gtk_widget_set_sensitive (data->wp_pcpicker, TRUE);
+
+ if (!mateconf_client_key_is_writable (data->client, WP_SCOLOR_KEY, NULL))
+ gtk_widget_set_sensitive (data->wp_scpicker, FALSE);
+ else
+ gtk_widget_set_sensitive (data->wp_scpicker, TRUE);
+
+ if (!filename || !strcmp (filename, "(none)"))
+ gtk_widget_set_sensitive (data->wp_rem_button, FALSE);
+ else
+ gtk_widget_set_sensitive (data->wp_rem_button, TRUE);
+}
+
+static void
+wp_scale_type_changed (GtkComboBox *combobox,
+ AppearanceData *data)
+{
+ MateWPItem *item;
+ GtkTreeIter iter;
+ GdkPixbuf *pixbuf;
+
+ item = get_selected_item (data, &iter);
+
+ if (item == NULL)
+ return;
+
+ item->options = gtk_combo_box_get_active (GTK_COMBO_BOX (data->wp_style_menu));
+
+ pixbuf = mate_wp_item_get_thumbnail (item, data->thumb_factory,
+ data->thumb_width,
+ data->thumb_height);
+ gtk_list_store_set (GTK_LIST_STORE (data->wp_model), &iter, 0, pixbuf, -1);
+ if (pixbuf != NULL)
+ g_object_unref (pixbuf);
+
+ if (mateconf_client_key_is_writable (data->client, WP_OPTIONS_KEY, NULL))
+ mateconf_client_set_string (data->client, WP_OPTIONS_KEY,
+ wp_item_option_to_string (item->options), NULL);
+}
+
+static void
+wp_shade_type_changed (GtkWidget *combobox,
+ AppearanceData *data)
+{
+ MateWPItem *item;
+ GtkTreeIter iter;
+ GdkPixbuf *pixbuf;
+
+ item = get_selected_item (data, &iter);
+
+ if (item == NULL)
+ return;
+
+ item->shade_type = gtk_combo_box_get_active (GTK_COMBO_BOX (data->wp_color_menu));
+
+ pixbuf = mate_wp_item_get_thumbnail (item, data->thumb_factory,
+ data->thumb_width,
+ data->thumb_height);
+ gtk_list_store_set (GTK_LIST_STORE (data->wp_model), &iter, 0, pixbuf, -1);
+ if (pixbuf != NULL)
+ g_object_unref (pixbuf);
+
+ if (mateconf_client_key_is_writable (data->client, WP_SHADING_KEY, NULL))
+ mateconf_client_set_string (data->client, WP_SHADING_KEY,
+ wp_item_shading_to_string (item->shade_type), NULL);
+}
+
+static void
+wp_color_changed (AppearanceData *data,
+ gboolean update)
+{
+ MateWPItem *item;
+
+ item = get_selected_item (data, NULL);
+
+ if (item == NULL)
+ return;
+
+ gtk_color_button_get_color (GTK_COLOR_BUTTON (data->wp_pcpicker), item->pcolor);
+ gtk_color_button_get_color (GTK_COLOR_BUTTON (data->wp_scpicker), item->scolor);
+
+ if (update)
+ {
+ gchar *pcolor, *scolor;
+
+ pcolor = gdk_color_to_string (item->pcolor);
+ scolor = gdk_color_to_string (item->scolor);
+ mateconf_client_set_string (data->client, WP_PCOLOR_KEY, pcolor, NULL);
+ mateconf_client_set_string (data->client, WP_SCOLOR_KEY, scolor, NULL);
+ g_free (pcolor);
+ g_free (scolor);
+ }
+
+ wp_shade_type_changed (NULL, data);
+}
+
+static void
+wp_scolor_changed (GtkWidget *widget,
+ AppearanceData *data)
+{
+ wp_color_changed (data, TRUE);
+}
+
+static void
+wp_remove_wallpaper (GtkWidget *widget,
+ AppearanceData *data)
+{
+ MateWPItem *item;
+ GtkTreeIter iter;
+ GtkTreePath *path;
+
+ item = get_selected_item (data, &iter);
+
+ if (item)
+ {
+ item->deleted = TRUE;
+
+ if (gtk_list_store_remove (GTK_LIST_STORE (data->wp_model), &iter))
+ path = gtk_tree_model_get_path (data->wp_model, &iter);
+ else
+ path = gtk_tree_path_new_first ();
+
+ gtk_icon_view_select_path (data->wp_view, path);
+ gtk_icon_view_set_cursor (data->wp_view, path, NULL, FALSE);
+ gtk_tree_path_free (path);
+ }
+}
+
+static void
+wp_uri_changed (const gchar *uri,
+ AppearanceData *data)
+{
+ MateWPItem *item, *selected;
+
+ item = g_hash_table_lookup (data->wp_hash, uri);
+ selected = get_selected_item (data, NULL);
+
+ if (selected != NULL && strcmp (selected->filename, uri) != 0)
+ {
+ if (item == NULL)
+ item = wp_add_image (data, uri);
+
+ if (item)
+ select_item (data, item, TRUE);
+ }
+}
+
+static void
+wp_file_changed (MateConfClient *client, guint id,
+ MateConfEntry *entry,
+ AppearanceData *data)
+{
+ const gchar *uri;
+ gchar *wpfile;
+
+ uri = mateconf_value_get_string (entry->value);
+
+ if (g_utf8_validate (uri, -1, NULL) && g_file_test (uri, G_FILE_TEST_EXISTS))
+ wpfile = g_strdup (uri);
+ else
+ wpfile = g_filename_from_utf8 (uri, -1, NULL, NULL, NULL);
+
+ wp_uri_changed (wpfile, data);
+
+ g_free (wpfile);
+}
+
+static void
+wp_options_changed (MateConfClient *client, guint id,
+ MateConfEntry *entry,
+ AppearanceData *data)
+{
+ MateWPItem *item;
+ const gchar *option;
+
+ option = mateconf_value_get_string (entry->value);
+
+ /* "none" means we don't use a background image */
+ if (option == NULL || !strcmp (option, "none"))
+ {
+ /* temporarily disconnect so we don't override settings when
+ * updating the selection */
+ data->wp_update_mateconf = FALSE;
+ wp_uri_changed ("(none)", data);
+ data->wp_update_mateconf = TRUE;
+ return;
+ }
+
+ item = get_selected_item (data, NULL);
+
+ if (item != NULL)
+ {
+ item->options = wp_item_string_to_option (option);
+ wp_option_menu_set (data, item->options, FALSE);
+ }
+}
+
+static void
+wp_shading_changed (MateConfClient *client, guint id,
+ MateConfEntry *entry,
+ AppearanceData *data)
+{
+ MateWPItem *item;
+
+ wp_set_sensitivities (data);
+
+ item = get_selected_item (data, NULL);
+
+ if (item != NULL)
+ {
+ item->shade_type = wp_item_string_to_shading (mateconf_value_get_string (entry->value));
+ wp_option_menu_set (data, item->shade_type, TRUE);
+ }
+}
+
+static void
+wp_color1_changed (MateConfClient *client, guint id,
+ MateConfEntry *entry,
+ AppearanceData *data)
+{
+ GdkColor color;
+ const gchar *colorhex;
+
+ colorhex = mateconf_value_get_string (entry->value);
+
+ gdk_color_parse (colorhex, &color);
+
+ gtk_color_button_set_color (GTK_COLOR_BUTTON (data->wp_pcpicker), &color);
+
+ wp_color_changed (data, FALSE);
+}
+
+static void
+wp_color2_changed (MateConfClient *client, guint id,
+ MateConfEntry *entry,
+ AppearanceData *data)
+{
+ GdkColor color;
+ const gchar *colorhex;
+
+ wp_set_sensitivities (data);
+
+ colorhex = mateconf_value_get_string (entry->value);
+
+ gdk_color_parse (colorhex, &color);
+
+ gtk_color_button_set_color (GTK_COLOR_BUTTON (data->wp_scpicker), &color);
+
+ wp_color_changed (data, FALSE);
+}
+
+static gboolean
+wp_props_wp_set (AppearanceData *data, MateWPItem *item)
+{
+ MateConfChangeSet *cs;
+ gchar *pcolor, *scolor;
+
+ cs = mateconf_change_set_new ();
+
+ if (!strcmp (item->filename, "(none)"))
+ {
+ mateconf_change_set_set_string (cs, WP_OPTIONS_KEY, "none");
+ mateconf_change_set_set_string (cs, WP_FILE_KEY, "");
+ }
+ else
+ {
+ gchar *uri;
+
+ if (g_utf8_validate (item->filename, -1, NULL))
+ uri = g_strdup (item->filename);
+ else
+ uri = g_filename_to_utf8 (item->filename, -1, NULL, NULL, NULL);
+
+ if (uri == NULL) {
+ g_warning ("Failed to convert filename to UTF-8: %s", item->filename);
+ } else {
+ mateconf_change_set_set_string (cs, WP_FILE_KEY, uri);
+ g_free (uri);
+ }
+
+ mateconf_change_set_set_string (cs, WP_OPTIONS_KEY,
+ wp_item_option_to_string (item->options));
+ }
+
+ mateconf_change_set_set_string (cs, WP_SHADING_KEY,
+ wp_item_shading_to_string (item->shade_type));
+
+ pcolor = gdk_color_to_string (item->pcolor);
+ scolor = gdk_color_to_string (item->scolor);
+ mateconf_change_set_set_string (cs, WP_PCOLOR_KEY, pcolor);
+ mateconf_change_set_set_string (cs, WP_SCOLOR_KEY, scolor);
+ g_free (pcolor);
+ g_free (scolor);
+
+ mateconf_client_commit_change_set (data->client, cs, TRUE, NULL);
+
+ mateconf_change_set_unref (cs);
+
+ return FALSE;
+}
+
+static void
+wp_props_wp_selected (GtkTreeSelection *selection,
+ AppearanceData *data)
+{
+ MateWPItem *item;
+
+ item = get_selected_item (data, NULL);
+
+ if (item != NULL)
+ {
+ wp_set_sensitivities (data);
+
+ if (strcmp (item->filename, "(none)") != 0)
+ wp_option_menu_set (data, item->options, FALSE);
+
+ wp_option_menu_set (data, item->shade_type, TRUE);
+
+ gtk_color_button_set_color (GTK_COLOR_BUTTON (data->wp_pcpicker),
+ item->pcolor);
+ gtk_color_button_set_color (GTK_COLOR_BUTTON (data->wp_scpicker),
+ item->scolor);
+
+ if (data->wp_update_mateconf)
+ wp_props_wp_set (data, item);
+ }
+ else
+ {
+ gtk_widget_set_sensitive (data->wp_rem_button, FALSE);
+ }
+}
+
+void
+wp_create_filechooser (AppearanceData *data)
+{
+ const char *start_dir, *pictures = NULL;
+ GtkFileFilter *filter;
+
+ data->wp_filesel = GTK_FILE_CHOOSER (
+ gtk_file_chooser_dialog_new (_("Add Wallpaper"),
+ GTK_WINDOW (appearance_capplet_get_widget (data, "appearance_window")),
+ GTK_FILE_CHOOSER_ACTION_OPEN,
+ GTK_STOCK_CANCEL,
+ GTK_RESPONSE_CANCEL,
+ GTK_STOCK_OPEN,
+ GTK_RESPONSE_OK,
+ NULL));
+
+ gtk_dialog_set_default_response (GTK_DIALOG (data->wp_filesel), GTK_RESPONSE_OK);
+ gtk_file_chooser_set_select_multiple (data->wp_filesel, TRUE);
+ gtk_file_chooser_set_use_preview_label (data->wp_filesel, FALSE);
+
+ start_dir = g_get_home_dir ();
+
+ if (g_file_test ("/usr/share/backgrounds", G_FILE_TEST_IS_DIR)) {
+ gtk_file_chooser_add_shortcut_folder (data->wp_filesel,
+ "/usr/share/backgrounds", NULL);
+ start_dir = "/usr/share/backgrounds";
+ }
+
+ pictures = g_get_user_special_dir (G_USER_DIRECTORY_PICTURES);
+ if (pictures != NULL && g_file_test (pictures, G_FILE_TEST_IS_DIR)) {
+ gtk_file_chooser_add_shortcut_folder (data->wp_filesel, pictures, NULL);
+ start_dir = pictures;
+ }
+
+ gtk_file_chooser_set_current_folder (data->wp_filesel, start_dir);
+
+ filter = gtk_file_filter_new ();
+ gtk_file_filter_add_pixbuf_formats (filter);
+ gtk_file_filter_set_name (filter, _("Images"));
+ gtk_file_chooser_add_filter (data->wp_filesel, filter);
+
+ filter = gtk_file_filter_new ();
+ gtk_file_filter_set_name (filter, _("All files"));
+ gtk_file_filter_add_pattern (filter, "*");
+ gtk_file_chooser_add_filter (data->wp_filesel, filter);
+
+ data->wp_image = gtk_image_new ();
+ gtk_file_chooser_set_preview_widget (data->wp_filesel, data->wp_image);
+ gtk_widget_set_size_request (data->wp_image, 128, -1);
+
+ gtk_widget_show (data->wp_image);
+
+ g_signal_connect (data->wp_filesel, "update-preview",
+ (GCallback) wp_update_preview, data);
+}
+
+static void
+wp_file_open_dialog (GtkWidget *widget,
+ AppearanceData *data)
+{
+ GSList *files;
+
+ if (!data->wp_filesel)
+ wp_create_filechooser (data);
+
+ switch (gtk_dialog_run (GTK_DIALOG (data->wp_filesel)))
+ {
+ case GTK_RESPONSE_OK:
+ files = gtk_file_chooser_get_filenames (data->wp_filesel);
+ wp_add_images (data, files);
+ case GTK_RESPONSE_CANCEL:
+ default:
+ gtk_widget_hide (GTK_WIDGET (data->wp_filesel));
+ break;
+ }
+}
+
+static void
+wp_drag_received (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x, gint y,
+ GtkSelectionData *selection_data,
+ guint info, guint time,
+ AppearanceData *data)
+{
+ if (info == TARGET_URI_LIST || info == TARGET_BGIMAGE)
+ {
+ GSList *realuris = NULL;
+ gchar **uris;
+
+ uris = g_uri_list_extract_uris ((gchar *) gtk_selection_data_get_data (selection_data));
+ if (uris != NULL)
+ {
+ GtkWidget *w;
+ GdkWindow *window;
+ GdkCursor *cursor;
+ gchar **uri;
+
+ w = appearance_capplet_get_widget (data, "appearance_window");
+ window = gtk_widget_get_window (w);
+
+ cursor = gdk_cursor_new_for_display (gdk_display_get_default (),
+ GDK_WATCH);
+ gdk_window_set_cursor (window, cursor);
+ gdk_cursor_unref (cursor);
+
+ for (uri = uris; *uri; ++uri)
+ {
+ GFile *f;
+
+ f = g_file_new_for_uri (*uri);
+ realuris = g_slist_append (realuris, g_file_get_path (f));
+ g_object_unref (f);
+ }
+
+ wp_add_images (data, realuris);
+ gdk_window_set_cursor (window, NULL);
+
+ g_strfreev (uris);
+ }
+ }
+}
+
+static void
+wp_drag_get_data (GtkWidget *widget,
+ GdkDragContext *context,
+ GtkSelectionData *selection_data,
+ guint type, guint time,
+ AppearanceData *data)
+{
+ if (type == TARGET_URI_LIST) {
+ MateWPItem *item = get_selected_item (data, NULL);
+
+ if (item != NULL) {
+ char *uris[2];
+
+ uris[0] = g_filename_to_uri (item->filename, NULL, NULL);
+ uris[1] = NULL;
+
+ gtk_selection_data_set_uris (selection_data, uris);
+
+ g_free (uris[0]);
+ }
+ }
+}
+
+static gboolean
+wp_view_tooltip_cb (GtkWidget *widget,
+ gint x,
+ gint y,
+ gboolean keyboard_mode,
+ GtkTooltip *tooltip,
+ AppearanceData *data)
+{
+ GtkTreeIter iter;
+ MateWPItem *item;
+
+ if (gtk_icon_view_get_tooltip_context (data->wp_view,
+ &x, &y,
+ keyboard_mode,
+ NULL,
+ NULL,
+ &iter))
+ {
+ gtk_tree_model_get (data->wp_model, &iter, 1, &item, -1);
+ gtk_tooltip_set_markup (tooltip, item->description);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gint
+wp_list_sort (GtkTreeModel *model,
+ GtkTreeIter *a, GtkTreeIter *b,
+ AppearanceData *data)
+{
+ MateWPItem *itema, *itemb;
+ gint retval;
+
+ gtk_tree_model_get (model, a, 1, &itema, -1);
+ gtk_tree_model_get (model, b, 1, &itemb, -1);
+
+ if (!strcmp (itema->filename, "(none)"))
+ {
+ retval = -1;
+ }
+ else if (!strcmp (itemb->filename, "(none)"))
+ {
+ retval = 1;
+ }
+ else
+ {
+ retval = g_utf8_collate (itema->description, itemb->description);
+ }
+
+ return retval;
+}
+
+static void
+wp_update_preview (GtkFileChooser *chooser,
+ AppearanceData *data)
+{
+ gchar *uri;
+
+ uri = gtk_file_chooser_get_preview_uri (chooser);
+
+ if (uri)
+ {
+ GdkPixbuf *pixbuf = NULL;
+ const gchar *mime_type = NULL;
+ GFile *file;
+ GFileInfo *file_info;
+
+ file = g_file_new_for_uri (uri);
+ file_info = g_file_query_info (file,
+ G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+ G_FILE_QUERY_INFO_NONE,
+ NULL, NULL);
+ g_object_unref (file);
+
+ if (file_info != NULL)
+ {
+ mime_type = g_file_info_get_content_type (file_info);
+ g_object_unref (file_info);
+ }
+
+ if (mime_type)
+ {
+ pixbuf = mate_desktop_thumbnail_factory_generate_thumbnail (data->thumb_factory,
+ uri,
+ mime_type);
+ }
+
+ if (pixbuf != NULL)
+ {
+ gtk_image_set_from_pixbuf (GTK_IMAGE (data->wp_image), pixbuf);
+ g_object_unref (pixbuf);
+ }
+ else
+ {
+ gtk_image_set_from_stock (GTK_IMAGE (data->wp_image),
+ "gtk-dialog-question",
+ GTK_ICON_SIZE_DIALOG);
+ }
+ }
+
+ gtk_file_chooser_set_preview_widget_active (chooser, TRUE);
+}
+
+static gboolean
+reload_item (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ AppearanceData *data)
+{
+ MateWPItem *item;
+ GdkPixbuf *pixbuf;
+
+ gtk_tree_model_get (model, iter, 1, &item, -1);
+
+ pixbuf = mate_wp_item_get_thumbnail (item,
+ data->thumb_factory,
+ data->thumb_width,
+ data->thumb_height);
+ if (pixbuf) {
+ gtk_list_store_set (GTK_LIST_STORE (data->wp_model), iter, 0, pixbuf, -1);
+ g_object_unref (pixbuf);
+ }
+
+ return FALSE;
+}
+
+static gdouble
+get_monitor_aspect_ratio_for_widget (GtkWidget *widget)
+{
+ gdouble aspect;
+ gint monitor;
+ GdkRectangle rect;
+
+ monitor = gdk_screen_get_monitor_at_window (gtk_widget_get_screen (widget), gtk_widget_get_window (widget));
+ gdk_screen_get_monitor_geometry (gtk_widget_get_screen (widget), monitor, &rect);
+ aspect = rect.height / (gdouble)rect.width;
+
+ return aspect;
+}
+
+#define LIST_IMAGE_SIZE 108
+
+static void
+compute_thumbnail_sizes (AppearanceData *data)
+{
+ gdouble aspect;
+
+ aspect = get_monitor_aspect_ratio_for_widget (GTK_WIDGET (data->wp_view));
+ if (aspect > 1) {
+ /* portrait */
+ data->thumb_width = LIST_IMAGE_SIZE / aspect;
+ data->thumb_height = LIST_IMAGE_SIZE;
+ } else {
+ data->thumb_width = LIST_IMAGE_SIZE;
+ data->thumb_height = LIST_IMAGE_SIZE * aspect;
+ }
+}
+
+static void
+reload_wallpapers (AppearanceData *data)
+{
+ compute_thumbnail_sizes (data);
+ gtk_tree_model_foreach (data->wp_model, (GtkTreeModelForeachFunc)reload_item, data);
+}
+
+static gboolean
+wp_load_stuffs (void *user_data)
+{
+ AppearanceData *data;
+ gchar *imagepath, *uri, *style;
+ MateWPItem *item;
+
+ data = (AppearanceData *) user_data;
+
+ compute_thumbnail_sizes (data);
+
+ mate_wp_xml_load_list (data);
+ g_hash_table_foreach (data->wp_hash, (GHFunc) wp_props_load_wallpaper,
+ data);
+
+ style = mateconf_client_get_string (data->client,
+ WP_OPTIONS_KEY,
+ NULL);
+ if (style == NULL)
+ style = g_strdup ("none");
+
+ uri = mateconf_client_get_string (data->client,
+ WP_FILE_KEY,
+ NULL);
+
+ if (uri && *uri == '\0')
+ {
+ g_free (uri);
+ uri = NULL;
+ }
+
+ if (uri == NULL)
+ uri = g_strdup ("(none)");
+
+ if (g_utf8_validate (uri, -1, NULL) && g_file_test (uri, G_FILE_TEST_EXISTS))
+ imagepath = g_strdup (uri);
+ else
+ imagepath = g_filename_from_utf8 (uri, -1, NULL, NULL, NULL);
+
+ g_free (uri);
+
+ item = g_hash_table_lookup (data->wp_hash, imagepath);
+
+ if (item != NULL)
+ {
+ /* update with the current mateconf settings */
+ mate_wp_item_update (item);
+
+ if (strcmp (style, "none") != 0)
+ {
+ if (item->deleted == TRUE)
+ {
+ item->deleted = FALSE;
+ wp_props_load_wallpaper (item->filename, item, data);
+ }
+
+ select_item (data, item, FALSE);
+ }
+ }
+ else if (strcmp (style, "none") != 0)
+ {
+ item = wp_add_image (data, imagepath);
+ if (item)
+ select_item (data, item, FALSE);
+ }
+
+ item = g_hash_table_lookup (data->wp_hash, "(none)");
+ if (item == NULL)
+ {
+ item = mate_wp_item_new ("(none)", data->wp_hash, data->thumb_factory);
+ if (item != NULL)
+ {
+ wp_props_load_wallpaper (item->filename, item, data);
+ }
+ }
+ else
+ {
+ if (item->deleted == TRUE)
+ {
+ item->deleted = FALSE;
+ wp_props_load_wallpaper (item->filename, item, data);
+ }
+
+ if (!strcmp (style, "none"))
+ {
+ select_item (data, item, FALSE);
+ wp_option_menu_set (data, MATE_BG_PLACEMENT_SCALED, FALSE);
+ }
+ }
+ g_free (imagepath);
+ g_free (style);
+
+ if (data->wp_uris) {
+ wp_add_images (data, data->wp_uris);
+ data->wp_uris = NULL;
+ }
+
+ return FALSE;
+}
+
+static void
+wp_select_after_realize (GtkWidget *widget,
+ AppearanceData *data)
+{
+ MateWPItem *item;
+
+ g_idle_add (wp_load_stuffs, data);
+
+ item = get_selected_item (data, NULL);
+ if (item == NULL)
+ item = g_hash_table_lookup (data->wp_hash, "(none)");
+
+ select_item (data, item, TRUE);
+}
+
+static GdkPixbuf *buttons[3];
+
+static void
+create_button_images (AppearanceData *data)
+{
+ GtkWidget *widget = (GtkWidget*)data->wp_view;
+ GtkStyle *style = gtk_widget_get_style (widget);
+ GtkIconSet *icon_set;
+ GdkPixbuf *pixbuf, *pb, *pb2;
+ gint i, w, h;
+
+ icon_set = gtk_style_lookup_icon_set (style, "gtk-media-play");
+ pb = gtk_icon_set_render_icon (icon_set,
+ style,
+ GTK_TEXT_DIR_RTL,
+ GTK_STATE_NORMAL,
+ GTK_ICON_SIZE_MENU,
+ widget,
+ NULL);
+ pb2 = gtk_icon_set_render_icon (icon_set,
+ style,
+ GTK_TEXT_DIR_LTR,
+ GTK_STATE_NORMAL,
+ GTK_ICON_SIZE_MENU,
+ widget,
+ NULL);
+ w = gdk_pixbuf_get_width (pb);
+ h = gdk_pixbuf_get_height (pb);
+
+ for (i = 0; i < 3; i++) {
+ pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, 2 * w, h);
+ gdk_pixbuf_fill (pixbuf, 0);
+ if (i > 0)
+ gdk_pixbuf_composite (pb, pixbuf, 0, 0, w, h, 0, 0, 1, 1, GDK_INTERP_NEAREST, 255);
+ if (i < 2)
+ gdk_pixbuf_composite (pb2, pixbuf, w, 0, w, h, w, 0, 1, 1, GDK_INTERP_NEAREST, 255);
+
+ buttons[i] = pixbuf;
+ }
+
+ g_object_unref (pb);
+ g_object_unref (pb2);
+}
+
+static void
+next_frame (AppearanceData *data,
+ GtkCellRenderer *cr,
+ gint direction)
+{
+ MateWPItem *item;
+ GtkTreeIter iter;
+ GdkPixbuf *pixbuf, *pb;
+ gint frame;
+
+ pixbuf = NULL;
+
+ frame = data->frame + direction;
+ item = get_selected_item (data, &iter);
+
+ if (frame >= 0)
+ pixbuf = mate_wp_item_get_frame_thumbnail (item,
+ data->thumb_factory,
+ data->thumb_width,
+ data->thumb_height,
+ frame);
+ if (pixbuf) {
+ gtk_list_store_set (GTK_LIST_STORE (data->wp_model), &iter, 0, pixbuf, -1);
+ g_object_unref (pixbuf);
+ data->frame = frame;
+ }
+
+ pb = buttons[1];
+ if (direction < 0) {
+ if (frame == 0)
+ pb = buttons[0];
+ }
+ else {
+ pixbuf = mate_wp_item_get_frame_thumbnail (item,
+ data->thumb_factory,
+ data->thumb_width,
+ data->thumb_height,
+ frame + 1);
+ if (pixbuf)
+ g_object_unref (pixbuf);
+ else
+ pb = buttons[2];
+ }
+ g_object_set (cr, "pixbuf", pb, NULL);
+}
+
+static gboolean
+wp_button_press_cb (GtkWidget *widget,
+ GdkEventButton *event,
+ AppearanceData *data)
+{
+ GtkCellRenderer *cell;
+ GdkEventButton *button_event = (GdkEventButton *) event;
+
+ if (event->type != GDK_BUTTON_PRESS)
+ return FALSE;
+
+ if (gtk_icon_view_get_item_at_pos (GTK_ICON_VIEW (widget),
+ button_event->x, button_event->y,
+ NULL, &cell)) {
+ if (g_object_get_data (G_OBJECT (cell), "buttons")) {
+ gint w, h;
+ GtkCellRenderer *cell2 = NULL;
+ gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &w, &h);
+ if (gtk_icon_view_get_item_at_pos (GTK_ICON_VIEW (widget),
+ button_event->x + w, button_event->y,
+ NULL, &cell2) && cell == cell2)
+ next_frame (data, cell, -1);
+ else
+ next_frame (data, cell, 1);
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static void
+wp_selected_changed_cb (GtkIconView *view,
+ AppearanceData *data)
+{
+ GtkCellRenderer *cr;
+ GList *cells, *l;
+
+ data->frame = -1;
+
+ cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (data->wp_view));
+ for (l = cells; l; l = l->next) {
+ cr = l->data;
+ if (g_object_get_data (G_OBJECT (cr), "buttons"))
+ g_object_set (cr, "pixbuf", buttons[0], NULL);
+ }
+ g_list_free (cells);
+}
+
+static void
+buttons_cell_data_func (GtkCellLayout *layout,
+ GtkCellRenderer *cell,
+ GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer user_data)
+{
+ AppearanceData *data = user_data;
+ GtkTreePath *path;
+ MateWPItem *item;
+ gboolean visible;
+
+ path = gtk_tree_model_get_path (model, iter);
+
+ if (gtk_icon_view_path_is_selected (GTK_ICON_VIEW (layout), path)) {
+ item = get_selected_item (data, NULL);
+ visible = mate_bg_changes_with_time (item->bg);
+ }
+ else
+ visible = FALSE;
+
+ g_object_set (G_OBJECT (cell), "visible", visible, NULL);
+
+ gtk_tree_path_free (path);
+}
+
+static void
+screen_monitors_changed (GdkScreen *screen,
+ AppearanceData *data)
+{
+ reload_wallpapers (data);
+}
+
+void
+desktop_init (AppearanceData *data,
+ const gchar **uris)
+{
+ GtkWidget *add_button, *w;
+ GtkCellRenderer *cr;
+ char *url;
+
+ data->wp_update_mateconf = TRUE;
+
+ data->wp_uris = NULL;
+ if (uris != NULL) {
+ while (*uris != NULL) {
+ data->wp_uris = g_slist_append (data->wp_uris, g_strdup (*uris));
+ uris++;
+ }
+ }
+
+ w = appearance_capplet_get_widget (data, "more_backgrounds_linkbutton");
+ url = mateconf_client_get_string (data->client, MORE_BACKGROUNDS_URL_KEY, NULL);
+ if (url != NULL && url[0] != '\0') {
+ gtk_link_button_set_uri (GTK_LINK_BUTTON (w), url);
+ gtk_widget_show (w);
+ } else {
+ gtk_widget_hide (w);
+ }
+ g_free (url);
+
+ data->wp_hash = g_hash_table_new (g_str_hash, g_str_equal);
+
+ mateconf_client_add_dir (data->client, WP_PATH_KEY,
+ MATECONF_CLIENT_PRELOAD_ONELEVEL, NULL);
+
+ mateconf_client_notify_add (data->client,
+ WP_FILE_KEY,
+ (MateConfClientNotifyFunc) wp_file_changed,
+ data, NULL, NULL);
+ mateconf_client_notify_add (data->client,
+ WP_OPTIONS_KEY,
+ (MateConfClientNotifyFunc) wp_options_changed,
+ data, NULL, NULL);
+ mateconf_client_notify_add (data->client,
+ WP_SHADING_KEY,
+ (MateConfClientNotifyFunc) wp_shading_changed,
+ data, NULL, NULL);
+ mateconf_client_notify_add (data->client,
+ WP_PCOLOR_KEY,
+ (MateConfClientNotifyFunc) wp_color1_changed,
+ data, NULL, NULL);
+ mateconf_client_notify_add (data->client,
+ WP_SCOLOR_KEY,
+ (MateConfClientNotifyFunc) wp_color2_changed,
+ data, NULL, NULL);
+
+ data->wp_model = GTK_TREE_MODEL (gtk_list_store_new (2, GDK_TYPE_PIXBUF,
+ G_TYPE_POINTER));
+
+ data->wp_view = GTK_ICON_VIEW (appearance_capplet_get_widget (data, "wp_view"));
+ gtk_icon_view_set_model (data->wp_view, GTK_TREE_MODEL (data->wp_model));
+
+ g_signal_connect_after (data->wp_view, "realize",
+ (GCallback) wp_select_after_realize, data);
+
+ gtk_cell_layout_clear (GTK_CELL_LAYOUT (data->wp_view));
+
+ cr = gtk_cell_renderer_pixbuf_new ();
+ g_object_set (cr, "xpad", 5, "ypad", 5, NULL);
+
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (data->wp_view), cr, TRUE);
+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (data->wp_view), cr,
+ "pixbuf", 0,
+ NULL);
+
+ cr = gtk_cell_renderer_pixbuf_new ();
+ create_button_images (data);
+ g_object_set (cr,
+ "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE,
+ "pixbuf", buttons[0],
+ NULL);
+ g_object_set_data (G_OBJECT (cr), "buttons", GINT_TO_POINTER (TRUE));
+
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (data->wp_view), cr, FALSE);
+ gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (data->wp_view), cr,
+ buttons_cell_data_func, data, NULL);
+ g_signal_connect (data->wp_view, "selection-changed",
+ (GCallback) wp_selected_changed_cb, data);
+ g_signal_connect (data->wp_view, "button-press-event",
+ G_CALLBACK (wp_button_press_cb), data);
+
+ data->frame = -1;
+
+ gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (data->wp_model), 1,
+ (GtkTreeIterCompareFunc) wp_list_sort,
+ data, NULL);
+
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (data->wp_model),
+ 1, GTK_SORT_ASCENDING);
+
+ gtk_drag_dest_set (GTK_WIDGET (data->wp_view), GTK_DEST_DEFAULT_ALL, drop_types,
+ G_N_ELEMENTS (drop_types), GDK_ACTION_COPY | GDK_ACTION_MOVE);
+ g_signal_connect (data->wp_view, "drag_data_received",
+ (GCallback) wp_drag_received, data);
+
+ gtk_drag_source_set (GTK_WIDGET (data->wp_view), GDK_BUTTON1_MASK,
+ drag_types, G_N_ELEMENTS (drag_types), GDK_ACTION_COPY);
+ g_signal_connect (data->wp_view, "drag-data-get",
+ (GCallback) wp_drag_get_data, data);
+
+ data->wp_style_menu = appearance_capplet_get_widget (data, "wp_style_menu");
+
+ g_signal_connect (data->wp_style_menu, "changed",
+ (GCallback) wp_scale_type_changed, data);
+
+ data->wp_color_menu = appearance_capplet_get_widget (data, "wp_color_menu");
+
+ g_signal_connect (data->wp_color_menu, "changed",
+ (GCallback) wp_shade_type_changed, data);
+
+ data->wp_scpicker = appearance_capplet_get_widget (data, "wp_scpicker");
+
+ g_signal_connect (data->wp_scpicker, "color-set",
+ (GCallback) wp_scolor_changed, data);
+
+ data->wp_pcpicker = appearance_capplet_get_widget (data, "wp_pcpicker");
+
+ g_signal_connect (data->wp_pcpicker, "color-set",
+ (GCallback) wp_scolor_changed, data);
+
+ add_button = appearance_capplet_get_widget (data, "wp_add_button");
+ gtk_button_set_image (GTK_BUTTON (add_button),
+ gtk_image_new_from_stock ("gtk-add", GTK_ICON_SIZE_BUTTON));
+
+ g_signal_connect (add_button, "clicked",
+ (GCallback) wp_file_open_dialog, data);
+
+ data->wp_rem_button = appearance_capplet_get_widget (data, "wp_rem_button");
+
+ g_signal_connect (data->wp_rem_button, "clicked",
+ (GCallback) wp_remove_wallpaper, data);
+ data->screen_monitors_handler = g_signal_connect (gtk_widget_get_screen (GTK_WIDGET (data->wp_view)),
+ "monitors-changed",
+ G_CALLBACK (screen_monitors_changed),
+ data);
+ data->screen_size_handler = g_signal_connect (gtk_widget_get_screen (GTK_WIDGET (data->wp_view)),
+ "size-changed",
+ G_CALLBACK (screen_monitors_changed),
+ data);
+
+ g_signal_connect (data->wp_view, "selection-changed",
+ (GCallback) wp_props_wp_selected, data);
+ g_signal_connect (data->wp_view, "query-tooltip",
+ (GCallback) wp_view_tooltip_cb, data);
+ gtk_widget_set_has_tooltip (GTK_WIDGET (data->wp_view), TRUE);
+
+ wp_set_sensitivities (data);
+
+ /* create the file selector later to save time on startup */
+ data->wp_filesel = NULL;
+
+}
+
+void
+desktop_shutdown (AppearanceData *data)
+{
+ mate_wp_xml_save_list (data);
+
+ if (data->screen_monitors_handler > 0) {
+ g_signal_handler_disconnect (gtk_widget_get_screen (GTK_WIDGET (data->wp_view)),
+ data->screen_monitors_handler);
+ data->screen_monitors_handler = 0;
+ }
+ if (data->screen_size_handler > 0) {
+ g_signal_handler_disconnect (gtk_widget_get_screen (GTK_WIDGET (data->wp_view)),
+ data->screen_size_handler);
+ data->screen_size_handler = 0;
+ }
+
+ g_slist_foreach (data->wp_uris, (GFunc) g_free, NULL);
+ g_slist_free (data->wp_uris);
+ if (data->wp_filesel)
+ {
+ g_object_ref_sink (data->wp_filesel);
+ g_object_unref (data->wp_filesel);
+ }
+}
diff --git a/capplets/appearance/appearance-desktop.h b/capplets/appearance/appearance-desktop.h
new file mode 100644
index 00000000..ae0b25a9
--- /dev/null
+++ b/capplets/appearance/appearance-desktop.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2007 The MATE Foundation
+ * Written by Denis Washington <[email protected]>
+ * All Rights Reserved
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+void desktop_init (AppearanceData *data, const gchar **uris);
+void desktop_shutdown (AppearanceData *data);
diff --git a/capplets/appearance/appearance-font.c b/capplets/appearance/appearance-font.c
new file mode 100644
index 00000000..d9f4d3c2
--- /dev/null
+++ b/capplets/appearance/appearance-font.c
@@ -0,0 +1,961 @@
+/*
+ * Copyright (C) 2007 The GNOME Foundation
+ * Written by Jonathan Blandford <[email protected]>
+ * Jens Granseuer <[email protected]>
+ * All Rights Reserved
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "appearance.h"
+
+#include <string.h>
+#include <stdarg.h>
+#include <math.h>
+
+#ifdef HAVE_XFT2
+ #include <gdk/gdkx.h>
+ #include <X11/Xft/Xft.h>
+#endif /* HAVE_XFT2 */
+
+#include <glib/gi18n.h>
+
+#include "capplet-util.h"
+#include "mateconf-property-editor.h"
+
+#define GTK_FONT_KEY "/desktop/mate/interface/font_name"
+#define DESKTOP_FONT_KEY "/apps/caja/preferences/desktop_font"
+
+#define MARCO_DIR "/apps/marco/general"
+#define WINDOW_TITLE_FONT_KEY MARCO_DIR "/titlebar_font"
+#define WINDOW_TITLE_USES_SYSTEM_KEY MARCO_DIR "/titlebar_uses_system_font"
+#define MONOSPACE_FONT_KEY "/desktop/mate/interface/monospace_font_name"
+#define DOCUMENT_FONT_KEY "/desktop/mate/interface/document_font_name"
+
+#ifdef HAVE_XFT2
+#define FONT_RENDER_DIR "/desktop/mate/font_rendering"
+#define FONT_ANTIALIASING_KEY FONT_RENDER_DIR "/antialiasing"
+#define FONT_HINTING_KEY FONT_RENDER_DIR "/hinting"
+#define FONT_RGBA_ORDER_KEY FONT_RENDER_DIR "/rgba_order"
+#define FONT_DPI_KEY FONT_RENDER_DIR "/dpi"
+
+/* X servers sometimes lie about the screen's physical dimensions, so we cannot
+ * compute an accurate DPI value. When this happens, the user gets fonts that
+ * are too huge or too tiny. So, we see what the server returns: if it reports
+ * something outside of the range [DPI_LOW_REASONABLE_VALUE,
+ * DPI_HIGH_REASONABLE_VALUE], then we assume that it is lying and we use
+ * DPI_FALLBACK instead.
+ *
+ * See get_dpi_from_mateconf_or_server() below, and also
+ * https://bugzilla.novell.com/show_bug.cgi?id=217790
+ */
+#define DPI_FALLBACK 96
+#define DPI_LOW_REASONABLE_VALUE 50
+#define DPI_HIGH_REASONABLE_VALUE 500
+#endif /* HAVE_XFT2 */
+
+static gboolean in_change = FALSE;
+static gchar* old_font = NULL;
+
+#define MAX_FONT_POINT_WITHOUT_WARNING 32
+#define MAX_FONT_SIZE_WITHOUT_WARNING MAX_FONT_POINT_WITHOUT_WARNING * 1024
+
+#ifdef HAVE_XFT2
+
+/*
+ * Code for displaying previews of font rendering with various Xft options
+ */
+
+static void sample_size_request(GtkWidget* darea, GtkRequisition* requisition)
+{
+ GdkPixbuf* pixbuf = g_object_get_data(G_OBJECT(darea), "sample-pixbuf");
+
+ requisition->width = gdk_pixbuf_get_width(pixbuf) + 2;
+ requisition->height = gdk_pixbuf_get_height(pixbuf) + 2;
+}
+
+static void sample_expose(GtkWidget* darea, GdkEventExpose* expose)
+{
+ GtkAllocation allocation;
+ GdkPixbuf* pixbuf = g_object_get_data(G_OBJECT(darea), "sample-pixbuf");
+ GdkWindow* window = gtk_widget_get_window(darea);
+ GtkStyle* style = gtk_widget_get_style(darea);
+ int width = gdk_pixbuf_get_width(pixbuf);
+ int height = gdk_pixbuf_get_height(pixbuf);
+
+ gtk_widget_get_allocation (darea, &allocation);
+
+ int x = (allocation.width - width) / 2;
+ int y = (allocation.height - height) / 2;
+
+ gdk_draw_rectangle(window, style->white_gc, TRUE, 0, 0, allocation.width, allocation.height);
+ gdk_draw_rectangle(window, style->black_gc, FALSE, 0, 0, allocation.width - 1, allocation.height - 1);
+
+ gdk_draw_pixbuf(window, NULL, pixbuf, 0, 0, x, y, width, height, GDK_RGB_DITHER_NORMAL, 0, 0);
+}
+
+typedef enum {
+ ANTIALIAS_NONE,
+ ANTIALIAS_GRAYSCALE,
+ ANTIALIAS_RGBA
+} Antialiasing;
+
+static MateConfEnumStringPair antialias_enums[] = {
+ {ANTIALIAS_NONE, "none"},
+ {ANTIALIAS_GRAYSCALE, "grayscale"},
+ {ANTIALIAS_RGBA, "rgba"},
+ {-1, NULL}
+};
+
+typedef enum {
+ HINT_NONE,
+ HINT_SLIGHT,
+ HINT_MEDIUM,
+ HINT_FULL
+} Hinting;
+
+static MateConfEnumStringPair hint_enums[] = {
+ {HINT_NONE, "none"},
+ {HINT_SLIGHT, "slight"},
+ {HINT_MEDIUM, "medium"},
+ {HINT_FULL, "full"},
+ {-1, NULL}
+};
+
+typedef enum {
+ RGBA_RGB,
+ RGBA_BGR,
+ RGBA_VRGB,
+ RGBA_VBGR
+} RgbaOrder;
+
+static MateConfEnumStringPair rgba_order_enums[] = {
+ {RGBA_RGB, "rgb" },
+ {RGBA_BGR, "bgr" },
+ {RGBA_VRGB, "vrgb" },
+ {RGBA_VBGR, "vbgr" },
+ {-1, NULL }
+};
+
+static XftFont* open_pattern(FcPattern* pattern, Antialiasing antialiasing, Hinting hinting)
+{
+ #ifdef FC_HINT_STYLE
+ static const int hintstyles[] = {
+ FC_HINT_NONE, FC_HINT_SLIGHT, FC_HINT_MEDIUM, FC_HINT_FULL
+ };
+ #endif /* FC_HINT_STYLE */
+
+ FcPattern* res_pattern;
+ FcResult result;
+ XftFont* font;
+
+ Display* xdisplay = gdk_x11_get_default_xdisplay();
+ int screen = gdk_x11_get_default_screen();
+
+ res_pattern = XftFontMatch(xdisplay, screen, pattern, &result);
+
+ if (res_pattern == NULL)
+ {
+ return NULL;
+ }
+
+ FcPatternDel(res_pattern, FC_HINTING);
+ FcPatternAddBool(res_pattern, FC_HINTING, hinting != HINT_NONE);
+
+ #ifdef FC_HINT_STYLE
+ FcPatternDel(res_pattern, FC_HINT_STYLE);
+ FcPatternAddInteger(res_pattern, FC_HINT_STYLE, hintstyles[hinting]);
+ #endif /* FC_HINT_STYLE */
+
+ FcPatternDel(res_pattern, FC_ANTIALIAS);
+ FcPatternAddBool(res_pattern, FC_ANTIALIAS, antialiasing != ANTIALIAS_NONE);
+
+ FcPatternDel(res_pattern, FC_RGBA);
+ FcPatternAddInteger(res_pattern, FC_RGBA, antialiasing == ANTIALIAS_RGBA ? FC_RGBA_RGB : FC_RGBA_NONE);
+
+ FcPatternDel(res_pattern, FC_DPI);
+ FcPatternAddInteger(res_pattern, FC_DPI, 96);
+
+ font = XftFontOpenPattern(xdisplay, res_pattern);
+
+ if (!font)
+ {
+ FcPatternDestroy(res_pattern);
+ }
+
+ return font;
+}
+
+static void setup_font_sample(GtkWidget* darea, Antialiasing antialiasing, Hinting hinting)
+{
+ const char* string1 = "abcfgop AO ";
+ const char* string2 = "abcfgop";
+
+ XftColor black, white;
+ XRenderColor rendcolor;
+
+ Display* xdisplay = gdk_x11_get_default_xdisplay();
+
+ GdkColormap* colormap = gdk_rgb_get_colormap();
+ Colormap xcolormap = GDK_COLORMAP_XCOLORMAP(colormap);
+
+ GdkVisual* visual = gdk_colormap_get_visual(colormap);
+ Visual* xvisual = GDK_VISUAL_XVISUAL(visual);
+
+ FcPattern* pattern;
+ XftFont* font1;
+ XftFont* font2;
+ XGlyphInfo extents1 = { 0 };
+ XGlyphInfo extents2 = { 0 };
+ GdkPixmap* pixmap;
+ XftDraw* draw;
+ GdkPixbuf* tmp_pixbuf;
+ GdkPixbuf* pixbuf;
+
+ int width, height;
+ int ascent, descent;
+
+ pattern = FcPatternBuild (NULL,
+ FC_FAMILY, FcTypeString, "Serif",
+ FC_SLANT, FcTypeInteger, FC_SLANT_ROMAN,
+ FC_SIZE, FcTypeDouble, 18.,
+ NULL);
+ font1 = open_pattern (pattern, antialiasing, hinting);
+ FcPatternDestroy (pattern);
+
+ pattern = FcPatternBuild (NULL,
+ FC_FAMILY, FcTypeString, "Serif",
+ FC_SLANT, FcTypeInteger, FC_SLANT_ITALIC,
+ FC_SIZE, FcTypeDouble, 20.,
+ NULL);
+ font2 = open_pattern (pattern, antialiasing, hinting);
+ FcPatternDestroy (pattern);
+
+ ascent = 0;
+ descent = 0;
+
+ if (font1)
+ {
+ XftTextExtentsUtf8 (xdisplay, font1, (unsigned char*) string1,
+ strlen (string1), &extents1);
+ ascent = MAX (ascent, font1->ascent);
+ descent = MAX (descent, font1->descent);
+ }
+
+ if (font2)
+ {
+ XftTextExtentsUtf8 (xdisplay, font2, (unsigned char*) string2, strlen (string2), &extents2);
+ ascent = MAX (ascent, font2->ascent);
+ descent = MAX (descent, font2->descent);
+ }
+
+ width = extents1.xOff + extents2.xOff + 4;
+ height = ascent + descent + 2;
+
+ pixmap = gdk_pixmap_new (NULL, width, height, visual->depth);
+
+ draw = XftDrawCreate (xdisplay, GDK_DRAWABLE_XID (pixmap), xvisual, xcolormap);
+
+ rendcolor.red = 0;
+ rendcolor.green = 0;
+ rendcolor.blue = 0;
+ rendcolor.alpha = 0xffff;
+
+ XftColorAllocValue(xdisplay, xvisual, xcolormap, &rendcolor, &black);
+
+ rendcolor.red = 0xffff;
+ rendcolor.green = 0xffff;
+ rendcolor.blue = 0xffff;
+ rendcolor.alpha = 0xffff;
+
+ XftColorAllocValue(xdisplay, xvisual, xcolormap, &rendcolor, &white);
+ XftDrawRect(draw, &white, 0, 0, width, height);
+
+ if (font1)
+ {
+ XftDrawStringUtf8(draw, &black, font1, 2, 2 + ascent, (unsigned char*) string1, strlen(string1));
+ }
+
+ if (font2)
+ {
+ XftDrawStringUtf8(draw, &black, font2, 2 + extents1.xOff, 2 + ascent, (unsigned char*) string2, strlen(string2));
+ }
+
+ XftDrawDestroy(draw);
+
+ if (font1)
+ {
+ XftFontClose(xdisplay, font1);
+ }
+
+ if (font2)
+ {
+ XftFontClose(xdisplay, font2);
+ }
+
+ tmp_pixbuf = gdk_pixbuf_get_from_drawable(NULL, pixmap, colormap, 0, 0, 0, 0, width, height);
+ pixbuf = gdk_pixbuf_scale_simple(tmp_pixbuf, 1 * width, 1 * height, GDK_INTERP_TILES);
+
+ g_object_unref(pixmap);
+ g_object_unref(tmp_pixbuf);
+
+ g_object_set_data_full(G_OBJECT(darea), "sample-pixbuf", pixbuf, (GDestroyNotify) g_object_unref);
+
+ g_signal_connect(darea, "size_request", G_CALLBACK(sample_size_request), NULL);
+ g_signal_connect(darea, "expose_event", G_CALLBACK(sample_expose), NULL);
+}
+
+/*
+ * Code implementing a group of radio buttons with different Xft option combinations.
+ * If one of the buttons is matched by the MateConf key, we pick it. Otherwise we
+ * show the group as inconsistent.
+ */
+static void
+font_render_get_mateconf (MateConfClient *client,
+ Antialiasing *antialiasing,
+ Hinting *hinting)
+{
+ gchar *antialias_str = mateconf_client_get_string (client, FONT_ANTIALIASING_KEY, NULL);
+ gchar *hint_str = mateconf_client_get_string (client, FONT_HINTING_KEY, NULL);
+ gint val;
+
+ val = ANTIALIAS_GRAYSCALE;
+ if (antialias_str) {
+ mateconf_string_to_enum (antialias_enums, antialias_str, &val);
+ g_free (antialias_str);
+ }
+ *antialiasing = val;
+
+ val = HINT_FULL;
+ if (hint_str) {
+ mateconf_string_to_enum (hint_enums, hint_str, &val);
+ g_free (hint_str);
+ }
+ *hinting = val;
+}
+
+typedef struct {
+ Antialiasing antialiasing;
+ Hinting hinting;
+ GtkToggleButton *radio;
+} FontPair;
+
+static GSList *font_pairs = NULL;
+
+static void
+font_render_load (MateConfClient *client)
+{
+ Antialiasing antialiasing;
+ Hinting hinting;
+ gboolean inconsistent = TRUE;
+ GSList *tmp_list;
+
+ font_render_get_mateconf (client, &antialiasing, &hinting);
+
+ in_change = TRUE;
+
+ for (tmp_list = font_pairs; tmp_list; tmp_list = tmp_list->next) {
+ FontPair *pair = tmp_list->data;
+
+ if (antialiasing == pair->antialiasing && hinting == pair->hinting) {
+ gtk_toggle_button_set_active (pair->radio, TRUE);
+ inconsistent = FALSE;
+ break;
+ }
+ }
+
+ for (tmp_list = font_pairs; tmp_list; tmp_list = tmp_list->next) {
+ FontPair *pair = tmp_list->data;
+
+ gtk_toggle_button_set_inconsistent (pair->radio, inconsistent);
+ }
+
+ in_change = FALSE;
+}
+
+static void
+font_render_changed (MateConfClient *client,
+ guint cnxn_id,
+ MateConfEntry *entry,
+ gpointer user_data)
+{
+ font_render_load (client);
+}
+
+static void
+font_radio_toggled (GtkToggleButton *toggle_button,
+ FontPair *pair)
+{
+ if (!in_change) {
+ MateConfClient *client = mateconf_client_get_default ();
+
+ mateconf_client_set_string (client, FONT_ANTIALIASING_KEY,
+ mateconf_enum_to_string (antialias_enums, pair->antialiasing),
+ NULL);
+ mateconf_client_set_string (client, FONT_HINTING_KEY,
+ mateconf_enum_to_string (hint_enums, pair->hinting),
+ NULL);
+
+ /* Restore back to the previous state until we get notification */
+ font_render_load (client);
+ g_object_unref (client);
+ }
+}
+
+static void
+setup_font_pair (GtkWidget *radio,
+ GtkWidget *darea,
+ Antialiasing antialiasing,
+ Hinting hinting)
+{
+ FontPair *pair = g_new (FontPair, 1);
+
+ pair->antialiasing = antialiasing;
+ pair->hinting = hinting;
+ pair->radio = GTK_TOGGLE_BUTTON (radio);
+
+ setup_font_sample (darea, antialiasing, hinting);
+ font_pairs = g_slist_prepend (font_pairs, pair);
+
+ g_signal_connect (radio, "toggled",
+ G_CALLBACK (font_radio_toggled), pair);
+}
+#endif /* HAVE_XFT2 */
+
+static void
+marco_titlebar_load_sensitivity (AppearanceData *data)
+{
+ gtk_widget_set_sensitive (appearance_capplet_get_widget (data, "window_title_font"),
+ !mateconf_client_get_bool (data->client,
+ WINDOW_TITLE_USES_SYSTEM_KEY,
+ NULL));
+}
+
+static void
+marco_changed (MateConfClient *client,
+ guint cnxn_id,
+ MateConfEntry *entry,
+ gpointer user_data)
+{
+ marco_titlebar_load_sensitivity (user_data);
+}
+
+/* returns 0 if the font is safe, otherwise returns the size in points. */
+static gint
+font_dangerous (const char *font)
+{
+ PangoFontDescription *pfd;
+ gboolean retval = 0;
+
+ pfd = pango_font_description_from_string (font);
+ if (pfd == NULL)
+ /* an invalid font was passed in. This isn't our problem. */
+ return 0;
+
+ if ((pango_font_description_get_set_fields (pfd) & PANGO_FONT_MASK_SIZE) &&
+ (pango_font_description_get_size (pfd) >= MAX_FONT_SIZE_WITHOUT_WARNING)) {
+ retval = pango_font_description_get_size (pfd)/1024;
+ }
+ pango_font_description_free (pfd);
+
+ return retval;
+}
+
+static MateConfValue *
+application_font_to_mateconf (MateConfPropertyEditor *peditor,
+ MateConfValue *value)
+{
+ MateConfValue *new_value;
+ const char *new_font;
+ GtkWidget *font_button;
+ gint danger_level;
+
+ font_button = GTK_WIDGET (mateconf_property_editor_get_ui_control (peditor));
+ g_return_val_if_fail (font_button != NULL, NULL);
+
+ new_value = mateconf_value_new (MATECONF_VALUE_STRING);
+ new_font = mateconf_value_get_string (value);
+ if (font_dangerous (old_font)) {
+ /* If we're already too large, we don't warn again. */
+ mateconf_value_set_string (new_value, new_font);
+ return new_value;
+ }
+
+ danger_level = font_dangerous (new_font);
+ if (danger_level) {
+ GtkWidget *warning_dialog, *apply_button;
+ const gchar *warning_label;
+ gchar *warning_label2;
+
+ warning_label = _("Font may be too large");
+
+ if (danger_level > MAX_FONT_POINT_WITHOUT_WARNING) {
+ warning_label2 = g_strdup_printf (ngettext (
+ "The font selected is %d point large, "
+ "and may make it difficult to effectively "
+ "use the computer. It is recommended that "
+ "you select a size smaller than %d.",
+ "The font selected is %d points large, "
+ "and may make it difficult to effectively "
+ "use the computer. It is recommended that "
+ "you select a size smaller than %d.",
+ danger_level),
+ danger_level,
+ MAX_FONT_POINT_WITHOUT_WARNING);
+ } else {
+ warning_label2 = g_strdup_printf (ngettext (
+ "The font selected is %d point large, "
+ "and may make it difficult to effectively "
+ "use the computer. It is recommended that "
+ "you select a smaller sized font.",
+ "The font selected is %d points large, "
+ "and may make it difficult to effectively "
+ "use the computer. It is recommended that "
+ "you select a smaller sized font.",
+ danger_level),
+ danger_level);
+ }
+
+ warning_dialog = gtk_message_dialog_new (NULL,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_NONE,
+ "%s",
+ warning_label);
+
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (warning_dialog),
+ "%s", warning_label2);
+
+ gtk_dialog_add_button (GTK_DIALOG (warning_dialog),
+ _("Use previous font"), GTK_RESPONSE_CLOSE);
+
+ apply_button = gtk_button_new_with_label (_("Use selected font"));
+
+ gtk_button_set_image (GTK_BUTTON (apply_button), gtk_image_new_from_stock (GTK_STOCK_APPLY, GTK_ICON_SIZE_BUTTON));
+ gtk_dialog_add_action_widget (GTK_DIALOG (warning_dialog), apply_button, GTK_RESPONSE_APPLY);
+ gtk_widget_set_can_default (apply_button, TRUE);
+ gtk_widget_show (apply_button);
+
+ gtk_dialog_set_default_response (GTK_DIALOG (warning_dialog), GTK_RESPONSE_CLOSE);
+
+ g_free (warning_label2);
+
+ if (gtk_dialog_run (GTK_DIALOG (warning_dialog)) == GTK_RESPONSE_APPLY) {
+ mateconf_value_set_string (new_value, new_font);
+ } else {
+ mateconf_value_set_string (new_value, old_font);
+ gtk_font_button_set_font_name (GTK_FONT_BUTTON (font_button), old_font);
+ }
+
+ gtk_widget_destroy (warning_dialog);
+ } else {
+ mateconf_value_set_string (new_value, new_font);
+ }
+
+ return new_value;
+}
+
+static void
+application_font_changed (GtkWidget *font_button)
+{
+ const gchar *font;
+
+ font = gtk_font_button_get_font_name (GTK_FONT_BUTTON (font_button));
+ g_free (old_font);
+ old_font = g_strdup (font);
+}
+
+#ifdef HAVE_XFT2
+/*
+ * EnumGroup - a group of radio buttons tied to a string enumeration
+ * value. We add this here because the mateconf peditor
+ * equivalent of this is both painful to use (you have
+ * to supply functions to convert from enums to indices)
+ * and conceptually broken (the order of radio buttons
+ * in a group when using Glade is not predictable.
+ */
+typedef struct
+{
+ MateConfClient *client;
+ GSList *items;
+ gchar *mateconf_key;
+ MateConfEnumStringPair *enums;
+ int default_value;
+} EnumGroup;
+
+typedef struct
+{
+ EnumGroup *group;
+ GtkToggleButton *widget;
+ int value;
+} EnumItem;
+
+static void
+enum_group_load (EnumGroup *group)
+{
+ gchar *str = mateconf_client_get_string (group->client, group->mateconf_key, NULL);
+ gint val = group->default_value;
+ GSList *tmp_list;
+
+ if (str)
+ mateconf_string_to_enum (group->enums, str, &val);
+
+ g_free (str);
+
+ in_change = TRUE;
+
+ for (tmp_list = group->items; tmp_list; tmp_list = tmp_list->next) {
+ EnumItem *item = tmp_list->data;
+
+ if (val == item->value)
+ gtk_toggle_button_set_active (item->widget, TRUE);
+ }
+
+ in_change = FALSE;
+}
+
+static void
+enum_group_changed (MateConfClient *client,
+ guint cnxn_id,
+ MateConfEntry *entry,
+ gpointer user_data)
+{
+ enum_group_load (user_data);
+}
+
+static void
+enum_item_toggled (GtkToggleButton *toggle_button,
+ EnumItem *item)
+{
+ EnumGroup *group = item->group;
+
+ if (!in_change) {
+ mateconf_client_set_string (group->client, group->mateconf_key,
+ mateconf_enum_to_string (group->enums, item->value),
+ NULL);
+ }
+
+ /* Restore back to the previous state until we get notification */
+ enum_group_load (group);
+}
+
+static EnumGroup *
+enum_group_create (const gchar *mateconf_key,
+ MateConfEnumStringPair *enums,
+ int default_value,
+ GtkWidget *first_widget,
+ ...)
+{
+ EnumGroup *group;
+ GtkWidget *widget;
+ va_list args;
+
+ group = g_new (EnumGroup, 1);
+
+ group->client = mateconf_client_get_default ();
+ group->mateconf_key = g_strdup (mateconf_key);
+ group->enums = enums;
+ group->default_value = default_value;
+ group->items = NULL;
+
+ va_start (args, first_widget);
+
+ widget = first_widget;
+ while (widget) {
+ EnumItem *item;
+
+ item = g_new (EnumItem, 1);
+ item->group = group;
+ item->widget = GTK_TOGGLE_BUTTON (widget);
+ item->value = va_arg (args, int);
+
+ g_signal_connect (item->widget, "toggled",
+ G_CALLBACK (enum_item_toggled), item);
+
+ group->items = g_slist_prepend (group->items, item);
+
+ widget = va_arg (args, GtkWidget *);
+ }
+
+ va_end (args);
+
+ enum_group_load (group);
+
+ mateconf_client_notify_add (group->client, mateconf_key,
+ enum_group_changed,
+ group, NULL, NULL);
+
+ return group;
+}
+
+static void
+enum_group_destroy (EnumGroup *group)
+{
+ g_object_unref (group->client);
+ g_free (group->mateconf_key);
+
+ g_slist_foreach (group->items, (GFunc) g_free, NULL);
+ g_slist_free (group->items);
+
+ g_free (group);
+}
+
+static double
+dpi_from_pixels_and_mm (int pixels, int mm)
+{
+ double dpi;
+
+ if (mm >= 1)
+ dpi = pixels / (mm / 25.4);
+ else
+ dpi = 0;
+
+ return dpi;
+}
+
+static double
+get_dpi_from_x_server (void)
+{
+ GdkScreen *screen;
+ double dpi;
+
+ screen = gdk_screen_get_default ();
+ if (screen) {
+ double width_dpi, height_dpi;
+
+ width_dpi = dpi_from_pixels_and_mm (gdk_screen_get_width (screen),
+ gdk_screen_get_width_mm (screen));
+ height_dpi = dpi_from_pixels_and_mm (gdk_screen_get_height (screen),
+ gdk_screen_get_height_mm (screen));
+
+ if (width_dpi < DPI_LOW_REASONABLE_VALUE || width_dpi > DPI_HIGH_REASONABLE_VALUE ||
+ height_dpi < DPI_LOW_REASONABLE_VALUE || height_dpi > DPI_HIGH_REASONABLE_VALUE)
+ dpi = DPI_FALLBACK;
+ else
+ dpi = (width_dpi + height_dpi) / 2.0;
+ } else {
+ /* Huh!? No screen? */
+ dpi = DPI_FALLBACK;
+ }
+
+ return dpi;
+}
+
+/*
+ * The font rendering details dialog
+ */
+static void
+dpi_load (MateConfClient *client,
+ GtkSpinButton *spinner)
+{
+ MateConfValue *value;
+ gdouble dpi;
+
+ value = mateconf_client_get_without_default (client, FONT_DPI_KEY, NULL);
+
+ if (value) {
+ dpi = mateconf_value_get_float (value);
+ mateconf_value_free (value);
+ } else
+ dpi = get_dpi_from_x_server ();
+
+ if (dpi < DPI_LOW_REASONABLE_VALUE)
+ dpi = DPI_LOW_REASONABLE_VALUE;
+
+ in_change = TRUE;
+ gtk_spin_button_set_value (spinner, dpi);
+ in_change = FALSE;
+}
+
+static void
+dpi_changed (MateConfClient *client,
+ guint cnxn_id,
+ MateConfEntry *entry,
+ gpointer user_data)
+{
+ dpi_load (client, user_data);
+}
+
+static void
+dpi_value_changed (GtkSpinButton *spinner,
+ MateConfClient *client)
+{
+ /* Like any time when using a spin button with MateConf, there is
+ * a race condition here. When we change, we send the new
+ * value to MateConf, then restore to the old value until
+ * we get a response to emulate the proper model/view behavior.
+ *
+ * If the user changes the value faster than responses are
+ * received from MateConf, this may cause mildly strange effects.
+ */
+ if (!in_change) {
+ gdouble new_dpi = gtk_spin_button_get_value (spinner);
+
+ mateconf_client_set_float (client, FONT_DPI_KEY, new_dpi, NULL);
+
+ dpi_load (client, spinner);
+ }
+}
+
+static void
+cb_details_response (GtkDialog *dialog, gint response_id)
+{
+ if (response_id == GTK_RESPONSE_HELP) {
+ capplet_help (GTK_WINDOW (dialog),
+ "goscustdesk-38");
+ } else
+ gtk_widget_hide (GTK_WIDGET (dialog));
+}
+
+static void
+cb_show_details (GtkWidget *button,
+ AppearanceData *data)
+{
+ if (!data->font_details) {
+ GtkAdjustment *adjustment;
+ GtkWidget *widget;
+ EnumGroup *group;
+
+ data->font_details = appearance_capplet_get_widget (data, "render_details");
+
+ gtk_window_set_transient_for (GTK_WINDOW (data->font_details),
+ GTK_WINDOW (appearance_capplet_get_widget (data, "appearance_window")));
+
+ widget = appearance_capplet_get_widget (data, "dpi_spinner");
+
+ /* pick a sensible maximum dpi */
+ adjustment = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (widget));
+ gtk_adjustment_set_lower (adjustment, DPI_LOW_REASONABLE_VALUE);
+ gtk_adjustment_set_upper (adjustment, DPI_HIGH_REASONABLE_VALUE);
+ gtk_adjustment_set_step_increment (adjustment, 1);
+
+ dpi_load (data->client, GTK_SPIN_BUTTON (widget));
+ g_signal_connect (widget, "value_changed",
+ G_CALLBACK (dpi_value_changed), data->client);
+
+ mateconf_client_notify_add (data->client, FONT_DPI_KEY,
+ dpi_changed, widget, NULL, NULL);
+
+ setup_font_sample (appearance_capplet_get_widget (data, "antialias_none_sample"), ANTIALIAS_NONE, HINT_FULL);
+ setup_font_sample (appearance_capplet_get_widget (data, "antialias_grayscale_sample"), ANTIALIAS_GRAYSCALE, HINT_FULL);
+ setup_font_sample (appearance_capplet_get_widget (data, "antialias_subpixel_sample"), ANTIALIAS_RGBA, HINT_FULL);
+
+ group = enum_group_create (
+ FONT_ANTIALIASING_KEY, antialias_enums, ANTIALIAS_GRAYSCALE,
+ appearance_capplet_get_widget (data, "antialias_none_radio"), ANTIALIAS_NONE,
+ appearance_capplet_get_widget (data, "antialias_grayscale_radio"), ANTIALIAS_GRAYSCALE,
+ appearance_capplet_get_widget (data, "antialias_subpixel_radio"), ANTIALIAS_RGBA,
+ NULL);
+ data->font_groups = g_slist_prepend (data->font_groups, group);
+
+ setup_font_sample (appearance_capplet_get_widget (data, "hint_none_sample"), ANTIALIAS_GRAYSCALE, HINT_NONE);
+ setup_font_sample (appearance_capplet_get_widget (data, "hint_slight_sample"), ANTIALIAS_GRAYSCALE, HINT_SLIGHT);
+ setup_font_sample (appearance_capplet_get_widget (data, "hint_medium_sample"), ANTIALIAS_GRAYSCALE, HINT_MEDIUM);
+ setup_font_sample (appearance_capplet_get_widget (data, "hint_full_sample"), ANTIALIAS_GRAYSCALE, HINT_FULL);
+
+ group = enum_group_create (FONT_HINTING_KEY, hint_enums, HINT_FULL,
+ appearance_capplet_get_widget (data, "hint_none_radio"), HINT_NONE,
+ appearance_capplet_get_widget (data, "hint_slight_radio"), HINT_SLIGHT,
+ appearance_capplet_get_widget (data, "hint_medium_radio"), HINT_MEDIUM,
+ appearance_capplet_get_widget (data, "hint_full_radio"), HINT_FULL,
+ NULL);
+ data->font_groups = g_slist_prepend (data->font_groups, group);
+
+ gtk_image_set_from_file (GTK_IMAGE (appearance_capplet_get_widget (data, "subpixel_rgb_image")),
+ MATECC_PIXMAP_DIR "/subpixel-rgb.png");
+ gtk_image_set_from_file (GTK_IMAGE (appearance_capplet_get_widget (data, "subpixel_bgr_image")),
+ MATECC_PIXMAP_DIR "/subpixel-bgr.png");
+ gtk_image_set_from_file (GTK_IMAGE (appearance_capplet_get_widget (data, "subpixel_vrgb_image")),
+ MATECC_PIXMAP_DIR "/subpixel-vrgb.png");
+ gtk_image_set_from_file (GTK_IMAGE (appearance_capplet_get_widget (data, "subpixel_vbgr_image")),
+ MATECC_PIXMAP_DIR "/subpixel-vbgr.png");
+
+ group = enum_group_create (FONT_RGBA_ORDER_KEY, rgba_order_enums, RGBA_RGB,
+ appearance_capplet_get_widget (data, "subpixel_rgb_radio"), RGBA_RGB,
+ appearance_capplet_get_widget (data, "subpixel_bgr_radio"), RGBA_BGR,
+ appearance_capplet_get_widget (data, "subpixel_vrgb_radio"), RGBA_VRGB,
+ appearance_capplet_get_widget (data, "subpixel_vbgr_radio"), RGBA_VBGR,
+ NULL);
+ data->font_groups = g_slist_prepend (data->font_groups, group);
+
+ g_signal_connect (G_OBJECT (data->font_details),
+ "response",
+ G_CALLBACK (cb_details_response), NULL);
+ g_signal_connect (G_OBJECT (data->font_details),
+ "delete_event",
+ G_CALLBACK (gtk_true), NULL);
+ }
+
+ gtk_window_present (GTK_WINDOW (data->font_details));
+}
+#endif /* HAVE_XFT2 */
+
+void font_init(AppearanceData* data)
+{
+ GObject* peditor;
+ GtkWidget* widget;
+
+ data->font_details = NULL;
+ data->font_groups = NULL;
+
+ mateconf_client_add_dir(data->client, "/desktop/mate/interface", MATECONF_CLIENT_PRELOAD_ONELEVEL, NULL);
+ mateconf_client_add_dir(data->client, "/apps/caja/preferences", MATECONF_CLIENT_PRELOAD_ONELEVEL, NULL);
+ mateconf_client_add_dir(data->client, MARCO_DIR, MATECONF_CLIENT_PRELOAD_ONELEVEL, NULL);
+
+ #ifdef HAVE_XFT2
+ mateconf_client_add_dir(data->client, FONT_RENDER_DIR, MATECONF_CLIENT_PRELOAD_ONELEVEL, NULL);
+ #endif /* HAVE_XFT2 */
+
+ widget = appearance_capplet_get_widget(data, "application_font");
+ peditor = mateconf_peditor_new_font(NULL, GTK_FONT_KEY, widget, "conv-from-widget-cb", application_font_to_mateconf, NULL);
+ g_signal_connect_swapped(peditor, "value-changed", G_CALLBACK (application_font_changed), widget);
+ application_font_changed(widget);
+
+ peditor = mateconf_peditor_new_font(NULL, DOCUMENT_FONT_KEY, appearance_capplet_get_widget (data, "document_font"), NULL);
+
+ peditor = mateconf_peditor_new_font(NULL, DESKTOP_FONT_KEY, appearance_capplet_get_widget (data, "desktop_font"), NULL);
+
+ peditor = mateconf_peditor_new_font(NULL, WINDOW_TITLE_FONT_KEY, appearance_capplet_get_widget (data, "window_title_font"), NULL);
+
+ peditor = mateconf_peditor_new_font(NULL, MONOSPACE_FONT_KEY, appearance_capplet_get_widget (data, "monospace_font"), NULL);
+
+ mateconf_client_notify_add (data->client, WINDOW_TITLE_USES_SYSTEM_KEY, marco_changed, data, NULL, NULL);
+
+ marco_titlebar_load_sensitivity(data);
+
+ #ifdef HAVE_XFT2
+ setup_font_pair(appearance_capplet_get_widget(data, "monochrome_radio"), appearance_capplet_get_widget (data, "monochrome_sample"), ANTIALIAS_NONE, HINT_FULL);
+ setup_font_pair(appearance_capplet_get_widget(data, "best_shapes_radio"), appearance_capplet_get_widget (data, "best_shapes_sample"), ANTIALIAS_GRAYSCALE, HINT_MEDIUM);
+ setup_font_pair(appearance_capplet_get_widget(data, "best_contrast_radio"), appearance_capplet_get_widget (data, "best_contrast_sample"), ANTIALIAS_GRAYSCALE, HINT_FULL);
+ setup_font_pair(appearance_capplet_get_widget(data, "subpixel_radio"), appearance_capplet_get_widget (data, "subpixel_sample"), ANTIALIAS_RGBA, HINT_FULL);
+
+ font_render_load (data->client);
+
+ mateconf_client_notify_add (data->client, FONT_RENDER_DIR, font_render_changed, data->client, NULL, NULL);
+
+ g_signal_connect (appearance_capplet_get_widget (data, "details_button"), "clicked", G_CALLBACK (cb_show_details), data);
+ #else /* !HAVE_XFT2 */
+ gtk_widget_hide (appearance_capplet_get_widget (data, "font_render_frame"));
+ #endif /* HAVE_XFT2 */
+}
+
+void font_shutdown(AppearanceData* data)
+{
+ g_slist_foreach(data->font_groups, (GFunc) enum_group_destroy, NULL);
+ g_slist_free(data->font_groups);
+ g_slist_foreach(font_pairs, (GFunc) g_free, NULL);
+ g_slist_free(font_pairs);
+ g_free(old_font);
+}
diff --git a/capplets/appearance/appearance-font.h b/capplets/appearance/appearance-font.h
new file mode 100644
index 00000000..995aa328
--- /dev/null
+++ b/capplets/appearance/appearance-font.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2007 The GNOME Foundation
+ * Written by Jens Granseuer <[email protected]>
+ * All Rights Reserved
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+void font_init(AppearanceData* data);
+void font_shutdown(AppearanceData* data);
diff --git a/capplets/appearance/appearance-main.c b/capplets/appearance/appearance-main.c
new file mode 100644
index 00000000..a7995105
--- /dev/null
+++ b/capplets/appearance/appearance-main.c
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2007 The MATE Foundation
+ * Written by Thomas Wood <[email protected]>
+ * All Rights Reserved
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <glib/gi18n.h>
+#include "appearance.h"
+#include "appearance-desktop.h"
+#include "appearance-font.h"
+#include "appearance-themes.h"
+#include "appearance-style.h"
+#include "theme-installer.h"
+#include "theme-thumbnail.h"
+#include "activate-settings-daemon.h"
+#include "capplet-util.h"
+
+static AppearanceData *
+init_appearance_data (int *argc, char ***argv, GOptionContext *context)
+{
+ AppearanceData *data = NULL;
+ gchar *uifile;
+ GtkBuilder *ui;
+ GError *err = NULL;
+
+ g_thread_init (NULL);
+ gdk_threads_init ();
+ gdk_threads_enter ();
+ theme_thumbnail_factory_init (*argc, *argv);
+ capplet_init (context, argc, argv);
+ activate_settings_daemon ();
+
+ /* set up the data */
+ uifile = g_build_filename (MATECC_GTKBUILDER_DIR, "appearance.ui",
+ NULL);
+ ui = gtk_builder_new ();
+ gtk_builder_add_from_file (ui, uifile, &err);
+ g_free (uifile);
+
+ if (err)
+ {
+ g_warning (_("Could not load user interface file: %s"), err->message);
+ g_error_free (err);
+ g_object_unref (ui);
+ }
+ else
+ {
+ data = g_new (AppearanceData, 1);
+ data->client = mateconf_client_get_default ();
+ data->ui = ui;
+ data->thumb_factory = mate_desktop_thumbnail_factory_new (MATE_DESKTOP_THUMBNAIL_SIZE_NORMAL);
+ }
+
+ return data;
+}
+
+static void
+main_window_response (GtkWidget *widget,
+ gint response_id,
+ AppearanceData *data)
+{
+ if (response_id == GTK_RESPONSE_CLOSE ||
+ response_id == GTK_RESPONSE_DELETE_EVENT)
+ {
+ gtk_main_quit ();
+
+ themes_shutdown (data);
+ style_shutdown (data);
+ desktop_shutdown (data);
+ font_shutdown (data);
+
+ g_object_unref (data->thumb_factory);
+ g_object_unref (data->client);
+ g_object_unref (data->ui);
+ }
+ else if (response_id == GTK_RESPONSE_HELP)
+ {
+ GtkNotebook *nb;
+ gint pindex;
+
+ nb = GTK_NOTEBOOK (appearance_capplet_get_widget (data, "main_notebook"));
+ pindex = gtk_notebook_get_current_page (nb);
+
+ switch (pindex)
+ {
+ case 0: /* theme */
+ capplet_help (GTK_WINDOW (widget), "goscustdesk-12");
+ break;
+ case 1: /* background */
+ capplet_help (GTK_WINDOW (widget), "goscustdesk-7");
+ break;
+ case 2: /* fonts */
+ capplet_help (GTK_WINDOW (widget), "goscustdesk-38");
+ break;
+ case 3: /* interface */
+ capplet_help (GTK_WINDOW (widget), "goscustuserinter-2");
+ break;
+ default:
+ capplet_help (GTK_WINDOW (widget), "prefs-look-and-feel");
+ break;
+ }
+ }
+}
+
+int
+main (int argc, char **argv)
+{
+ AppearanceData *data;
+ GtkWidget *w;
+
+ gchar *install_filename = NULL;
+ gchar *start_page = NULL;
+ gchar **wallpaper_files = NULL;
+ GOptionContext *option_context;
+ GOptionEntry option_entries[] = {
+ { "install-theme",
+ 'i',
+ G_OPTION_FLAG_IN_MAIN,
+ G_OPTION_ARG_FILENAME,
+ &install_filename,
+ N_("Specify the filename of a theme to install"),
+ N_("filename") },
+ { "show-page",
+ 'p',
+ G_OPTION_FLAG_IN_MAIN,
+ G_OPTION_ARG_STRING,
+ &start_page,
+ /* TRANSLATORS: don't translate the terms in brackets */
+ N_("Specify the name of the page to show (theme|background|fonts|interface)"),
+ N_("page") },
+ { G_OPTION_REMAINING,
+ 0,
+ G_OPTION_FLAG_IN_MAIN,
+ G_OPTION_ARG_FILENAME_ARRAY,
+ &wallpaper_files,
+ NULL,
+ N_("[WALLPAPER...]") },
+ { NULL }
+ };
+
+ option_context = g_option_context_new (NULL);
+ g_option_context_add_main_entries (option_context, option_entries, GETTEXT_PACKAGE);
+
+ /* init */
+ data = init_appearance_data (&argc, &argv, option_context);
+ if (!data)
+ return 1;
+
+ /* init tabs */
+ themes_init (data);
+ style_init (data);
+ desktop_init (data, (const gchar **) wallpaper_files);
+ g_strfreev (wallpaper_files);
+ font_init (data);
+
+ /* prepare the main window */
+ w = appearance_capplet_get_widget (data, "appearance_window");
+ capplet_set_icon (w, "preferences-desktop-theme");
+ gtk_widget_show_all (w);
+
+ g_signal_connect_after (w, "response",
+ (GCallback) main_window_response, data);
+
+ /* default to background page if files were given on the command line */
+ if (wallpaper_files && !install_filename && !start_page)
+ start_page = g_strdup ("background");
+
+ if (start_page != NULL) {
+ gchar *page_name;
+
+ page_name = g_strconcat (start_page, "_vbox", NULL);
+ g_free (start_page);
+
+ w = appearance_capplet_get_widget (data, page_name);
+ if (w != NULL) {
+ GtkNotebook *nb;
+ gint pindex;
+
+ nb = GTK_NOTEBOOK (appearance_capplet_get_widget (data, "main_notebook"));
+ pindex = gtk_notebook_page_num (nb, w);
+ if (pindex != -1)
+ gtk_notebook_set_current_page (nb, pindex);
+ }
+ g_free (page_name);
+ }
+
+ if (install_filename != NULL) {
+ GFile *inst = g_file_new_for_commandline_arg (install_filename);
+ g_free (install_filename);
+ mate_theme_install (inst, GTK_WINDOW (w));
+ g_object_unref (inst);
+ }
+
+ g_option_context_free (option_context);
+
+ /* start the mainloop */
+ gtk_main ();
+ gdk_threads_leave ();
+
+ /* free stuff */
+ g_free (data);
+
+ return 0;
+}
diff --git a/capplets/appearance/appearance-style.c b/capplets/appearance/appearance-style.c
new file mode 100644
index 00000000..21612248
--- /dev/null
+++ b/capplets/appearance/appearance-style.c
@@ -0,0 +1,1073 @@
+/*
+ * Copyright (C) 2007, 2010 The MATE Foundation
+ * Written by Thomas Wood <[email protected]>
+ * All Rights Reserved
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include "appearance.h"
+
+#include <string.h>
+#include <pango/pango.h>
+#include <glib/gi18n.h>
+
+#include "theme-util.h"
+#include "gtkrc-utils.h"
+#include "mateconf-property-editor.h"
+#include "theme-thumbnail.h"
+#include "capplet-util.h"
+
+typedef void (* ThumbnailGenFunc) (void *type,
+ ThemeThumbnailFunc theme,
+ AppearanceData *data,
+ GDestroyNotify *destroy);
+
+typedef struct {
+ AppearanceData *data;
+ GdkPixbuf *thumbnail;
+} PEditorConvData;
+
+static void update_message_area (AppearanceData *data);
+static void create_thumbnail (const gchar *name, GdkPixbuf *default_thumb, AppearanceData *data);
+
+static const gchar *symbolic_names[NUM_SYMBOLIC_COLORS] = {
+ "fg_color", "bg_color",
+ "text_color", "base_color",
+ "selected_fg_color", "selected_bg_color",
+ "tooltip_fg_color", "tooltip_bg_color"
+};
+
+static gchar *
+find_string_in_model (GtkTreeModel *model, const gchar *value, gint column)
+{
+ GtkTreeIter iter;
+ gboolean valid;
+ gchar *path = NULL, *test;
+
+ if (!value)
+ return NULL;
+
+ for (valid = gtk_tree_model_get_iter_first (model, &iter); valid;
+ valid = gtk_tree_model_iter_next (model, &iter))
+ {
+ gtk_tree_model_get (model, &iter, column, &test, -1);
+
+ if (test)
+ {
+ gint cmp = strcmp (test, value);
+ g_free (test);
+
+ if (!cmp)
+ {
+ path = gtk_tree_model_get_string_from_iter (model, &iter);
+ break;
+ }
+ }
+ }
+
+ return path;
+}
+
+static MateConfValue *
+conv_to_widget_cb (MateConfPropertyEditor *peditor, const MateConfValue *value)
+{
+ GtkTreeModel *store;
+ GtkTreeView *list;
+ const gchar *curr_value;
+ MateConfValue *new_value;
+ gchar *path;
+
+ /* find value in model */
+ curr_value = mateconf_value_get_string (value);
+ list = GTK_TREE_VIEW (mateconf_property_editor_get_ui_control (peditor));
+ store = gtk_tree_view_get_model (list);
+
+ path = find_string_in_model (store, curr_value, COL_NAME);
+
+ /* Add a temporary item if we can't find a match
+ * TODO: delete this item if it is no longer selected?
+ */
+ if (!path)
+ {
+ GtkListStore *list_store;
+ GtkTreeIter iter, sort_iter;
+ PEditorConvData *conv;
+
+ list_store = GTK_LIST_STORE (gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (store)));
+
+ g_object_get (peditor, "data", &conv, NULL);
+ gtk_list_store_insert_with_values (list_store, &iter, 0,
+ COL_LABEL, curr_value,
+ COL_NAME, curr_value,
+ COL_THUMBNAIL, conv->thumbnail,
+ -1);
+ /* convert the tree store iter for use with the sort model */
+ gtk_tree_model_sort_convert_child_iter_to_iter (GTK_TREE_MODEL_SORT (store),
+ &sort_iter, &iter);
+ path = gtk_tree_model_get_string_from_iter (store, &sort_iter);
+
+ create_thumbnail (curr_value, conv->thumbnail, conv->data);
+ }
+
+ new_value = mateconf_value_new (MATECONF_VALUE_STRING);
+ mateconf_value_set_string (new_value, path);
+ g_free (path);
+
+ return new_value;
+}
+
+static MateConfValue *
+conv_from_widget_cb (MateConfPropertyEditor *peditor, const MateConfValue *value)
+{
+ MateConfValue *new_value = NULL;
+ GtkTreeIter iter;
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ GtkTreeView *list;
+
+ list = GTK_TREE_VIEW (mateconf_property_editor_get_ui_control (peditor));
+ selection = gtk_tree_view_get_selection (list);
+
+ if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
+ gchar *list_value;
+
+ gtk_tree_model_get (model, &iter, COL_NAME, &list_value, -1);
+
+ if (list_value) {
+ new_value = mateconf_value_new (MATECONF_VALUE_STRING);
+ mateconf_value_set_string (new_value, list_value);
+ g_free (list_value);
+ }
+ }
+
+ return new_value;
+}
+
+static gint
+cursor_theme_sort_func (GtkTreeModel *model,
+ GtkTreeIter *a,
+ GtkTreeIter *b,
+ gpointer user_data)
+{
+ gchar *a_label = NULL;
+ gchar *b_label = NULL;
+ const gchar *default_label;
+ gint result;
+
+ gtk_tree_model_get (model, a, COL_LABEL, &a_label, -1);
+ gtk_tree_model_get (model, b, COL_LABEL, &b_label, -1);
+
+ default_label = _("Default Pointer");
+
+ if (!strcmp (a_label, default_label))
+ result = -1;
+ else if (!strcmp (b_label, default_label))
+ result = 1;
+ else
+ result = strcmp (a_label, b_label);
+
+ g_free (a_label);
+ g_free (b_label);
+
+ return result;
+}
+
+static void
+style_message_area_response_cb (GtkWidget *w,
+ gint response_id,
+ AppearanceData *data)
+{
+ GtkSettings *settings = gtk_settings_get_default ();
+ gchar *theme;
+ gchar *engine_path;
+
+ g_object_get (settings, "gtk-theme-name", &theme, NULL);
+ engine_path = gtk_theme_info_missing_engine (theme, FALSE);
+ g_free (theme);
+
+ if (engine_path != NULL) {
+ theme_install_file (GTK_WINDOW (gtk_widget_get_toplevel (data->style_message_area)),
+ engine_path);
+ g_free (engine_path);
+ }
+ update_message_area (data);
+}
+
+static void update_message_area(AppearanceData* data)
+{
+ GtkSettings* settings = gtk_settings_get_default();
+ gchar* theme = NULL;
+ gchar* engine;
+
+ g_object_get(settings, "gtk-theme-name", &theme, NULL);
+ engine = gtk_theme_info_missing_engine(theme, TRUE);
+ g_free(theme);
+
+ if (data->style_message_area == NULL)
+ {
+ GtkWidget* hbox;
+ GtkWidget* parent;
+ GtkWidget* icon;
+ GtkWidget* content;
+
+ if (engine == NULL)
+ {
+ return;
+ }
+
+ data->style_message_area = gtk_info_bar_new ();
+
+ g_signal_connect (data->style_message_area, "response", (GCallback) style_message_area_response_cb, data);
+
+ data->style_install_button = gtk_info_bar_add_button(GTK_INFO_BAR (data->style_message_area), _("Install"), GTK_RESPONSE_APPLY);
+
+ data->style_message_label = gtk_label_new (NULL);
+ gtk_label_set_line_wrap (GTK_LABEL (data->style_message_label), TRUE);
+ gtk_misc_set_alignment (GTK_MISC (data->style_message_label), 0.0, 0.5);
+
+ hbox = gtk_hbox_new (FALSE, 9);
+ icon = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_DIALOG);
+ gtk_misc_set_alignment (GTK_MISC (icon), 0.5, 0);
+ gtk_box_pack_start (GTK_BOX (hbox), icon, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (hbox), data->style_message_label, TRUE, TRUE, 0);
+ content = gtk_info_bar_get_content_area (GTK_INFO_BAR (data->style_message_area));
+ gtk_container_add (GTK_CONTAINER (content), hbox);
+ gtk_widget_show_all (data->style_message_area);
+ gtk_widget_set_no_show_all (data->style_message_area, TRUE);
+
+ parent = appearance_capplet_get_widget (data, "gtk_themes_vbox");
+ gtk_box_pack_start (GTK_BOX (parent), data->style_message_area, FALSE, FALSE, 0);
+ }
+
+ if (engine != NULL)
+ {
+ gchar* message = g_strdup_printf(_("This theme will not look as intended because the required GTK+ theme engine '%s' is not installed."), engine);
+ gtk_label_set_text(GTK_LABEL(data->style_message_label), message);
+ g_free(message);
+ g_free(engine);
+
+ if (packagekit_available())
+ {
+ gtk_widget_show(data->style_install_button);
+ }
+ else
+ {
+ gtk_widget_hide(data->style_install_button);
+ }
+
+ gtk_widget_show(data->style_message_area);
+ gtk_widget_queue_draw(data->style_message_area);
+ }
+ else
+ {
+ gtk_widget_hide(data->style_message_area);
+ }
+}
+
+static void
+update_color_buttons_from_string (const gchar *color_scheme, AppearanceData *data)
+{
+ GdkColor colors[NUM_SYMBOLIC_COLORS];
+ GtkWidget *widget;
+ gint i;
+
+ if (!mate_theme_color_scheme_parse (color_scheme, colors))
+ return;
+
+ /* now set all the buttons to the correct settings */
+ for (i = 0; i < NUM_SYMBOLIC_COLORS; ++i) {
+ widget = appearance_capplet_get_widget (data, symbolic_names[i]);
+ gtk_color_button_set_color (GTK_COLOR_BUTTON (widget), &colors[i]);
+ }
+}
+
+static void
+update_color_buttons_from_settings (GtkSettings *settings,
+ AppearanceData *data)
+{
+ gchar *scheme, *setting;
+
+ scheme = mateconf_client_get_string (data->client, COLOR_SCHEME_KEY, NULL);
+ g_object_get (settings, "gtk-color-scheme", &setting, NULL);
+
+ if (scheme == NULL || strcmp (scheme, "") == 0)
+ gtk_widget_set_sensitive (appearance_capplet_get_widget (data, "color_scheme_defaults_button"), FALSE);
+
+ g_free (scheme);
+ update_color_buttons_from_string (setting, data);
+ g_free (setting);
+}
+
+static void
+color_scheme_changed (GObject *settings,
+ GParamSpec *pspec,
+ AppearanceData *data)
+{
+ update_color_buttons_from_settings (GTK_SETTINGS (settings), data);
+}
+
+static void
+check_color_schemes_enabled (GtkSettings *settings,
+ AppearanceData *data)
+{
+ gchar *theme = NULL;
+ gchar *filename;
+ GSList *symbolic_colors = NULL;
+ gboolean enable_colors = FALSE;
+ gint i;
+
+ g_object_get (settings, "gtk-theme-name", &theme, NULL);
+ filename = gtkrc_find_named (theme);
+ g_free (theme);
+
+ gtkrc_get_details (filename, NULL, &symbolic_colors);
+ g_free (filename);
+
+ for (i = 0; i < NUM_SYMBOLIC_COLORS; ++i) {
+ gboolean found;
+
+ found = (g_slist_find_custom (symbolic_colors, symbolic_names[i], (GCompareFunc) strcmp) != NULL);
+ gtk_widget_set_sensitive (appearance_capplet_get_widget (data, symbolic_names[i]), found);
+
+ enable_colors |= found;
+ }
+
+ g_slist_foreach (symbolic_colors, (GFunc) g_free, NULL);
+ g_slist_free (symbolic_colors);
+
+ gtk_widget_set_sensitive (appearance_capplet_get_widget (data, "color_scheme_table"), enable_colors);
+ gtk_widget_set_sensitive (appearance_capplet_get_widget (data, "color_scheme_defaults_button"), enable_colors);
+
+ if (enable_colors)
+ gtk_widget_hide (appearance_capplet_get_widget (data, "color_scheme_message_hbox"));
+ else
+ gtk_widget_show (appearance_capplet_get_widget (data, "color_scheme_message_hbox"));
+}
+
+static void
+color_button_clicked_cb (GtkWidget *colorbutton, AppearanceData *data)
+{
+ GtkWidget *widget;
+ GdkColor color;
+ GString *scheme = g_string_new (NULL);
+ gchar *colstr;
+ gchar *old_scheme = NULL;
+ gint i;
+
+ for (i = 0; i < NUM_SYMBOLIC_COLORS; ++i) {
+ widget = appearance_capplet_get_widget (data, symbolic_names[i]);
+ gtk_color_button_get_color (GTK_COLOR_BUTTON (widget), &color);
+
+ colstr = gdk_color_to_string (&color);
+ g_string_append_printf (scheme, "%s:%s\n", symbolic_names[i], colstr);
+ g_free (colstr);
+ }
+ /* remove the last newline */
+ g_string_truncate (scheme, scheme->len - 1);
+
+ /* verify that the scheme really has changed */
+ g_object_get (gtk_settings_get_default (), "gtk-color-scheme", &old_scheme, NULL);
+
+ if (!mate_theme_color_scheme_equal (old_scheme, scheme->str)) {
+ mateconf_client_set_string (data->client, COLOR_SCHEME_KEY, scheme->str, NULL);
+
+ gtk_widget_set_sensitive (appearance_capplet_get_widget (data, "color_scheme_defaults_button"), TRUE);
+ }
+ g_free (old_scheme);
+ g_string_free (scheme, TRUE);
+}
+
+static void
+color_scheme_defaults_button_clicked_cb (GtkWidget *button, AppearanceData *data)
+{
+ mateconf_client_unset (data->client, COLOR_SCHEME_KEY, NULL);
+ gtk_widget_set_sensitive (appearance_capplet_get_widget (data, "color_scheme_defaults_button"), FALSE);
+}
+
+static void
+style_response_cb (GtkDialog *dialog, gint response_id)
+{
+ if (response_id == GTK_RESPONSE_HELP) {
+ capplet_help (GTK_WINDOW (dialog), "goscustdesk-61");
+ } else {
+ gtk_widget_hide (GTK_WIDGET (dialog));
+ }
+}
+
+static void
+gtk_theme_changed (MateConfPropertyEditor *peditor,
+ const gchar *key,
+ const MateConfValue *value,
+ AppearanceData *data)
+{
+ MateThemeInfo *theme = NULL;
+ const gchar *name;
+ GtkSettings *settings = gtk_settings_get_default ();
+
+ if (value && (name = mateconf_value_get_string (value))) {
+ gchar *current;
+
+ theme = mate_theme_info_find (name);
+
+ /* Manually update GtkSettings to new gtk+ theme.
+ * This will eventually happen anyway, but we need the
+ * info for the color scheme updates already. */
+ g_object_get (settings, "gtk-theme-name", &current, NULL);
+
+ if (strcmp (current, name) != 0) {
+ g_object_set (settings, "gtk-theme-name", name, NULL);
+ update_message_area (data);
+ }
+
+ g_free (current);
+
+ check_color_schemes_enabled (settings, data);
+ update_color_buttons_from_settings (settings, data);
+ }
+
+ gtk_widget_set_sensitive (appearance_capplet_get_widget (data, "gtk_themes_delete"),
+ theme_is_writable (theme));
+}
+
+static void
+window_theme_changed (MateConfPropertyEditor *peditor,
+ const gchar *key,
+ const MateConfValue *value,
+ AppearanceData *data)
+{
+ MateThemeInfo *theme = NULL;
+ const gchar *name;
+
+ if (value && (name = mateconf_value_get_string (value)))
+ theme = mate_theme_info_find (name);
+
+ gtk_widget_set_sensitive (appearance_capplet_get_widget (data, "window_themes_delete"),
+ theme_is_writable (theme));
+}
+
+static void
+icon_theme_changed (MateConfPropertyEditor *peditor,
+ const gchar *key,
+ const MateConfValue *value,
+ AppearanceData *data)
+{
+ MateThemeIconInfo *theme = NULL;
+ const gchar *name;
+
+ if (value && (name = mateconf_value_get_string (value)))
+ theme = mate_theme_icon_info_find (name);
+
+ gtk_widget_set_sensitive (appearance_capplet_get_widget (data, "icon_themes_delete"),
+ theme_is_writable (theme));
+}
+
+#ifdef HAVE_XCURSOR
+static void
+cursor_size_changed_cb (int size, AppearanceData *data)
+{
+ mateconf_client_set_int (data->client, CURSOR_SIZE_KEY, size, NULL);
+}
+
+static void
+cursor_size_scale_value_changed_cb (GtkRange *range, AppearanceData *data)
+{
+ MateThemeCursorInfo *theme;
+ gchar *name;
+
+ name = mateconf_client_get_string (data->client, CURSOR_THEME_KEY, NULL);
+ if (name == NULL)
+ return;
+
+ theme = mate_theme_cursor_info_find (name);
+ g_free (name);
+
+ if (theme) {
+ gint size;
+
+ size = g_array_index (theme->sizes, gint, (int) gtk_range_get_value (range));
+ cursor_size_changed_cb (size, data);
+ }
+}
+#endif
+
+static void
+update_cursor_size_scale (MateThemeCursorInfo *theme,
+ AppearanceData *data)
+{
+#ifdef HAVE_XCURSOR
+ GtkWidget *cursor_size_scale;
+ GtkWidget *cursor_size_label;
+ GtkWidget *cursor_size_small_label;
+ GtkWidget *cursor_size_large_label;
+ gboolean sensitive;
+ gint size, mateconf_size;
+
+ cursor_size_scale = appearance_capplet_get_widget (data, "cursor_size_scale");
+ cursor_size_label = appearance_capplet_get_widget (data, "cursor_size_label");
+ cursor_size_small_label = appearance_capplet_get_widget (data, "cursor_size_small_label");
+ cursor_size_large_label = appearance_capplet_get_widget (data, "cursor_size_large_label");
+
+ sensitive = theme && theme->sizes->len > 1;
+ gtk_widget_set_sensitive (cursor_size_scale, sensitive);
+ gtk_widget_set_sensitive (cursor_size_label, sensitive);
+ gtk_widget_set_sensitive (cursor_size_small_label, sensitive);
+ gtk_widget_set_sensitive (cursor_size_large_label, sensitive);
+
+ mateconf_size = mateconf_client_get_int (data->client, CURSOR_SIZE_KEY, NULL);
+
+ if (sensitive) {
+ GtkAdjustment *adjustment;
+ gint i, index;
+ GtkRange *range = GTK_RANGE (cursor_size_scale);
+
+ adjustment = gtk_range_get_adjustment (range);
+ g_object_set (adjustment, "upper", (gdouble) theme->sizes->len - 1, NULL);
+
+
+ /* fallback if the mateconf value is bigger than all available sizes;
+ use the largest we have */
+ index = theme->sizes->len - 1;
+
+ /* set the slider to the cursor size which matches the mateconf setting best */
+ for (i = 0; i < theme->sizes->len; i++) {
+ size = g_array_index (theme->sizes, gint, i);
+
+ if (size == mateconf_size) {
+ index = i;
+ break;
+ } else if (size > mateconf_size) {
+ if (i == 0) {
+ index = 0;
+ } else {
+ gint diff, diff_to_last;
+
+ diff = size - mateconf_size;
+ diff_to_last = mateconf_size - g_array_index (theme->sizes, gint, i - 1);
+
+ index = (diff < diff_to_last) ? i : i - 1;
+ }
+ break;
+ }
+ }
+
+ gtk_range_set_value (range, (gdouble) index);
+
+ size = g_array_index (theme->sizes, gint, index);
+ } else {
+ if (theme && theme->sizes->len > 0)
+ size = g_array_index (theme->sizes, gint, 0);
+ else
+ size = 18;
+ }
+
+ if (size != mateconf_size)
+ cursor_size_changed_cb (size, data);
+#endif
+}
+
+static void
+cursor_theme_changed (MateConfPropertyEditor *peditor,
+ const gchar *key,
+ const MateConfValue *value,
+ AppearanceData *data)
+{
+ MateThemeCursorInfo *theme = NULL;
+ const gchar *name;
+
+ if (value && (name = mateconf_value_get_string (value)))
+ theme = mate_theme_cursor_info_find (name);
+
+ update_cursor_size_scale (theme, data);
+
+ gtk_widget_set_sensitive (appearance_capplet_get_widget (data, "cursor_themes_delete"),
+ theme_is_writable (theme));
+
+}
+
+static void
+generic_theme_delete (const gchar *tv_name, ThemeType type, AppearanceData *data)
+{
+ GtkTreeView *treeview = GTK_TREE_VIEW (appearance_capplet_get_widget (data, tv_name));
+ GtkTreeSelection *selection = gtk_tree_view_get_selection (treeview);
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+
+ if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
+ gchar *name;
+
+ gtk_tree_model_get (model, &iter, COL_NAME, &name, -1);
+
+ if (name != NULL && theme_delete (name, type)) {
+ /* remove theme from the model, too */
+ GtkTreeIter child;
+ GtkTreePath *path;
+
+ path = gtk_tree_model_get_path (model, &iter);
+ gtk_tree_model_sort_convert_iter_to_child_iter (
+ GTK_TREE_MODEL_SORT (model), &child, &iter);
+ gtk_list_store_remove (GTK_LIST_STORE (
+ gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (model))), &child);
+
+ if (gtk_tree_model_get_iter (model, &iter, path) ||
+ theme_model_iter_last (model, &iter)) {
+ gtk_tree_path_free (path);
+ path = gtk_tree_model_get_path (model, &iter);
+ gtk_tree_selection_select_path (selection, path);
+ gtk_tree_view_scroll_to_cell (treeview, path, NULL, FALSE, 0, 0);
+ }
+ gtk_tree_path_free (path);
+ }
+ g_free (name);
+ }
+}
+
+static void
+gtk_theme_delete_cb (GtkWidget *button, AppearanceData *data)
+{
+ generic_theme_delete ("gtk_themes_list", THEME_TYPE_GTK, data);
+}
+
+static void
+window_theme_delete_cb (GtkWidget *button, AppearanceData *data)
+{
+ generic_theme_delete ("window_themes_list", THEME_TYPE_WINDOW, data);
+}
+
+static void
+icon_theme_delete_cb (GtkWidget *button, AppearanceData *data)
+{
+ generic_theme_delete ("icon_themes_list", THEME_TYPE_ICON, data);
+}
+
+static void
+cursor_theme_delete_cb (GtkWidget *button, AppearanceData *data)
+{
+ generic_theme_delete ("cursor_themes_list", THEME_TYPE_CURSOR, data);
+}
+
+static void
+add_to_treeview (const gchar *tv_name,
+ const gchar *theme_name,
+ const gchar *theme_label,
+ GdkPixbuf *theme_thumbnail,
+ AppearanceData *data)
+{
+ GtkTreeView *treeview;
+ GtkListStore *model;
+
+ treeview = GTK_TREE_VIEW (appearance_capplet_get_widget (data, tv_name));
+ model = GTK_LIST_STORE (
+ gtk_tree_model_sort_get_model (
+ GTK_TREE_MODEL_SORT (gtk_tree_view_get_model (treeview))));
+
+ gtk_list_store_insert_with_values (model, NULL, 0,
+ COL_LABEL, theme_label,
+ COL_NAME, theme_name,
+ COL_THUMBNAIL, theme_thumbnail,
+ -1);
+}
+
+static void
+remove_from_treeview (const gchar *tv_name,
+ const gchar *theme_name,
+ AppearanceData *data)
+{
+ GtkTreeView *treeview;
+ GtkListStore *model;
+ GtkTreeIter iter;
+
+ treeview = GTK_TREE_VIEW (appearance_capplet_get_widget (data, tv_name));
+ model = GTK_LIST_STORE (
+ gtk_tree_model_sort_get_model (
+ GTK_TREE_MODEL_SORT (gtk_tree_view_get_model (treeview))));
+
+ if (theme_find_in_model (GTK_TREE_MODEL (model), theme_name, &iter))
+ gtk_list_store_remove (model, &iter);
+}
+
+static void
+update_in_treeview (const gchar *tv_name,
+ const gchar *theme_name,
+ const gchar *theme_label,
+ AppearanceData *data)
+{
+ GtkTreeView *treeview;
+ GtkListStore *model;
+ GtkTreeIter iter;
+
+ treeview = GTK_TREE_VIEW (appearance_capplet_get_widget (data, tv_name));
+ model = GTK_LIST_STORE (
+ gtk_tree_model_sort_get_model (
+ GTK_TREE_MODEL_SORT (gtk_tree_view_get_model (treeview))));
+
+ if (theme_find_in_model (GTK_TREE_MODEL (model), theme_name, &iter)) {
+ gtk_list_store_set (model, &iter,
+ COL_LABEL, theme_label,
+ COL_NAME, theme_name,
+ -1);
+ }
+}
+
+static void
+update_thumbnail_in_treeview (const gchar *tv_name,
+ const gchar *theme_name,
+ GdkPixbuf *theme_thumbnail,
+ AppearanceData *data)
+{
+ GtkTreeView *treeview;
+ GtkListStore *model;
+ GtkTreeIter iter;
+
+ if (theme_thumbnail == NULL)
+ return;
+
+ treeview = GTK_TREE_VIEW (appearance_capplet_get_widget (data, tv_name));
+ model = GTK_LIST_STORE (
+ gtk_tree_model_sort_get_model (
+ GTK_TREE_MODEL_SORT (gtk_tree_view_get_model (treeview))));
+
+ if (theme_find_in_model (GTK_TREE_MODEL (model), theme_name, &iter)) {
+ gtk_list_store_set (model, &iter,
+ COL_THUMBNAIL, theme_thumbnail,
+ -1);
+ }
+}
+
+static void
+gtk_theme_thumbnail_cb (GdkPixbuf *pixbuf,
+ gchar *theme_name,
+ AppearanceData *data)
+{
+ update_thumbnail_in_treeview ("gtk_themes_list", theme_name, pixbuf, data);
+}
+
+static void
+marco_theme_thumbnail_cb (GdkPixbuf *pixbuf,
+ gchar *theme_name,
+ AppearanceData *data)
+{
+ update_thumbnail_in_treeview ("window_themes_list", theme_name, pixbuf, data);
+}
+
+static void
+icon_theme_thumbnail_cb (GdkPixbuf *pixbuf,
+ gchar *theme_name,
+ AppearanceData *data)
+{
+ update_thumbnail_in_treeview ("icon_themes_list", theme_name, pixbuf, data);
+}
+
+static void
+create_thumbnail (const gchar *name, GdkPixbuf *default_thumb, AppearanceData *data)
+{
+ if (default_thumb == data->icon_theme_icon) {
+ MateThemeIconInfo *info;
+ info = mate_theme_icon_info_find (name);
+ if (info != NULL) {
+ generate_icon_theme_thumbnail_async (info,
+ (ThemeThumbnailFunc) icon_theme_thumbnail_cb, data, NULL);
+ }
+ } else if (default_thumb == data->gtk_theme_icon) {
+ MateThemeInfo *info;
+ info = mate_theme_info_find (name);
+ if (info != NULL && info->has_gtk) {
+ generate_gtk_theme_thumbnail_async (info,
+ (ThemeThumbnailFunc) gtk_theme_thumbnail_cb, data, NULL);
+ }
+ } else if (default_thumb == data->window_theme_icon) {
+ MateThemeInfo *info;
+ info = mate_theme_info_find (name);
+ if (info != NULL && info->has_marco) {
+ generate_marco_theme_thumbnail_async (info,
+ (ThemeThumbnailFunc) marco_theme_thumbnail_cb, data, NULL);
+ }
+ }
+}
+
+static void
+changed_on_disk_cb (MateThemeCommonInfo *theme,
+ MateThemeChangeType change_type,
+ MateThemeElement element_type,
+ AppearanceData *data)
+{
+ if (theme->type == MATE_THEME_TYPE_REGULAR) {
+ MateThemeInfo *info = (MateThemeInfo *) theme;
+
+ if (change_type == MATE_THEME_CHANGE_DELETED) {
+ if (element_type & MATE_THEME_GTK_2)
+ remove_from_treeview ("gtk_themes_list", info->name, data);
+ if (element_type & MATE_THEME_MARCO)
+ remove_from_treeview ("window_themes_list", info->name, data);
+
+ } else {
+ if (element_type & MATE_THEME_GTK_2) {
+ if (change_type == MATE_THEME_CHANGE_CREATED)
+ add_to_treeview ("gtk_themes_list", info->name, info->name, data->gtk_theme_icon, data);
+ else if (change_type == MATE_THEME_CHANGE_CHANGED)
+ update_in_treeview ("gtk_themes_list", info->name, info->name, data);
+
+ generate_gtk_theme_thumbnail_async (info,
+ (ThemeThumbnailFunc) gtk_theme_thumbnail_cb, data, NULL);
+ }
+
+ if (element_type & MATE_THEME_MARCO) {
+ if (change_type == MATE_THEME_CHANGE_CREATED)
+ add_to_treeview ("window_themes_list", info->name, info->name, data->window_theme_icon, data);
+ else if (change_type == MATE_THEME_CHANGE_CHANGED)
+ update_in_treeview ("window_themes_list", info->name, info->name, data);
+
+ generate_marco_theme_thumbnail_async (info,
+ (ThemeThumbnailFunc) marco_theme_thumbnail_cb, data, NULL);
+ }
+ }
+
+ } else if (theme->type == MATE_THEME_TYPE_ICON) {
+ MateThemeIconInfo *info = (MateThemeIconInfo *) theme;
+
+ if (change_type == MATE_THEME_CHANGE_DELETED) {
+ remove_from_treeview ("icon_themes_list", info->name, data);
+ } else {
+ if (change_type == MATE_THEME_CHANGE_CREATED)
+ add_to_treeview ("icon_themes_list", info->name, info->readable_name, data->icon_theme_icon, data);
+ else if (change_type == MATE_THEME_CHANGE_CHANGED)
+ update_in_treeview ("icon_themes_list", info->name, info->readable_name, data);
+
+ generate_icon_theme_thumbnail_async (info,
+ (ThemeThumbnailFunc) icon_theme_thumbnail_cb, data, NULL);
+ }
+
+ } else if (theme->type == MATE_THEME_TYPE_CURSOR) {
+ MateThemeCursorInfo *info = (MateThemeCursorInfo *) theme;
+
+ if (change_type == MATE_THEME_CHANGE_DELETED) {
+ remove_from_treeview ("cursor_themes_list", info->name, data);
+ } else {
+ if (change_type == MATE_THEME_CHANGE_CREATED)
+ add_to_treeview ("cursor_themes_list", info->name, info->readable_name, info->thumbnail, data);
+ else if (change_type == MATE_THEME_CHANGE_CHANGED)
+ update_in_treeview ("cursor_themes_list", info->name, info->readable_name, data);
+ }
+ }
+}
+
+static void
+prepare_list (AppearanceData *data, GtkWidget *list, ThemeType type, GCallback callback)
+{
+ GtkListStore *store;
+ GList *l, *themes = NULL;
+ GtkCellRenderer *renderer;
+ GtkTreeViewColumn *column;
+ GtkTreeModel *sort_model;
+ GdkPixbuf *thumbnail;
+ const gchar *key;
+ GObject *peditor;
+ MateConfValue *value;
+ ThumbnailGenFunc generator;
+ ThemeThumbnailFunc thumb_cb;
+ PEditorConvData *conv_data;
+
+ switch (type)
+ {
+ case THEME_TYPE_GTK:
+ themes = mate_theme_info_find_by_type (MATE_THEME_GTK_2);
+ thumbnail = data->gtk_theme_icon;
+ key = GTK_THEME_KEY;
+ generator = (ThumbnailGenFunc) generate_gtk_theme_thumbnail_async;
+ thumb_cb = (ThemeThumbnailFunc) gtk_theme_thumbnail_cb;
+ break;
+
+ case THEME_TYPE_WINDOW:
+ themes = mate_theme_info_find_by_type (MATE_THEME_MARCO);
+ thumbnail = data->window_theme_icon;
+ key = MARCO_THEME_KEY;
+ generator = (ThumbnailGenFunc) generate_marco_theme_thumbnail_async;
+ thumb_cb = (ThemeThumbnailFunc) marco_theme_thumbnail_cb;
+ break;
+
+ case THEME_TYPE_ICON:
+ themes = mate_theme_icon_info_find_all ();
+ thumbnail = data->icon_theme_icon;
+ key = ICON_THEME_KEY;
+ generator = (ThumbnailGenFunc) generate_icon_theme_thumbnail_async;
+ thumb_cb = (ThemeThumbnailFunc) icon_theme_thumbnail_cb;
+ break;
+
+ case THEME_TYPE_CURSOR:
+ themes = mate_theme_cursor_info_find_all ();
+ thumbnail = NULL;
+ key = CURSOR_THEME_KEY;
+ generator = NULL;
+ thumb_cb = NULL;
+ break;
+
+ default:
+ /* we don't deal with any other type of themes here */
+ return;
+ }
+
+ store = gtk_list_store_new (NUM_COLS, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING);
+
+ for (l = themes; l; l = g_list_next (l))
+ {
+ MateThemeCommonInfo *theme = (MateThemeCommonInfo *) l->data;
+ GtkTreeIter i;
+
+ if (type == THEME_TYPE_CURSOR) {
+ thumbnail = ((MateThemeCursorInfo *) theme)->thumbnail;
+ } else {
+ generator (theme, thumb_cb, data, NULL);
+ }
+
+ gtk_list_store_insert_with_values (store, &i, 0,
+ COL_LABEL, theme->readable_name,
+ COL_NAME, theme->name,
+ COL_THUMBNAIL, thumbnail,
+ -1);
+
+ if (type == THEME_TYPE_CURSOR && thumbnail) {
+ g_object_unref (thumbnail);
+ thumbnail = NULL;
+ }
+ }
+ g_list_free (themes);
+
+ sort_model = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store));
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort_model),
+ COL_LABEL, GTK_SORT_ASCENDING);
+
+ if (type == THEME_TYPE_CURSOR)
+ gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (sort_model), COL_LABEL,
+ (GtkTreeIterCompareFunc) cursor_theme_sort_func,
+ NULL, NULL);
+
+ gtk_tree_view_set_model (GTK_TREE_VIEW (list), GTK_TREE_MODEL (sort_model));
+
+ renderer = gtk_cell_renderer_pixbuf_new ();
+ g_object_set (renderer, "xpad", 3, "ypad", 3, NULL);
+
+ column = gtk_tree_view_column_new ();
+ gtk_tree_view_column_pack_start (column, renderer, FALSE);
+ gtk_tree_view_column_add_attribute (column, renderer, "pixbuf", COL_THUMBNAIL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (list), column);
+
+ renderer = gtk_cell_renderer_text_new ();
+
+ column = gtk_tree_view_column_new ();
+ gtk_tree_view_column_pack_start (column, renderer, FALSE);
+ gtk_tree_view_column_add_attribute (column, renderer, "text", COL_LABEL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (list), column);
+
+ conv_data = g_new (PEditorConvData, 1);
+ conv_data->data = data;
+ conv_data->thumbnail = thumbnail;
+ peditor = mateconf_peditor_new_tree_view (NULL, key, list,
+ "conv-to-widget-cb", conv_to_widget_cb,
+ "conv-from-widget-cb", conv_from_widget_cb,
+ "data", conv_data,
+ "data-free-cb", g_free,
+ NULL);
+ g_signal_connect (peditor, "value-changed", callback, data);
+
+ /* init the delete buttons */
+ value = mateconf_client_get (data->client, key, NULL);
+ (*((void (*) (MateConfPropertyEditor *, const gchar *, const MateConfValue *, gpointer)) callback))
+ (MATECONF_PROPERTY_EDITOR (peditor), key, value, data);
+ if (value)
+ mateconf_value_free (value);
+}
+
+void
+style_init (AppearanceData *data)
+{
+ GtkSettings *settings;
+ GtkWidget *w;
+ gchar *label;
+ gint i;
+
+ data->gtk_theme_icon = gdk_pixbuf_new_from_file (MATECC_PIXMAP_DIR "/gtk-theme-thumbnailing.png", NULL);
+ data->window_theme_icon = gdk_pixbuf_new_from_file (MATECC_PIXMAP_DIR "/window-theme-thumbnailing.png", NULL);
+ data->icon_theme_icon = gdk_pixbuf_new_from_file (MATECC_PIXMAP_DIR "/icon-theme-thumbnailing.png", NULL);
+ data->style_message_area = NULL;
+ data->style_message_label = NULL;
+ data->style_install_button = NULL;
+
+ w = appearance_capplet_get_widget (data, "theme_details");
+ g_signal_connect (w, "response", (GCallback) style_response_cb, NULL);
+ g_signal_connect (w, "delete_event", (GCallback) gtk_true, NULL);
+
+ prepare_list (data, appearance_capplet_get_widget (data, "window_themes_list"), THEME_TYPE_WINDOW, (GCallback) window_theme_changed);
+ prepare_list (data, appearance_capplet_get_widget (data, "gtk_themes_list"), THEME_TYPE_GTK, (GCallback) gtk_theme_changed);
+ prepare_list (data, appearance_capplet_get_widget (data, "icon_themes_list"), THEME_TYPE_ICON, (GCallback) icon_theme_changed);
+ prepare_list (data, appearance_capplet_get_widget (data, "cursor_themes_list"), THEME_TYPE_CURSOR, (GCallback) cursor_theme_changed);
+
+ w = appearance_capplet_get_widget (data, "color_scheme_message_hbox");
+ gtk_widget_set_no_show_all (w, TRUE);
+
+ w = appearance_capplet_get_widget (data, "color_scheme_defaults_button");
+ gtk_button_set_image (GTK_BUTTON (w),
+ gtk_image_new_from_stock (GTK_STOCK_REVERT_TO_SAVED,
+ GTK_ICON_SIZE_BUTTON));
+
+ settings = gtk_settings_get_default ();
+ g_signal_connect (settings, "notify::gtk-color-scheme", (GCallback) color_scheme_changed, data);
+
+#ifdef HAVE_XCURSOR
+ w = appearance_capplet_get_widget (data, "cursor_size_scale");
+ g_signal_connect (w, "value-changed", (GCallback) cursor_size_scale_value_changed_cb, data);
+
+ w = appearance_capplet_get_widget (data, "cursor_size_small_label");
+ label = g_strdup_printf ("<small><i>%s</i></small>", gtk_label_get_text (GTK_LABEL (w)));
+ gtk_label_set_markup (GTK_LABEL (w), label);
+ g_free (label);
+
+ w = appearance_capplet_get_widget (data, "cursor_size_large_label");
+ label = g_strdup_printf ("<small><i>%s</i></small>", gtk_label_get_text (GTK_LABEL (w)));
+ gtk_label_set_markup (GTK_LABEL (w), label);
+ g_free (label);
+#else
+ w = appearance_capplet_get_widget (data, "cursor_size_hbox");
+ gtk_widget_set_no_show_all (w, TRUE);
+ gtk_widget_hide (w);
+ gtk_widget_show (appearance_capplet_get_widget (data, "cursor_message_hbox"));
+ gtk_box_set_spacing (GTK_BOX (appearance_capplet_get_widget (data, "cursor_vbox")), 12);
+#endif
+
+ /* connect signals */
+ /* color buttons */
+ for (i = 0; i < NUM_SYMBOLIC_COLORS; ++i)
+ g_signal_connect (appearance_capplet_get_widget (data, symbolic_names[i]), "color-set", (GCallback) color_button_clicked_cb, data);
+
+ /* revert button */
+ g_signal_connect (appearance_capplet_get_widget (data, "color_scheme_defaults_button"), "clicked", (GCallback) color_scheme_defaults_button_clicked_cb, data);
+ /* delete buttons */
+ g_signal_connect (appearance_capplet_get_widget (data, "gtk_themes_delete"), "clicked", (GCallback) gtk_theme_delete_cb, data);
+ g_signal_connect (appearance_capplet_get_widget (data, "window_themes_delete"), "clicked", (GCallback) window_theme_delete_cb, data);
+ g_signal_connect (appearance_capplet_get_widget (data, "icon_themes_delete"), "clicked", (GCallback) icon_theme_delete_cb, data);
+ g_signal_connect (appearance_capplet_get_widget (data, "cursor_themes_delete"), "clicked", (GCallback) cursor_theme_delete_cb, data);
+
+ update_message_area (data);
+ mate_theme_info_register_theme_change ((ThemeChangedCallback) changed_on_disk_cb, data);
+}
+
+void
+style_shutdown (AppearanceData *data)
+{
+ if (data->gtk_theme_icon)
+ g_object_unref (data->gtk_theme_icon);
+ if (data->window_theme_icon)
+ g_object_unref (data->window_theme_icon);
+ if (data->icon_theme_icon)
+ g_object_unref (data->icon_theme_icon);
+}
diff --git a/capplets/appearance/appearance-style.h b/capplets/appearance/appearance-style.h
new file mode 100644
index 00000000..65203104
--- /dev/null
+++ b/capplets/appearance/appearance-style.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2007 The MATE Foundation
+ * Written by Thomas Wood <[email protected]>
+ * All Rights Reserved
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+void style_init (AppearanceData *data);
+void style_shutdown (AppearanceData *data);
diff --git a/capplets/appearance/appearance-themes.c b/capplets/appearance/appearance-themes.c
new file mode 100644
index 00000000..132aa4b4
--- /dev/null
+++ b/capplets/appearance/appearance-themes.c
@@ -0,0 +1,1179 @@
+/*
+ * Copyright (C) 2007, 2010 The MATE Foundation
+ * Written by Thomas Wood <[email protected]>
+ * Jens Granseuer <[email protected]>
+ * All Rights Reserved
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "appearance.h"
+#include "theme-thumbnail.h"
+#include "mate-theme-apply.h"
+#include "theme-installer.h"
+#include "theme-save.h"
+#include "theme-util.h"
+#include "gtkrc-utils.h"
+
+#include <glib/gi18n.h>
+#include <libwindow-settings/mate-wm-manager.h>
+#include <string.h>
+#include <libmateui/mate-desktop-thumbnail.h>
+
+#define CUSTOM_THEME_NAME "__custom__"
+
+enum {
+ RESPONSE_APPLY_BG,
+ RESPONSE_REVERT_FONT,
+ RESPONSE_APPLY_FONT,
+ RESPONSE_INSTALL_ENGINE
+};
+
+enum {
+ TARGET_URI_LIST,
+ TARGET_NS_URL
+};
+
+static const GtkTargetEntry drop_types[] =
+{
+ {"text/uri-list", 0, TARGET_URI_LIST},
+ {"_NETSCAPE_URL", 0, TARGET_NS_URL}
+};
+
+static void theme_message_area_update(AppearanceData* data);
+
+static time_t theme_get_mtime(const char* name)
+{
+ MateThemeMetaInfo* theme;
+ time_t mtime = -1;
+
+ theme = mate_theme_meta_info_find(name);
+ if (theme != NULL)
+ {
+ GFile* file;
+ GFileInfo* file_info;
+
+ file = g_file_new_for_path(theme->path);
+ file_info = g_file_query_info(file, G_FILE_ATTRIBUTE_TIME_MODIFIED, G_FILE_QUERY_INFO_NONE, NULL, NULL);
+ g_object_unref(file);
+
+ if (file_info != NULL)
+ {
+ mtime = g_file_info_get_attribute_uint64(file_info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
+ g_object_unref(file_info);
+ }
+ }
+
+ return mtime;
+}
+
+static void theme_thumbnail_update(GdkPixbuf* pixbuf, gchar* theme_name, AppearanceData* data, gboolean cache)
+{
+ GtkTreeIter iter;
+ GtkTreeModel* model = GTK_TREE_MODEL(data->theme_store);
+
+ /* find item in model and update thumbnail */
+ if (!pixbuf)
+ return;
+
+ if (theme_find_in_model(model, theme_name, &iter))
+ {
+ time_t mtime;
+
+ gtk_list_store_set(data->theme_store, &iter, COL_THUMBNAIL, pixbuf, -1);
+
+ /* cache thumbnail */
+ if (cache && (mtime = theme_get_mtime(theme_name)) != -1)
+ {
+ gchar* path;
+
+ /* try to share thumbs with caja, use themes:/// */
+ path = g_strconcat("themes:///", theme_name, NULL);
+
+ mate_desktop_thumbnail_factory_save_thumbnail(data->thumb_factory, pixbuf, path, mtime);
+
+ g_free(path);
+ }
+ }
+}
+
+static GdkPixbuf* theme_get_thumbnail_from_cache(MateThemeMetaInfo* info, AppearanceData* data)
+{
+ GdkPixbuf* thumb = NULL;
+ gchar* path, *thumb_filename;
+ time_t mtime;
+
+ if (info == data->theme_custom)
+ return NULL;
+
+ mtime = theme_get_mtime(info->name);
+
+ if (mtime == -1)
+ return NULL;
+
+ /* try to share thumbs with caja, use themes:/// */
+ path = g_strconcat ("themes:///", info->name, NULL);
+ thumb_filename = mate_desktop_thumbnail_factory_lookup(data->thumb_factory, path, mtime);
+ g_free(path);
+
+ if (thumb_filename != NULL)
+ {
+ thumb = gdk_pixbuf_new_from_file(thumb_filename, NULL);
+ g_free(thumb_filename);
+ }
+
+ return thumb;
+}
+
+static void
+theme_thumbnail_done_cb (GdkPixbuf *pixbuf, gchar *theme_name, AppearanceData *data)
+{
+ theme_thumbnail_update (pixbuf, theme_name, data, TRUE);
+}
+
+static void theme_thumbnail_generate(MateThemeMetaInfo* info, AppearanceData* data)
+{
+ GdkPixbuf* thumb = theme_get_thumbnail_from_cache(info, data);
+
+ if (thumb != NULL)
+ {
+ theme_thumbnail_update(thumb, info->name, data, FALSE);
+ g_object_unref(thumb);
+ }
+ else
+ {
+ generate_meta_theme_thumbnail_async(info, (ThemeThumbnailFunc) theme_thumbnail_done_cb, data, NULL);
+ }
+}
+
+static void theme_changed_on_disk_cb(MateThemeCommonInfo* theme, MateThemeChangeType change_type, MateThemeElement element_type, AppearanceData* data)
+{
+ if (theme->type == MATE_THEME_TYPE_METATHEME)
+ {
+ MateThemeMetaInfo* meta = (MateThemeMetaInfo*) theme;
+
+ if (change_type == MATE_THEME_CHANGE_CREATED)
+ {
+ gtk_list_store_insert_with_values (data->theme_store, NULL, 0, COL_LABEL, meta->readable_name, COL_NAME, meta->name, COL_THUMBNAIL, data->theme_icon, -1);
+ theme_thumbnail_generate(meta, data);
+ }
+ else if (change_type == MATE_THEME_CHANGE_DELETED)
+ {
+ GtkTreeIter iter;
+
+ if (theme_find_in_model(GTK_TREE_MODEL(data->theme_store), meta->name, &iter))
+ {
+ gtk_list_store_remove(data->theme_store, &iter);
+ }
+ }
+ else if (change_type == MATE_THEME_CHANGE_CHANGED)
+ {
+ theme_thumbnail_generate(meta, data);
+ }
+ }
+}
+
+static gchar* get_default_string_from_key(MateConfClient* client, const char* key)
+{
+ gchar* str = NULL;
+
+ MateConfValue* value = mateconf_client_get_default_from_schema(client, key, NULL);
+
+ if (value)
+ {
+ if (value->type == MATECONF_VALUE_STRING)
+ {
+ str = mateconf_value_to_string (value);
+ }
+
+ mateconf_value_free (value);
+ }
+
+ return str;
+}
+
+/* Find out if the lockdown key has been set.
+ * Currently returns false on error... */
+static gboolean is_locked_down(MateConfClient* client)
+{
+ return mateconf_client_get_bool(client, LOCKDOWN_KEY, NULL);
+}
+
+static MateThemeMetaInfo *
+theme_load_from_mateconf (MateConfClient *client)
+{
+ MateThemeMetaInfo *theme;
+ gchar *scheme;
+
+ theme = mate_theme_meta_info_new ();
+
+ theme->gtk_theme_name = mateconf_client_get_string (client, GTK_THEME_KEY, NULL);
+ if (theme->gtk_theme_name == NULL)
+ theme->gtk_theme_name = g_strdup ("Clearlooks");
+
+ scheme = mateconf_client_get_string (client, COLOR_SCHEME_KEY, NULL);
+ if (scheme == NULL || !strcmp (scheme, "")) {
+ g_free (scheme);
+ scheme = gtkrc_get_color_scheme_for_theme (theme->gtk_theme_name);
+ }
+ theme->gtk_color_scheme = scheme;
+
+ theme->marco_theme_name = mateconf_client_get_string (client, MARCO_THEME_KEY, NULL);
+ if (theme->marco_theme_name == NULL)
+ theme->marco_theme_name = g_strdup ("Clearlooks");
+
+ theme->icon_theme_name = mateconf_client_get_string (client, ICON_THEME_KEY, NULL);
+ if (theme->icon_theme_name == NULL)
+ theme->icon_theme_name = g_strdup ("mate");
+
+ theme->notification_theme_name = mateconf_client_get_string (client, NOTIFICATION_THEME_KEY, NULL);
+
+ theme->cursor_theme_name = mateconf_client_get_string (client, CURSOR_THEME_KEY, NULL);
+#ifdef HAVE_XCURSOR
+ theme->cursor_size = mateconf_client_get_int (client, CURSOR_SIZE_KEY, NULL);
+#endif
+ if (theme->cursor_theme_name == NULL)
+ theme->cursor_theme_name = g_strdup ("default");
+
+ theme->application_font = mateconf_client_get_string (client, APPLICATION_FONT_KEY, NULL);
+
+ return theme;
+}
+
+static gchar *
+theme_get_selected_name (GtkIconView *icon_view, AppearanceData *data)
+{
+ gchar *name = NULL;
+ GList *selected = gtk_icon_view_get_selected_items (icon_view);
+
+ if (selected) {
+ GtkTreePath *path = selected->data;
+ GtkTreeModel *model = gtk_icon_view_get_model (icon_view);
+ GtkTreeIter iter;
+
+ if (gtk_tree_model_get_iter (model, &iter, path))
+ gtk_tree_model_get (model, &iter, COL_NAME, &name, -1);
+
+ g_list_foreach (selected, (GFunc) gtk_tree_path_free, NULL);
+ g_list_free (selected);
+ }
+
+ return name;
+}
+
+static const MateThemeMetaInfo *
+theme_get_selected (GtkIconView *icon_view, AppearanceData *data)
+{
+ MateThemeMetaInfo *theme = NULL;
+ gchar *name = theme_get_selected_name (icon_view, data);
+
+ if (name != NULL) {
+ if (!strcmp (name, data->theme_custom->name)) {
+ theme = data->theme_custom;
+ } else {
+ theme = mate_theme_meta_info_find (name);
+ }
+
+ g_free (name);
+ }
+
+ return theme;
+}
+
+static void
+theme_select_iter (GtkIconView *icon_view, GtkTreeIter *iter)
+{
+ GtkTreePath *path;
+
+ path = gtk_tree_model_get_path (gtk_icon_view_get_model (icon_view), iter);
+ gtk_icon_view_select_path (icon_view, path);
+ gtk_icon_view_scroll_to_path (icon_view, path, FALSE, 0.5, 0.0);
+ gtk_tree_path_free (path);
+}
+
+static void
+theme_select_name (GtkIconView *icon_view, const gchar *theme)
+{
+ GtkTreeIter iter;
+ GtkTreeModel *model = gtk_icon_view_get_model (icon_view);
+
+ if (theme_find_in_model (model, theme, &iter))
+ theme_select_iter (icon_view, &iter);
+}
+
+static gboolean
+theme_is_equal (const MateThemeMetaInfo *a, const MateThemeMetaInfo *b)
+{
+ gboolean a_set, b_set;
+
+ if (!(a->gtk_theme_name && b->gtk_theme_name) ||
+ strcmp (a->gtk_theme_name, b->gtk_theme_name))
+ return FALSE;
+
+ if (!(a->icon_theme_name && b->icon_theme_name) ||
+ strcmp (a->icon_theme_name, b->icon_theme_name))
+ return FALSE;
+
+ if (!(a->marco_theme_name && b->marco_theme_name) ||
+ strcmp (a->marco_theme_name, b->marco_theme_name))
+ return FALSE;
+
+ if (!(a->cursor_theme_name && b->cursor_theme_name) ||
+ strcmp (a->cursor_theme_name, b->cursor_theme_name))
+ return FALSE;
+
+ if (a->cursor_size != b->cursor_size)
+ return FALSE;
+
+ a_set = a->gtk_color_scheme && strcmp (a->gtk_color_scheme, "");
+ b_set = b->gtk_color_scheme && strcmp (b->gtk_color_scheme, "");
+ if ((a_set != b_set) ||
+ (a_set && !mate_theme_color_scheme_equal (a->gtk_color_scheme, b->gtk_color_scheme)))
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+theme_set_custom_from_theme (const MateThemeMetaInfo *info, AppearanceData *data)
+{
+ MateThemeMetaInfo *custom = data->theme_custom;
+ GtkIconView *icon_view = GTK_ICON_VIEW (appearance_capplet_get_widget (data, "theme_list"));
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GtkTreePath *path;
+
+ if (info == custom)
+ return;
+
+ /* if info is not NULL, we'll copy those theme settings over */
+ if (info != NULL) {
+ g_free (custom->gtk_theme_name);
+ g_free (custom->icon_theme_name);
+ g_free (custom->marco_theme_name);
+ g_free (custom->gtk_color_scheme);
+ g_free (custom->cursor_theme_name);
+ g_free (custom->application_font);
+ custom->gtk_color_scheme = NULL;
+ custom->application_font = NULL;
+
+ /* these settings are guaranteed to be non-NULL */
+ custom->gtk_theme_name = g_strdup (info->gtk_theme_name);
+ custom->icon_theme_name = g_strdup (info->icon_theme_name);
+ custom->marco_theme_name = g_strdup (info->marco_theme_name);
+ custom->cursor_theme_name = g_strdup (info->cursor_theme_name);
+ custom->cursor_size = info->cursor_size;
+
+ /* these can be NULL */
+ if (info->gtk_color_scheme)
+ custom->gtk_color_scheme = g_strdup (info->gtk_color_scheme);
+ else
+ custom->gtk_color_scheme = get_default_string_from_key (data->client, COLOR_SCHEME_KEY);
+
+ if (info->application_font)
+ custom->application_font = g_strdup (info->application_font);
+ else
+ custom->application_font = get_default_string_from_key (data->client, APPLICATION_FONT_KEY);
+ }
+
+ /* select the custom theme */
+ model = gtk_icon_view_get_model (icon_view);
+ if (!theme_find_in_model (model, custom->name, &iter)) {
+ GtkTreeIter child;
+
+ gtk_list_store_insert_with_values (data->theme_store, &child, 0,
+ COL_LABEL, custom->readable_name,
+ COL_NAME, custom->name,
+ COL_THUMBNAIL, data->theme_icon,
+ -1);
+ gtk_tree_model_sort_convert_child_iter_to_iter (
+ GTK_TREE_MODEL_SORT (model), &iter, &child);
+ }
+
+ path = gtk_tree_model_get_path (model, &iter);
+ gtk_icon_view_select_path (icon_view, path);
+ gtk_icon_view_scroll_to_path (icon_view, path, FALSE, 0.5, 0.0);
+ gtk_tree_path_free (path);
+
+ /* update the theme thumbnail */
+ theme_thumbnail_generate (custom, data);
+}
+
+/** GUI Callbacks **/
+
+static void custom_font_cb(GtkWidget* button, AppearanceData* data)
+{
+ g_free(data->revert_application_font);
+ g_free(data->revert_documents_font);
+ g_free(data->revert_desktop_font);
+ g_free(data->revert_windowtitle_font);
+ g_free(data->revert_monospace_font);
+ data->revert_application_font = NULL;
+ data->revert_documents_font = NULL;
+ data->revert_desktop_font = NULL;
+ data->revert_windowtitle_font = NULL;
+ data->revert_monospace_font = NULL;
+}
+
+static void
+theme_message_area_response_cb (GtkWidget *w,
+ gint response_id,
+ AppearanceData *data)
+{
+ const MateThemeMetaInfo *theme;
+ gchar *tmpfont;
+ gchar *engine_path;
+
+ theme = theme_get_selected (GTK_ICON_VIEW (appearance_capplet_get_widget (data, "theme_list")), data);
+ if (!theme)
+ return;
+
+ switch (response_id)
+ {
+ case RESPONSE_APPLY_BG:
+ mateconf_client_set_string (data->client, BACKGROUND_KEY,
+ theme->background_image, NULL);
+ break;
+
+ case RESPONSE_REVERT_FONT:
+ if (data->revert_application_font != NULL) {
+ mateconf_client_set_string (data->client, APPLICATION_FONT_KEY,
+ data->revert_application_font, NULL);
+ g_free (data->revert_application_font);
+ data->revert_application_font = NULL;
+ }
+
+ if (data->revert_documents_font != NULL) {
+ mateconf_client_set_string (data->client, DOCUMENTS_FONT_KEY,
+ data->revert_documents_font, NULL);
+ g_free (data->revert_documents_font);
+ data->revert_documents_font = NULL;
+ }
+
+ if (data->revert_desktop_font != NULL) {
+ mateconf_client_set_string (data->client, DESKTOP_FONT_KEY,
+ data->revert_desktop_font, NULL);
+ g_free (data->revert_desktop_font);
+ data->revert_desktop_font = NULL;
+ }
+
+ if (data->revert_windowtitle_font != NULL) {
+ mateconf_client_set_string (data->client, WINDOWTITLE_FONT_KEY,
+ data->revert_windowtitle_font, NULL);
+ g_free (data->revert_windowtitle_font);
+ data->revert_windowtitle_font = NULL;
+ }
+
+ if (data->revert_monospace_font != NULL) {
+ mateconf_client_set_string (data->client, MONOSPACE_FONT_KEY,
+ data->revert_monospace_font, NULL);
+ g_free (data->revert_monospace_font);
+ data->revert_monospace_font = NULL;
+ }
+ break;
+
+ case RESPONSE_APPLY_FONT:
+ if (theme->application_font) {
+ tmpfont = mateconf_client_get_string (data->client, APPLICATION_FONT_KEY, NULL);
+ if (tmpfont != NULL) {
+ g_free (data->revert_application_font);
+
+ if (strcmp (theme->application_font, tmpfont) == 0) {
+ g_free (tmpfont);
+ data->revert_application_font = NULL;
+ } else
+ data->revert_application_font = tmpfont;
+ }
+ mateconf_client_set_string (data->client, APPLICATION_FONT_KEY,
+ theme->application_font, NULL);
+ }
+
+ if (theme->documents_font) {
+ tmpfont = mateconf_client_get_string (data->client, DOCUMENTS_FONT_KEY, NULL);
+ if (tmpfont != NULL) {
+ g_free (data->revert_documents_font);
+
+ if (strcmp (theme->documents_font, tmpfont) == 0) {
+ g_free (tmpfont);
+ data->revert_documents_font = NULL;
+ } else
+ data->revert_documents_font = tmpfont;
+ }
+ mateconf_client_set_string (data->client, DOCUMENTS_FONT_KEY,
+ theme->documents_font, NULL);
+ }
+
+ if (theme->desktop_font) {
+ tmpfont = mateconf_client_get_string (data->client, DESKTOP_FONT_KEY, NULL);
+ if (tmpfont != NULL) {
+ g_free (data->revert_desktop_font);
+
+ if (strcmp (theme->desktop_font, tmpfont) == 0) {
+ g_free (tmpfont);
+ data->revert_desktop_font = NULL;
+ } else
+ data->revert_desktop_font = tmpfont;
+ }
+ mateconf_client_set_string (data->client, DESKTOP_FONT_KEY,
+ theme->desktop_font, NULL);
+ }
+
+ if (theme->windowtitle_font) {
+ tmpfont = mateconf_client_get_string (data->client, WINDOWTITLE_FONT_KEY, NULL);
+ if (tmpfont != NULL) {
+ g_free (data->revert_windowtitle_font);
+
+ if (strcmp (theme->windowtitle_font, tmpfont) == 0) {
+ g_free (tmpfont);
+ data->revert_windowtitle_font = NULL;
+ } else
+ data->revert_windowtitle_font = tmpfont;
+ }
+ mateconf_client_set_string (data->client, WINDOWTITLE_FONT_KEY,
+ theme->windowtitle_font, NULL);
+ }
+
+ if (theme->monospace_font) {
+ tmpfont = mateconf_client_get_string (data->client, MONOSPACE_FONT_KEY, NULL);
+ if (tmpfont != NULL) {
+ g_free (data->revert_monospace_font);
+
+ if (strcmp (theme->monospace_font, tmpfont) == 0) {
+ g_free (tmpfont);
+ data->revert_monospace_font = NULL;
+ } else
+ data->revert_monospace_font = tmpfont;
+ }
+ mateconf_client_set_string (data->client, MONOSPACE_FONT_KEY,
+ theme->monospace_font, NULL);
+ }
+ break;
+
+ case RESPONSE_INSTALL_ENGINE:
+
+ engine_path = gtk_theme_info_missing_engine(theme->gtk_theme_name, FALSE);
+
+ if (engine_path != NULL)
+ {
+ theme_install_file(GTK_WINDOW(gtk_widget_get_toplevel(data->install_button)), engine_path);
+ g_free (engine_path);
+ }
+
+ theme_message_area_update(data);
+ break;
+ }
+}
+
+static void
+theme_message_area_update (AppearanceData *data)
+{
+ const MateThemeMetaInfo *theme;
+ gboolean show_apply_background = FALSE;
+ gboolean show_apply_font = FALSE;
+ gboolean show_revert_font = FALSE;
+ gboolean show_error;
+ const gchar *message;
+ gchar *font;
+ GError *error = NULL;
+
+ theme = theme_get_selected (GTK_ICON_VIEW (appearance_capplet_get_widget (data, "theme_list")), data);
+
+ if (!theme) {
+ if (data->theme_message_area != NULL)
+ gtk_widget_hide (data->theme_message_area);
+ return;
+ }
+
+ show_error = !mate_theme_meta_info_validate (theme, &error);
+
+ if (!show_error) {
+ if (theme->background_image != NULL) {
+ gchar *background;
+
+ background = mateconf_client_get_string (data->client, BACKGROUND_KEY, NULL);
+ show_apply_background =
+ (!background || strcmp (theme->background_image, background) != 0);
+ g_free (background);
+ }
+
+ if (theme->application_font) {
+ font = mateconf_client_get_string (data->client, APPLICATION_FONT_KEY, NULL);
+ show_apply_font =
+ (!font || strcmp (theme->application_font, font) != 0);
+ g_free (font);
+ }
+
+ if (!show_apply_font && theme->documents_font) {
+ font = mateconf_client_get_string (data->client, DOCUMENTS_FONT_KEY, NULL);
+ show_apply_font =
+ (!font || strcmp (theme->application_font, font) != 0);
+ g_free (font);
+ }
+
+ if (!show_apply_font && theme->desktop_font) {
+ font = mateconf_client_get_string (data->client, DESKTOP_FONT_KEY, NULL);
+ show_apply_font =
+ (!font || strcmp (theme->application_font, font) != 0);
+ g_free (font);
+ }
+
+ if (!show_apply_font && theme->windowtitle_font) {
+ font = mateconf_client_get_string (data->client, WINDOWTITLE_FONT_KEY, NULL);
+ show_apply_font =
+ (!font || strcmp (theme->application_font, font) != 0);
+ g_free (font);
+ }
+
+ if (!show_apply_font && theme->monospace_font) {
+ font = mateconf_client_get_string (data->client, MONOSPACE_FONT_KEY, NULL);
+ show_apply_font =
+ (!font || strcmp (theme->application_font, font) != 0);
+ g_free (font);
+ }
+
+ show_revert_font = (data->revert_application_font != NULL ||
+ data->revert_documents_font != NULL || data->revert_desktop_font != NULL ||
+ data->revert_windowtitle_font != NULL || data->revert_monospace_font != NULL);
+ }
+
+ if (data->theme_message_area == NULL) {
+ GtkWidget *hbox;
+ GtkWidget *parent;
+ GtkWidget *content;
+
+ if (!show_apply_background && !show_revert_font && !show_apply_font && !show_error)
+ return;
+
+ data->theme_message_area = gtk_info_bar_new ();
+ gtk_widget_set_no_show_all (data->theme_message_area, TRUE);
+
+ g_signal_connect (data->theme_message_area, "response",
+ (GCallback) theme_message_area_response_cb, data);
+
+ data->apply_background_button = gtk_info_bar_add_button (
+ GTK_INFO_BAR (data->theme_message_area),
+ _("Apply Background"),
+ RESPONSE_APPLY_BG);
+ data->apply_font_button = gtk_info_bar_add_button (
+ GTK_INFO_BAR (data->theme_message_area),
+ _("Apply Font"),
+ RESPONSE_APPLY_FONT);
+ data->revert_font_button = gtk_info_bar_add_button (
+ GTK_INFO_BAR (data->theme_message_area),
+ _("Revert Font"),
+ RESPONSE_REVERT_FONT);
+ data->install_button = gtk_info_bar_add_button (
+ GTK_INFO_BAR (data->theme_message_area),
+ _("Install"),
+ RESPONSE_INSTALL_ENGINE);
+
+ data->theme_message_label = gtk_label_new (NULL);
+ gtk_widget_show (data->theme_message_label);
+ gtk_label_set_line_wrap (GTK_LABEL (data->theme_message_label), TRUE);
+ gtk_misc_set_alignment (GTK_MISC (data->theme_message_label), 0.0, 0.5);
+
+ hbox = gtk_hbox_new (FALSE, 9);
+ gtk_widget_show (hbox);
+ data->theme_info_icon = gtk_image_new_from_stock (GTK_STOCK_DIALOG_INFO, GTK_ICON_SIZE_DIALOG);
+ data->theme_error_icon = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_DIALOG);
+ gtk_misc_set_alignment (GTK_MISC (data->theme_info_icon), 0.5, 0);
+ gtk_misc_set_alignment (GTK_MISC (data->theme_error_icon), 0.5, 0);
+ gtk_box_pack_start (GTK_BOX (hbox), data->theme_info_icon, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (hbox), data->theme_error_icon, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (hbox), data->theme_message_label, TRUE, TRUE, 0);
+ content = gtk_info_bar_get_content_area (GTK_INFO_BAR (data->theme_message_area));
+ gtk_container_add (GTK_CONTAINER (content), hbox);
+
+ parent = appearance_capplet_get_widget (data, "theme_list_vbox");
+ gtk_box_pack_start (GTK_BOX (parent), data->theme_message_area, FALSE, FALSE, 0);
+ }
+
+ if (show_error)
+ message = error->message;
+ else if (show_apply_background && show_apply_font && show_revert_font)
+ message = _("The current theme suggests a background and a font. Also, the last applied font suggestion can be reverted.");
+ else if (show_apply_background && show_revert_font)
+ message = _("The current theme suggests a background. Also, the last applied font suggestion can be reverted.");
+ else if (show_apply_background && show_apply_font)
+ message = _("The current theme suggests a background and a font.");
+ else if (show_apply_font && show_revert_font)
+ message = _("The current theme suggests a font. Also, the last applied font suggestion can be reverted.");
+ else if (show_apply_background)
+ message = _("The current theme suggests a background.");
+ else if (show_revert_font)
+ message = _("The last applied font suggestion can be reverted.");
+ else if (show_apply_font)
+ message = _("The current theme suggests a font.");
+ else
+ message = NULL;
+
+ if (show_apply_background)
+ gtk_widget_show (data->apply_background_button);
+ else
+ gtk_widget_hide (data->apply_background_button);
+
+ if (show_apply_font)
+ gtk_widget_show (data->apply_font_button);
+ else
+ gtk_widget_hide (data->apply_font_button);
+
+ if (show_revert_font)
+ gtk_widget_show (data->revert_font_button);
+ else
+ gtk_widget_hide (data->revert_font_button);
+
+ if (show_error
+ && g_error_matches (error, MATE_THEME_ERROR, MATE_THEME_ERROR_GTK_ENGINE_NOT_AVAILABLE)
+ && packagekit_available ())
+ gtk_widget_show (data->install_button);
+ else
+ gtk_widget_hide (data->install_button);
+
+ if (show_error || show_apply_background || show_apply_font || show_revert_font) {
+ gtk_widget_show (data->theme_message_area);
+ gtk_widget_queue_draw (data->theme_message_area);
+
+ if (show_error) {
+ gtk_widget_show (data->theme_error_icon);
+ gtk_widget_hide (data->theme_info_icon);
+ } else {
+ gtk_widget_show (data->theme_info_icon);
+ gtk_widget_hide (data->theme_error_icon);
+ }
+ } else {
+ gtk_widget_hide (data->theme_message_area);
+ }
+
+ gtk_label_set_text (GTK_LABEL (data->theme_message_label), message);
+ g_clear_error (&error);
+}
+
+static void
+theme_selection_changed_cb (GtkWidget *icon_view, AppearanceData *data)
+{
+ GList *selection;
+ MateThemeMetaInfo *theme = NULL;
+ gboolean is_custom = FALSE;
+
+ selection = gtk_icon_view_get_selected_items (GTK_ICON_VIEW (icon_view));
+
+ if (selection) {
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ gchar *name;
+
+ model = gtk_icon_view_get_model (GTK_ICON_VIEW (icon_view));
+ gtk_tree_model_get_iter (model, &iter, selection->data);
+ gtk_tree_model_get (model, &iter, COL_NAME, &name, -1);
+
+ is_custom = !strcmp (name, CUSTOM_THEME_NAME);
+
+ if (is_custom)
+ theme = data->theme_custom;
+ else
+ theme = mate_theme_meta_info_find (name);
+
+ if (theme) {
+ mate_meta_theme_set (theme);
+ theme_message_area_update (data);
+ }
+
+ g_free (name);
+ g_list_foreach (selection, (GFunc) gtk_tree_path_free, NULL);
+ g_list_free (selection);
+ }
+
+ gtk_widget_set_sensitive (appearance_capplet_get_widget (data, "theme_delete"),
+ theme_is_writable (theme));
+ gtk_widget_set_sensitive (appearance_capplet_get_widget (data, "theme_save"), is_custom);
+}
+
+static void
+theme_custom_cb (GtkWidget *button, AppearanceData *data)
+{
+ GtkWidget *w, *parent;
+
+ w = appearance_capplet_get_widget (data, "theme_details");
+ parent = appearance_capplet_get_widget (data, "appearance_window");
+ gtk_window_set_transient_for (GTK_WINDOW (w), GTK_WINDOW (parent));
+ gtk_widget_show_all (w);
+}
+
+static void
+theme_save_cb (GtkWidget *button, AppearanceData *data)
+{
+ theme_save_dialog_run (data->theme_custom, data);
+}
+
+static void
+theme_install_cb (GtkWidget *button, AppearanceData *data)
+{
+ mate_theme_installer_run (
+ GTK_WINDOW (appearance_capplet_get_widget (data, "appearance_window")), NULL);
+}
+
+static void
+theme_delete_cb (GtkWidget *button, AppearanceData *data)
+{
+ GtkIconView *icon_view = GTK_ICON_VIEW (appearance_capplet_get_widget (data, "theme_list"));
+ GList *selected = gtk_icon_view_get_selected_items (icon_view);
+
+ if (selected) {
+ GtkTreePath *path = selected->data;
+ GtkTreeModel *model = gtk_icon_view_get_model (icon_view);
+ GtkTreeIter iter;
+ gchar *name = NULL;
+
+ if (gtk_tree_model_get_iter (model, &iter, path))
+ gtk_tree_model_get (model, &iter, COL_NAME, &name, -1);
+
+ if (name != NULL &&
+ strcmp (name, data->theme_custom->name) &&
+ theme_delete (name, THEME_TYPE_META)) {
+ /* remove theme from the model, too */
+ GtkTreeIter child;
+
+ if (gtk_tree_model_iter_next (model, &iter) ||
+ theme_model_iter_last (model, &iter))
+ theme_select_iter (icon_view, &iter);
+
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_model_sort_convert_iter_to_child_iter (
+ GTK_TREE_MODEL_SORT (model), &child, &iter);
+ gtk_list_store_remove (data->theme_store, &child);
+ }
+
+ g_list_foreach (selected, (GFunc) gtk_tree_path_free, NULL);
+ g_list_free (selected);
+ g_free (name);
+ }
+}
+
+static void
+theme_details_changed_cb (AppearanceData *data)
+{
+ MateThemeMetaInfo *mateconf_theme;
+ const MateThemeMetaInfo *selected;
+ GtkIconView *icon_view;
+ gboolean done = FALSE;
+
+ /* load new state from mateconf */
+ mateconf_theme = theme_load_from_mateconf (data->client);
+
+ /* check if it's our currently selected theme */
+ icon_view = GTK_ICON_VIEW (appearance_capplet_get_widget (data, "theme_list"));
+ selected = theme_get_selected (icon_view, data);
+
+ if (!selected || !(done = theme_is_equal (selected, mateconf_theme))) {
+ /* look for a matching metatheme */
+ GList *theme_list, *l;
+
+ theme_list = mate_theme_meta_info_find_all ();
+
+ for (l = theme_list; l; l = l->next) {
+ MateThemeMetaInfo *info = l->data;
+
+ if (theme_is_equal (mateconf_theme, info)) {
+ theme_select_name (icon_view, info->name);
+ done = TRUE;
+ break;
+ }
+ }
+ g_list_free (theme_list);
+ }
+
+ if (!done)
+ /* didn't find a match, set or update custom */
+ theme_set_custom_from_theme (mateconf_theme, data);
+
+ mate_theme_meta_info_free (mateconf_theme);
+}
+
+static void
+theme_setting_changed_cb (GObject *settings,
+ GParamSpec *pspec,
+ AppearanceData *data)
+{
+ theme_details_changed_cb (data);
+}
+
+static void
+theme_mateconf_changed (MateConfClient *client,
+ guint conn_id,
+ MateConfEntry *entry,
+ AppearanceData *data)
+{
+ theme_details_changed_cb (data);
+}
+
+static gint
+theme_list_sort_func (MateThemeMetaInfo *a,
+ MateThemeMetaInfo *b)
+{
+ return strcmp (a->readable_name, b->readable_name);
+}
+
+static gint
+theme_store_sort_func (GtkTreeModel *model,
+ GtkTreeIter *a,
+ GtkTreeIter *b,
+ gpointer user_data)
+{
+ gchar *a_name, *a_label;
+ gint rc;
+
+ gtk_tree_model_get (model, a, COL_NAME, &a_name, COL_LABEL, &a_label, -1);
+
+ if (!strcmp (a_name, CUSTOM_THEME_NAME)) {
+ rc = -1;
+ } else {
+ gchar *b_name, *b_label;
+
+ gtk_tree_model_get (model, b, COL_NAME, &b_name, COL_LABEL, &b_label, -1);
+
+ if (!strcmp (b_name, CUSTOM_THEME_NAME)) {
+ rc = 1;
+ } else {
+ gchar *a_case, *b_case;
+
+ a_case = g_utf8_casefold (a_label, -1);
+ b_case = g_utf8_casefold (b_label, -1);
+ rc = g_utf8_collate (a_case, b_case);
+ g_free (a_case);
+ g_free (b_case);
+ }
+
+ g_free (b_name);
+ g_free (b_label);
+ }
+
+ g_free (a_name);
+ g_free (a_label);
+
+ return rc;
+}
+
+static void
+theme_drag_data_received_cb (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x, gint y,
+ GtkSelectionData *selection_data,
+ guint info, guint time,
+ AppearanceData *data)
+{
+ gchar **uris;
+
+ if (!(info == TARGET_URI_LIST || info == TARGET_NS_URL))
+ return;
+
+ uris = g_uri_list_extract_uris ((gchar *) gtk_selection_data_get_data (selection_data));
+
+ if (uris != NULL && uris[0] != NULL) {
+ GFile *f = g_file_new_for_uri (uris[0]);
+
+ mate_theme_install (f,
+ GTK_WINDOW (appearance_capplet_get_widget (data, "appearance_window")));
+ g_object_unref (f);
+ }
+
+ g_strfreev (uris);
+}
+
+static void background_or_font_changed(MateConfEngine* conf, guint cnxn_id, MateConfEntry* entry, AppearanceData* data)
+{
+ theme_message_area_update(data);
+}
+
+void themes_init(AppearanceData* data)
+{
+ GtkWidget *w, *del_button;
+ GList *theme_list, *l;
+ GtkListStore *theme_store;
+ GtkTreeModel *sort_model;
+ MateThemeMetaInfo *meta_theme = NULL;
+ GtkIconView *icon_view;
+ GtkCellRenderer *renderer;
+ GtkSettings *settings;
+ char *url;
+
+ /* initialise some stuff */
+ mate_theme_init ();
+ mate_wm_manager_init ();
+
+ data->revert_application_font = NULL;
+ data->revert_documents_font = NULL;
+ data->revert_desktop_font = NULL;
+ data->revert_windowtitle_font = NULL;
+ data->revert_monospace_font = NULL;
+ data->theme_save_dialog = NULL;
+ data->theme_message_area = NULL;
+ data->theme_info_icon = NULL;
+ data->theme_error_icon = NULL;
+ data->theme_custom = mate_theme_meta_info_new ();
+ data->theme_icon = gdk_pixbuf_new_from_file (MATECC_PIXMAP_DIR "/theme-thumbnailing.png", NULL);
+ data->theme_store = theme_store =
+ gtk_list_store_new (NUM_COLS, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING);
+
+ /* set up theme list */
+ theme_list = mate_theme_meta_info_find_all ();
+ mate_theme_info_register_theme_change ((ThemeChangedCallback) theme_changed_on_disk_cb, data);
+
+ data->theme_custom = theme_load_from_mateconf (data->client);
+ data->theme_custom->name = g_strdup (CUSTOM_THEME_NAME);
+ data->theme_custom->readable_name = g_strdup_printf ("<i>%s</i>", _("Custom"));
+
+ for (l = theme_list; l; l = l->next) {
+ MateThemeMetaInfo *info = l->data;
+
+ gtk_list_store_insert_with_values (theme_store, NULL, 0,
+ COL_LABEL, info->readable_name,
+ COL_NAME, info->name,
+ COL_THUMBNAIL, data->theme_icon,
+ -1);
+
+ if (!meta_theme && theme_is_equal (data->theme_custom, info))
+ meta_theme = info;
+ }
+
+ if (!meta_theme) {
+ /* add custom theme */
+ meta_theme = data->theme_custom;
+
+ gtk_list_store_insert_with_values (theme_store, NULL, 0,
+ COL_LABEL, meta_theme->readable_name,
+ COL_NAME, meta_theme->name,
+ COL_THUMBNAIL, data->theme_icon,
+ -1);
+
+ theme_thumbnail_generate (meta_theme, data);
+ }
+
+ theme_list = g_list_sort (theme_list, (GCompareFunc) theme_list_sort_func);
+
+ g_list_foreach (theme_list, (GFunc) theme_thumbnail_generate, data);
+ g_list_free (theme_list);
+
+ icon_view = GTK_ICON_VIEW (appearance_capplet_get_widget (data, "theme_list"));
+
+ renderer = gtk_cell_renderer_pixbuf_new ();
+ g_object_set (renderer, "xpad", 5, "ypad", 5,
+ "xalign", 0.5, "yalign", 1.0, NULL);
+ gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (icon_view), renderer, FALSE);
+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (icon_view), renderer,
+ "pixbuf", COL_THUMBNAIL, NULL);
+
+ renderer = gtk_cell_renderer_text_new ();
+ g_object_set (renderer, "alignment", PANGO_ALIGN_CENTER,
+ "wrap-mode", PANGO_WRAP_WORD_CHAR,
+ "wrap-width", gtk_icon_view_get_item_width (icon_view),
+ "width", gtk_icon_view_get_item_width (icon_view),
+ "xalign", 0.0, "yalign", 0.0, NULL);
+ gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (icon_view), renderer, FALSE);
+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (icon_view), renderer,
+ "markup", COL_LABEL, NULL);
+
+ sort_model = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (theme_store));
+ gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (sort_model), COL_LABEL, theme_store_sort_func, NULL, NULL);
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort_model), COL_LABEL, GTK_SORT_ASCENDING);
+ gtk_icon_view_set_model (icon_view, GTK_TREE_MODEL (sort_model));
+
+ g_signal_connect (icon_view, "selection-changed", (GCallback) theme_selection_changed_cb, data);
+ g_signal_connect_after (icon_view, "realize", (GCallback) theme_select_name, meta_theme->name);
+
+ w = appearance_capplet_get_widget (data, "theme_install");
+ gtk_button_set_image (GTK_BUTTON (w),
+ gtk_image_new_from_stock (GTK_STOCK_OPEN, GTK_ICON_SIZE_BUTTON));
+ g_signal_connect (w, "clicked", (GCallback) theme_install_cb, data);
+
+ w = appearance_capplet_get_widget (data, "theme_save");
+ gtk_button_set_image (GTK_BUTTON (w),
+ gtk_image_new_from_stock (GTK_STOCK_SAVE_AS, GTK_ICON_SIZE_BUTTON));
+ g_signal_connect (w, "clicked", (GCallback) theme_save_cb, data);
+
+ w = appearance_capplet_get_widget (data, "theme_custom");
+ gtk_button_set_image (GTK_BUTTON (w),
+ gtk_image_new_from_stock (GTK_STOCK_EDIT, GTK_ICON_SIZE_BUTTON));
+ g_signal_connect (w, "clicked", (GCallback) theme_custom_cb, data);
+
+ del_button = appearance_capplet_get_widget (data, "theme_delete");
+ g_signal_connect (del_button, "clicked", (GCallback) theme_delete_cb, data);
+
+ w = appearance_capplet_get_widget (data, "theme_vbox");
+ gtk_drag_dest_set (w, GTK_DEST_DEFAULT_ALL,
+ drop_types, G_N_ELEMENTS (drop_types),
+ GDK_ACTION_COPY | GDK_ACTION_LINK | GDK_ACTION_MOVE);
+ g_signal_connect (w, "drag-data-received", (GCallback) theme_drag_data_received_cb, data);
+ if (is_locked_down (data->client))
+ gtk_widget_set_sensitive (w, FALSE);
+
+ w = appearance_capplet_get_widget (data, "more_themes_linkbutton");
+ url = mateconf_client_get_string (data->client, MORE_THEMES_URL_KEY, NULL);
+ if (url != NULL && url[0] != '\0') {
+ gtk_link_button_set_uri (GTK_LINK_BUTTON (w), url);
+ gtk_widget_show (w);
+ } else {
+ gtk_widget_hide (w);
+ }
+ g_free (url);
+
+ /* listen to mateconf changes, too */
+ mateconf_client_add_dir (data->client, "/apps/marco/general", MATECONF_CLIENT_PRELOAD_NONE, NULL);
+ mateconf_client_add_dir (data->client, "/desktop/mate/interface", MATECONF_CLIENT_PRELOAD_NONE, NULL);
+ mateconf_client_notify_add (data->client, MARCO_THEME_KEY, (MateConfClientNotifyFunc) theme_mateconf_changed, data, NULL, NULL);
+ mateconf_client_notify_add (data->client, CURSOR_THEME_KEY, (MateConfClientNotifyFunc) theme_mateconf_changed, data, NULL, NULL);
+#ifdef HAVE_XCURSOR
+ mateconf_client_notify_add (data->client, CURSOR_SIZE_KEY, (MateConfClientNotifyFunc) theme_mateconf_changed, data, NULL, NULL);
+#endif
+ mateconf_client_notify_add (data->client, BACKGROUND_KEY, (MateConfClientNotifyFunc) background_or_font_changed, data, NULL, NULL);
+ mateconf_client_notify_add (data->client, APPLICATION_FONT_KEY, (MateConfClientNotifyFunc) background_or_font_changed, data, NULL, NULL);
+ mateconf_client_notify_add (data->client, DOCUMENTS_FONT_KEY, (MateConfClientNotifyFunc) background_or_font_changed, data, NULL, NULL);
+ mateconf_client_notify_add (data->client, DESKTOP_FONT_KEY, (MateConfClientNotifyFunc) background_or_font_changed, data, NULL, NULL);
+ mateconf_client_notify_add (data->client, WINDOWTITLE_FONT_KEY, (MateConfClientNotifyFunc) background_or_font_changed, data, NULL, NULL);
+ mateconf_client_notify_add (data->client, MONOSPACE_FONT_KEY, (MateConfClientNotifyFunc) background_or_font_changed, data, NULL, NULL);
+
+ settings = gtk_settings_get_default ();
+ g_signal_connect (settings, "notify::gtk-color-scheme", (GCallback) theme_setting_changed_cb, data);
+ g_signal_connect (settings, "notify::gtk-theme-name", (GCallback) theme_setting_changed_cb, data);
+ g_signal_connect (settings, "notify::gtk-icon-theme-name", (GCallback) theme_setting_changed_cb, data);
+
+ /* monitor individual font choice buttons, so
+ "revert font" option (if any) can be cleared */
+ w = appearance_capplet_get_widget (data, "application_font");
+ g_signal_connect (w, "font_set", (GCallback) custom_font_cb, data);
+ w = appearance_capplet_get_widget (data, "document_font");
+ g_signal_connect (w, "font_set", (GCallback) custom_font_cb, data);
+ w = appearance_capplet_get_widget (data, "desktop_font");
+ g_signal_connect (w, "font_set", (GCallback) custom_font_cb, data);
+ w = appearance_capplet_get_widget (data, "window_title_font");
+ g_signal_connect (w, "font_set", (GCallback) custom_font_cb, data);
+ w = appearance_capplet_get_widget (data, "monospace_font");
+ g_signal_connect (w, "font_set", (GCallback) custom_font_cb, data);
+}
+
+void
+themes_shutdown (AppearanceData *data)
+{
+ mate_theme_meta_info_free (data->theme_custom);
+
+ if (data->theme_icon)
+ g_object_unref (data->theme_icon);
+ if (data->theme_save_dialog)
+ gtk_widget_destroy (data->theme_save_dialog);
+ g_free (data->revert_application_font);
+ g_free (data->revert_documents_font);
+ g_free (data->revert_desktop_font);
+ g_free (data->revert_windowtitle_font);
+ g_free (data->revert_monospace_font);
+}
diff --git a/capplets/appearance/appearance-themes.h b/capplets/appearance/appearance-themes.h
new file mode 100644
index 00000000..6d1c59ff
--- /dev/null
+++ b/capplets/appearance/appearance-themes.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2007 The MATE Foundation
+ * Written by Thomas Wood <[email protected]>
+ * All Rights Reserved
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+void themes_init(AppearanceData* data);
+void themes_shutdown(AppearanceData* data);
diff --git a/capplets/appearance/appearance.h b/capplets/appearance/appearance.h
new file mode 100644
index 00000000..3658ea0f
--- /dev/null
+++ b/capplets/appearance/appearance.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2007 The MATE Foundation
+ * Written by Thomas Wood <[email protected]>
+ * All Rights Reserved
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <mateconf/mateconf-client.h>
+#include <libmateui/mate-desktop-thumbnail.h>
+
+#include "mate-theme-info.h"
+
+#define APPEARANCE_KEY_DIR "/apps/control-center/appearance"
+#define MORE_THEMES_URL_KEY APPEARANCE_KEY_DIR "/more_themes_url"
+#define MORE_BACKGROUNDS_URL_KEY APPEARANCE_KEY_DIR "/more_backgrounds_url"
+
+typedef struct {
+ MateConfClient* client;
+ GtkBuilder* ui;
+ MateDesktopThumbnailFactory* thumb_factory;
+ gulong screen_size_handler;
+ gulong screen_monitors_handler;
+
+ /* desktop */
+ GHashTable* wp_hash;
+ gboolean wp_update_mateconf;
+ GtkIconView* wp_view;
+ GtkTreeModel* wp_model;
+ GtkWidget* wp_scpicker;
+ GtkWidget* wp_pcpicker;
+ GtkWidget* wp_style_menu;
+ GtkWidget* wp_color_menu;
+ GtkWidget* wp_rem_button;
+ GtkFileChooser* wp_filesel;
+ GtkWidget* wp_image;
+ GSList* wp_uris;
+ gint frame;
+ gint thumb_width;
+ gint thumb_height;
+
+ /* font */
+ GtkWidget* font_details;
+ GSList* font_groups;
+
+ /* themes */
+ GtkListStore* theme_store;
+ MateThemeMetaInfo* theme_custom;
+ GdkPixbuf* theme_icon;
+ GtkWidget* theme_save_dialog;
+ GtkWidget* theme_message_area;
+ GtkWidget* theme_message_label;
+ GtkWidget* apply_background_button;
+ GtkWidget* revert_font_button;
+ GtkWidget* apply_font_button;
+ GtkWidget* install_button;
+ GtkWidget* theme_info_icon;
+ GtkWidget* theme_error_icon;
+ gchar* revert_application_font;
+ gchar* revert_documents_font;
+ gchar* revert_desktop_font;
+ gchar* revert_windowtitle_font;
+ gchar* revert_monospace_font;
+
+ /* style */
+ GdkPixbuf* gtk_theme_icon;
+ GdkPixbuf* window_theme_icon;
+ GdkPixbuf* icon_theme_icon;
+ GtkWidget* style_message_area;
+ GtkWidget* style_message_label;
+ GtkWidget* style_install_button;
+} AppearanceData;
+
+#define appearance_capplet_get_widget(x, y) (GtkWidget*) gtk_builder_get_object(x->ui, y)
diff --git a/capplets/appearance/data/Makefile.am b/capplets/appearance/data/Makefile.am
new file mode 100644
index 00000000..987213fb
--- /dev/null
+++ b/capplets/appearance/data/Makefile.am
@@ -0,0 +1,62 @@
+
+gtkbuilderdir = $(pkgdatadir)/ui
+dist_gtkbuilder_DATA = appearance.ui
+
+pixmapdir = $(pkgdatadir)/pixmaps
+dist_pixmap_DATA = \
+ subpixel-bgr.png \
+ subpixel-rgb.png \
+ subpixel-vbgr.png \
+ subpixel-vrgb.png \
+ theme-thumbnailing.png \
+ gtk-theme-thumbnailing.png \
+ window-theme-thumbnailing.png \
+ icon-theme-thumbnailing.png \
+ mouse-cursor-normal.png \
+ mouse-cursor-normal-large.png \
+ mouse-cursor-white.png \
+ mouse-cursor-white-large.png
+
+cursorfontdir = $(datadir)/mate/cursor-fonts
+dist_cursorfont_DATA = \
+ cursor-large.pcf \
+ cursor-white.pcf \
+ cursor-large-white.pcf
+
+@INTLTOOL_DESKTOP_RULE@
+
+desktopdir = $(datadir)/applications
+desktop_in_files = \
+ mate-appearance-properties.desktop.in \
+ mate-theme-installer.desktop.in
+desktop_DATA = $(desktop_in_files:.desktop.in=.desktop)
+
+
+
+
+@INTLTOOL_XML_RULE@
+
+xml_in_files = \
+ mate-theme-package.xml.in
+
+mimedir = $(datadir)/mime/packages
+mime_DATA = $(xml_in_files:.xml.in=.xml)
+
+
+install-data-hook:
+if ENABLE_UPDATE_MIMEDB
+ $(UPDATE_MIME_DATABASE) "$(DESTDIR)$(datadir)/mime"
+endif
+
+uninstall-hook:
+if ENABLE_UPDATE_MIMEDB
+ $(UPDATE_MIME_DATABASE) "$(DESTDIR)$(datadir)/mime"
+endif
+
+
+EXTRA_DIST = $(xml_in_files)
+
+
+CLEANFILES = $(desktop_in_files) $(desktop_DATA) $(mime_DATA)
+
+-include $(top_srcdir)/git.mk
diff --git a/capplets/appearance/data/Makefile.in b/capplets/appearance/data/Makefile.in
new file mode 100644
index 00000000..84174029
--- /dev/null
+++ b/capplets/appearance/data/Makefile.in
@@ -0,0 +1,660 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = capplets/appearance/data
+DIST_COMMON = $(dist_cursorfont_DATA) $(dist_gtkbuilder_DATA) \
+ $(dist_pixmap_DATA) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in \
+ $(srcdir)/mate-appearance-properties.desktop.in.in \
+ $(srcdir)/mate-theme-installer.desktop.in.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/intltool.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/mate-doc-utils.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES = mate-appearance-properties.desktop.in \
+ mate-theme-installer.desktop.in
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+SOURCES =
+DIST_SOURCES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__installdirs = "$(DESTDIR)$(desktopdir)" \
+ "$(DESTDIR)$(cursorfontdir)" "$(DESTDIR)$(gtkbuilderdir)" \
+ "$(DESTDIR)$(pixmapdir)" "$(DESTDIR)$(mimedir)"
+DATA = $(desktop_DATA) $(dist_cursorfont_DATA) $(dist_gtkbuilder_DATA) \
+ $(dist_pixmap_DATA) $(mime_DATA)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+ALL_LINGUAS = @ALL_LINGUAS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+APP_INDICATOR_CFLAGS = @APP_INDICATOR_CFLAGS@
+APP_INDICATOR_LIBS = @APP_INDICATOR_LIBS@
+AR = @AR@
+AT_CAPPLET_CFLAGS = @AT_CAPPLET_CFLAGS@
+AT_CAPPLET_LIBS = @AT_CAPPLET_LIBS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CAPPLET_CFLAGS = @CAPPLET_CFLAGS@
+CAPPLET_LIBS = @CAPPLET_LIBS@
+CATALOGS = @CATALOGS@
+CATOBJEXT = @CATOBJEXT@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DATADIRNAME = @DATADIRNAME@
+DBUS_CFLAGS = @DBUS_CFLAGS@
+DBUS_LIBS = @DBUS_LIBS@
+DEFAULT_APPLICATIONS_CAPPLET_CFLAGS = @DEFAULT_APPLICATIONS_CAPPLET_CFLAGS@
+DEFAULT_APPLICATIONS_CAPPLET_LIBS = @DEFAULT_APPLICATIONS_CAPPLET_LIBS@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISABLE_DEPRECATED = @DISABLE_DEPRECATED@
+DISPLAY_CAPPLET_CFLAGS = @DISPLAY_CAPPLET_CFLAGS@
+DISPLAY_CAPPLET_LIBS = @DISPLAY_CAPPLET_LIBS@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOC_USER_FORMATS = @DOC_USER_FORMATS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXTERNAL_LIBSLAB_CFLAGS = @EXTERNAL_LIBSLAB_CFLAGS@
+EXTERNAL_LIBSLAB_LIBS = @EXTERNAL_LIBSLAB_LIBS@
+FGREP = @FGREP@
+FONT_CAPPLET_CFLAGS = @FONT_CAPPLET_CFLAGS@
+FONT_CAPPLET_LIBS = @FONT_CAPPLET_LIBS@
+FONT_VIEWER_CFLAGS = @FONT_VIEWER_CFLAGS@
+FONT_VIEWER_LIBS = @FONT_VIEWER_LIBS@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GIO_CFLAGS = @GIO_CFLAGS@
+GIO_LIBS = @GIO_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GMOFILES = @GMOFILES@
+GMSGFMT = @GMSGFMT@
+GREP = @GREP@
+GSD_DBUS_CFLAGS = @GSD_DBUS_CFLAGS@
+GSD_DBUS_LIBS = @GSD_DBUS_LIBS@
+GTK_ENGINE_DIR = @GTK_ENGINE_DIR@
+HELP_DIR = @HELP_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INSTOBJEXT = @INSTOBJEXT@
+INTLLIBS = @INTLLIBS@
+INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
+INTLTOOL_MERGE = @INTLTOOL_MERGE@
+INTLTOOL_PERL = @INTLTOOL_PERL@
+INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBCANBERRA_GTK_CFLAGS = @LIBCANBERRA_GTK_CFLAGS@
+LIBCANBERRA_GTK_LIBS = @LIBCANBERRA_GTK_LIBS@
+LIBEBOOK_CFLAGS = @LIBEBOOK_CFLAGS@
+LIBEBOOK_LIBS = @LIBEBOOK_LIBS@
+LIBMATEKBDUI_CFLAGS = @LIBMATEKBDUI_CFLAGS@
+LIBMATEKBDUI_LIBS = @LIBMATEKBDUI_LIBS@
+LIBMATEKBD_CFLAGS = @LIBMATEKBD_CFLAGS@
+LIBMATEKBD_LIBS = @LIBMATEKBD_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBSLAB_CFLAGS = @LIBSLAB_CFLAGS@
+LIBSLAB_LIBS = @LIBSLAB_LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MARCO_CFLAGS = @MARCO_CFLAGS@
+MARCO_LIBS = @MARCO_LIBS@
+MATECC_CAPPLETS_CFLAGS = @MATECC_CAPPLETS_CFLAGS@
+MATECC_CAPPLETS_CLEANFILES = @MATECC_CAPPLETS_CLEANFILES@
+MATECC_CAPPLETS_EXTRA_DIST = @MATECC_CAPPLETS_EXTRA_DIST@
+MATECC_CAPPLETS_LIBS = @MATECC_CAPPLETS_LIBS@
+MATECC_CFLAGS = @MATECC_CFLAGS@
+MATECC_LIBS = @MATECC_LIBS@
+MATECC_SHELL_CFLAGS = @MATECC_SHELL_CFLAGS@
+MATECC_SHELL_LIBS = @MATECC_SHELL_LIBS@
+MATECONFTOOL = @MATECONFTOOL@
+MATECONF_SCHEMA_CONFIG_SOURCE = @MATECONF_SCHEMA_CONFIG_SOURCE@
+MATECONF_SCHEMA_FILE_DIR = @MATECONF_SCHEMA_FILE_DIR@
+MATE_DESKTOP_CFLAGS = @MATE_DESKTOP_CFLAGS@
+MATE_DESKTOP_LIBS = @MATE_DESKTOP_LIBS@
+MKDIR_P = @MKDIR_P@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MSGFMT = @MSGFMT@
+MSGFMT_OPTS = @MSGFMT_OPTS@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OMF_DIR = @OMF_DIR@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+POFILES = @POFILES@
+POSUB = @POSUB@
+PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@
+PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@
+RANLIB = @RANLIB@
+SCREENSAVER_LIBS = @SCREENSAVER_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+TYPING_BREAK = @TYPING_BREAK@
+TYPING_CFLAGS = @TYPING_CFLAGS@
+TYPING_LIBS = @TYPING_LIBS@
+UPDATE_MIME_DATABASE = @UPDATE_MIME_DATABASE@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+WARN_CFLAGS = @WARN_CFLAGS@
+XCURSOR_CFLAGS = @XCURSOR_CFLAGS@
+XCURSOR_LIBS = @XCURSOR_LIBS@
+XF86MISC_LIBS = @XF86MISC_LIBS@
+XGETTEXT = @XGETTEXT@
+XINPUT_CFLAGS = @XINPUT_CFLAGS@
+XINPUT_LIBS = @XINPUT_LIBS@
+XMKMF = @XMKMF@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+gtkbuilderdir = $(pkgdatadir)/ui
+dist_gtkbuilder_DATA = appearance.ui
+pixmapdir = $(pkgdatadir)/pixmaps
+dist_pixmap_DATA = \
+ subpixel-bgr.png \
+ subpixel-rgb.png \
+ subpixel-vbgr.png \
+ subpixel-vrgb.png \
+ theme-thumbnailing.png \
+ gtk-theme-thumbnailing.png \
+ window-theme-thumbnailing.png \
+ icon-theme-thumbnailing.png \
+ mouse-cursor-normal.png \
+ mouse-cursor-normal-large.png \
+ mouse-cursor-white.png \
+ mouse-cursor-white-large.png
+
+cursorfontdir = $(datadir)/mate/cursor-fonts
+dist_cursorfont_DATA = \
+ cursor-large.pcf \
+ cursor-white.pcf \
+ cursor-large-white.pcf
+
+desktopdir = $(datadir)/applications
+desktop_in_files = \
+ mate-appearance-properties.desktop.in \
+ mate-theme-installer.desktop.in
+
+desktop_DATA = $(desktop_in_files:.desktop.in=.desktop)
+xml_in_files = \
+ mate-theme-package.xml.in
+
+mimedir = $(datadir)/mime/packages
+mime_DATA = $(xml_in_files:.xml.in=.xml)
+EXTRA_DIST = $(xml_in_files)
+CLEANFILES = $(desktop_in_files) $(desktop_DATA) $(mime_DATA)
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu capplets/appearance/data/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu capplets/appearance/data/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+mate-appearance-properties.desktop.in: $(top_builddir)/config.status $(srcdir)/mate-appearance-properties.desktop.in.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+mate-theme-installer.desktop.in: $(top_builddir)/config.status $(srcdir)/mate-theme-installer.desktop.in.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-desktopDATA: $(desktop_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(desktopdir)" || $(MKDIR_P) "$(DESTDIR)$(desktopdir)"
+ @list='$(desktop_DATA)'; test -n "$(desktopdir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(desktopdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(desktopdir)" || exit $$?; \
+ done
+
+uninstall-desktopDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(desktop_DATA)'; test -n "$(desktopdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(desktopdir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(desktopdir)" && rm -f $$files
+install-dist_cursorfontDATA: $(dist_cursorfont_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(cursorfontdir)" || $(MKDIR_P) "$(DESTDIR)$(cursorfontdir)"
+ @list='$(dist_cursorfont_DATA)'; test -n "$(cursorfontdir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(cursorfontdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(cursorfontdir)" || exit $$?; \
+ done
+
+uninstall-dist_cursorfontDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_cursorfont_DATA)'; test -n "$(cursorfontdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(cursorfontdir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(cursorfontdir)" && rm -f $$files
+install-dist_gtkbuilderDATA: $(dist_gtkbuilder_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(gtkbuilderdir)" || $(MKDIR_P) "$(DESTDIR)$(gtkbuilderdir)"
+ @list='$(dist_gtkbuilder_DATA)'; test -n "$(gtkbuilderdir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(gtkbuilderdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(gtkbuilderdir)" || exit $$?; \
+ done
+
+uninstall-dist_gtkbuilderDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_gtkbuilder_DATA)'; test -n "$(gtkbuilderdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(gtkbuilderdir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(gtkbuilderdir)" && rm -f $$files
+install-dist_pixmapDATA: $(dist_pixmap_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(pixmapdir)" || $(MKDIR_P) "$(DESTDIR)$(pixmapdir)"
+ @list='$(dist_pixmap_DATA)'; test -n "$(pixmapdir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pixmapdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(pixmapdir)" || exit $$?; \
+ done
+
+uninstall-dist_pixmapDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_pixmap_DATA)'; test -n "$(pixmapdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(pixmapdir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(pixmapdir)" && rm -f $$files
+install-mimeDATA: $(mime_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(mimedir)" || $(MKDIR_P) "$(DESTDIR)$(mimedir)"
+ @list='$(mime_DATA)'; test -n "$(mimedir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(mimedir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(mimedir)" || exit $$?; \
+ done
+
+uninstall-mimeDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(mime_DATA)'; test -n "$(mimedir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(mimedir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(mimedir)" && rm -f $$files
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(DATA)
+installdirs:
+ for dir in "$(DESTDIR)$(desktopdir)" "$(DESTDIR)$(cursorfontdir)" "$(DESTDIR)$(gtkbuilderdir)" "$(DESTDIR)$(pixmapdir)" "$(DESTDIR)$(mimedir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-desktopDATA install-dist_cursorfontDATA \
+ install-dist_gtkbuilderDATA install-dist_pixmapDATA \
+ install-mimeDATA
+ @$(NORMAL_INSTALL)
+ $(MAKE) $(AM_MAKEFLAGS) install-data-hook
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-desktopDATA uninstall-dist_cursorfontDATA \
+ uninstall-dist_gtkbuilderDATA uninstall-dist_pixmapDATA \
+ uninstall-mimeDATA
+ @$(NORMAL_INSTALL)
+ $(MAKE) $(AM_MAKEFLAGS) uninstall-hook
+.MAKE: install-am install-data-am install-strip uninstall-am
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+ distclean distclean-generic distclean-libtool distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-data-hook \
+ install-desktopDATA install-dist_cursorfontDATA \
+ install-dist_gtkbuilderDATA install-dist_pixmapDATA \
+ install-dvi install-dvi-am install-exec install-exec-am \
+ install-html install-html-am install-info install-info-am \
+ install-man install-mimeDATA install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am uninstall uninstall-am \
+ uninstall-desktopDATA uninstall-dist_cursorfontDATA \
+ uninstall-dist_gtkbuilderDATA uninstall-dist_pixmapDATA \
+ uninstall-hook uninstall-mimeDATA
+
+
+@INTLTOOL_DESKTOP_RULE@
+
+@INTLTOOL_XML_RULE@
+
+install-data-hook:
+@ENABLE_UPDATE_MIMEDB_TRUE@ $(UPDATE_MIME_DATABASE) "$(DESTDIR)$(datadir)/mime"
+
+uninstall-hook:
+@ENABLE_UPDATE_MIMEDB_TRUE@ $(UPDATE_MIME_DATABASE) "$(DESTDIR)$(datadir)/mime"
+
+-include $(top_srcdir)/git.mk
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/capplets/appearance/data/appearance.ui b/capplets/appearance/data/appearance.ui
new file mode 100644
index 00000000..d97b2371
--- /dev/null
+++ b/capplets/appearance/data/appearance.ui
@@ -0,0 +1,2603 @@
+<?xml version="1.0"?>
+<interface>
+ <requires lib="gtk+" version="2.16"/>
+ <!-- interface-naming-policy toplevel-contextual -->
+ <object class="GtkDialog" id="render_details">
+ <property name="border_width">5</property>
+ <property name="title" translatable="yes">Font Rendering Details</property>
+ <property name="resizable">False</property>
+ <property name="type_hint">dialog</property>
+ <property name="has_separator">False</property>
+ <child internal-child="vbox">
+ <object class="GtkVBox" id="dialog-vbox1">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">2</property>
+ <child>
+ <object class="GtkVBox" id="vbox7">
+ <property name="visible">True</property>
+ <property name="border_width">5</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">18</property>
+ <child>
+ <object class="GtkAlignment" id="alignment5">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="xscale">0</property>
+ <child>
+ <object class="GtkHBox" id="hbox_resolution">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="label11">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">R_esolution:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">dpi_spinner</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox20">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkSpinButton" id="dpi_spinner">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="climb_rate">1</property>
+ </object>
+ <packing>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label16">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">dots per inch</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox8">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel" id="label8">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Smoothing</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment20">
+ <property name="visible">True</property>
+ <property name="top_padding">6</property>
+ <property name="left_padding">12</property>
+ <child>
+ <object class="GtkTable" id="table5">
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkVBox" id="vbox12">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">3</property>
+ <child>
+ <object class="GtkRadioButton" id="antialias_none_radio">
+ <property name="label" translatable="yes">_None</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment6">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkDrawingArea" id="antialias_none_sample">
+ <property name="visible">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox13">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">3</property>
+ <child>
+ <object class="GtkRadioButton" id="antialias_grayscale_radio">
+ <property name="label" translatable="yes">Gra_yscale</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">antialias_none_radio</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment7">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkDrawingArea" id="antialias_grayscale_sample">
+ <property name="visible">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox14">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">3</property>
+ <child>
+ <object class="GtkRadioButton" id="antialias_subpixel_radio">
+ <property name="label" translatable="yes">Sub_pixel (LCDs)</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">antialias_none_radio</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment8">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkDrawingArea" id="antialias_subpixel_sample">
+ <property name="visible">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox9">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel" id="label9">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes" comments="font hinting">Hinting</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment21">
+ <property name="visible">True</property>
+ <property name="top_padding">6</property>
+ <property name="left_padding">12</property>
+ <child>
+ <object class="GtkTable" id="table6">
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkVBox" id="vbox15">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">3</property>
+ <child>
+ <object class="GtkRadioButton" id="hint_none_radio">
+ <property name="label" translatable="yes">N_one</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment9">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkDrawingArea" id="hint_none_sample">
+ <property name="visible">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox16">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">3</property>
+ <child>
+ <object class="GtkRadioButton" id="hint_slight_radio">
+ <property name="label" translatable="yes">_Slight</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">hint_none_radio</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment10">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkDrawingArea" id="hint_slight_sample">
+ <property name="visible">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox17">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">3</property>
+ <child>
+ <object class="GtkRadioButton" id="hint_medium_radio">
+ <property name="label" translatable="yes">_Medium</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">hint_none_radio</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment11">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkDrawingArea" id="hint_medium_sample">
+ <property name="visible">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox18">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">3</property>
+ <child>
+ <object class="GtkRadioButton" id="hint_full_radio">
+ <property name="label" translatable="yes">_Full</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">hint_none_radio</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment12">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkDrawingArea" id="hint_full_sample">
+ <property name="visible">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox10">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel" id="label10">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Subpixel Order</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment22">
+ <property name="visible">True</property>
+ <property name="top_padding">6</property>
+ <property name="left_padding">12</property>
+ <child>
+ <object class="GtkTable" id="table7">
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkHBox" id="hbox2">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkRadioButton" id="subpixel_rgb_radio">
+ <property name="label" translatable="yes" comments="pixel order red, green, blue">_RGB</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkImage" id="subpixel_rgb_image">
+ <property name="visible">True</property>
+ <property name="stock">gtk-missing-image</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox_bgr">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkRadioButton" id="subpixel_bgr_radio">
+ <property name="label" translatable="yes" comments="pixel order blue, green, red">_BGR</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">subpixel_rgb_radio</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkImage" id="subpixel_bgr_image">
+ <property name="visible">True</property>
+ <property name="stock">gtk-missing-image</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox_rgb">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkRadioButton" id="subpixel_vrgb_radio">
+ <property name="label" translatable="yes" comments="vertical hinting, pixel order red, green, blue">_VRGB</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">subpixel_rgb_radio</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkImage" id="subpixel_vrgb_image">
+ <property name="visible">True</property>
+ <property name="stock">gtk-missing-image</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox5">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkRadioButton" id="subpixel_vbgr_radio">
+ <property name="label" translatable="yes" comments="vertical hinting, pixel order blue, green, red">VB_GR</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">subpixel_rgb_radio</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkImage" id="subpixel_vbgr_image">
+ <property name="visible">True</property>
+ <property name="stock">gtk-missing-image</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <object class="GtkHButtonBox" id="dialog-action_area1">
+ <property name="visible">True</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="button3">
+ <property name="label">gtk-close</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-7">button3</action-widget>
+ </action-widgets>
+ </object>
+ <object class="GtkDialog" id="appearance_window">
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="border_width">5</property>
+ <property name="title" translatable="yes">Appearance Preferences</property>
+ <property name="type_hint">dialog</property>
+ <property name="has_separator">False</property>
+ <child internal-child="vbox">
+ <object class="GtkVBox" id="dialog-vbox2">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">2</property>
+ <child>
+ <object class="GtkNotebook" id="main_notebook">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="border_width">5</property>
+ <child>
+ <object class="GtkVBox" id="theme_vbox">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="border_width">12</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkVBox" id="theme_list_vbox">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkScrolledWindow" id="scrolledwindow1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="hscrollbar_policy">never</property>
+ <property name="vscrollbar_policy">automatic</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkIconView" id="theme_list">
+ <property name="width_request">1</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="selection_mode">browse</property>
+ <property name="item_width">138</property>
+ <property name="spacing">3</property>
+ <property name="row_spacing">18</property>
+ <property name="column_spacing">18</property>
+ <property name="margin">18</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHButtonBox" id="hbuttonbox1">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="spacing">6</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="theme_delete">
+ <property name="label">gtk-delete</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="theme_save">
+ <property name="label" translatable="yes">Save _As...</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="theme_custom">
+ <property name="label" translatable="yes">C_ustomize...</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="theme_install">
+ <property name="label" translatable="yes">_Install...</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox_more_themes">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkLinkButton" id="more_themes_linkbutton">
+ <property name="label" translatable="yes">Get more themes online</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="no_show_all">True</property>
+ <property name="has_tooltip">True</property>
+ <property name="relief">none</property>
+ <property name="uri">http://gnome-look.org/</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label" translatable="yes">Theme</property>
+ </object>
+ <packing>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="background_vbox">
+ <property name="visible">True</property>
+ <property name="border_width">12</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkVBox" id="vbox4">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkHBox" id="wp_hbox">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkScrolledWindow" id="scrolledwindow2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">never</property>
+ <property name="vscrollbar_policy">automatic</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkIconView" id="wp_view">
+ <property name="width_request">1</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="selection_mode">browse</property>
+ <property name="row_spacing">3</property>
+ <property name="column_spacing">3</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox8">
+ <property name="visible">True</property>
+ <property name="spacing">24</property>
+ <child>
+ <object class="GtkHBox" id="hbox_style">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="label22">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Style:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">wp_style_menu</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBox" id="wp_style_menu">
+ <property name="visible">True</property>
+ <property name="model">wp_style_liststore</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderertext1"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="wp_colors_box">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="label25">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">C_olors:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">wp_color_menu</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox_color_menu">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkComboBox" id="wp_color_menu">
+ <property name="visible">True</property>
+ <property name="model">wp_color_liststore</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderertext2"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkColorButton" id="wp_pcpicker">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="color">#000000000000</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="wp_pcpicker-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes">Open a dialog to specify the color</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkColorButton" id="wp_scpicker">
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="color">#000000000000</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="wp_scpicker-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes">Open a dialog to specify the color</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox_get_more">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkLinkButton" id="more_backgrounds_linkbutton">
+ <property name="label" translatable="yes">Get more backgrounds online</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="no_show_all">True</property>
+ <property name="relief">none</property>
+ <property name="uri">http://gnome-look.org/</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHButtonBox" id="hbuttonbox_add">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <property name="homogeneous">True</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="wp_add_button">
+ <property name="label" translatable="yes">_Add...</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="wp_rem_button">
+ <property name="label">gtk-remove</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="label27">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label" translatable="yes">Background</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="fonts_vbox">
+ <property name="visible">True</property>
+ <property name="border_width">12</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">18</property>
+ <child>
+ <object class="GtkTable" id="table2">
+ <property name="visible">True</property>
+ <property name="n_rows">5</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkFontButton" id="document_font">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_font">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label32">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Document font:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">document_font</property>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFontButton" id="desktop_font">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_font">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFontButton" id="window_title_font">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_font">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFontButton" id="monospace_font">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_font">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label31">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Des_ktop font:</property>
+ <property name="use_underline">True</property>
+ <property name="justify">right</property>
+ <property name="mnemonic_widget">desktop_font</property>
+ </object>
+ <packing>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label30">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Window title font:</property>
+ <property name="use_underline">True</property>
+ <property name="justify">right</property>
+ <property name="mnemonic_widget">window_title_font</property>
+ </object>
+ <packing>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label29">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Fixed width font:</property>
+ <property name="use_underline">True</property>
+ <property name="justify">right</property>
+ <property name="mnemonic_widget">monospace_font</property>
+ </object>
+ <packing>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFontButton" id="application_font">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_font">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label28">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Application font:</property>
+ <property name="use_underline">True</property>
+ <property name="justify">right</property>
+ <property name="mnemonic_widget">application_font</property>
+ </object>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox6">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label33">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Rendering</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment1">
+ <property name="visible">True</property>
+ <property name="left_padding">12</property>
+ <child>
+ <object class="GtkTable" id="font_render_frame">
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkVBox" id="vbox21">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkRadioButton" id="subpixel_radio">
+ <property name="label" translatable="yes">Sub_pixel smoothing (LCDs)</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">monochrome_radio</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment13">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkDrawingArea" id="subpixel_sample">
+ <property name="visible">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox20">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkRadioButton" id="best_contrast_radio">
+ <property name="label" translatable="yes">Best co_ntrast</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">monochrome_radio</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment4">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkDrawingArea" id="best_contrast_sample">
+ <property name="visible">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox19">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkRadioButton" id="best_shapes_radio">
+ <property name="label" translatable="yes">Best _shapes</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">monochrome_radio</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment3">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkDrawingArea" id="best_shapes_sample">
+ <property name="visible">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox11">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkRadioButton" id="monochrome_radio">
+ <property name="label" translatable="yes">_Monochrome</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment2">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkDrawingArea" id="monochrome_sample">
+ <property name="visible">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHButtonBox" id="hbuttonbox2">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="details_button">
+ <property name="label" translatable="yes">D_etails...</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="label34">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label" translatable="yes">Fonts</property>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <object class="GtkHButtonBox" id="dialog-action_area2">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="help_button">
+ <property name="label">gtk-help</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ <property name="secondary">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="close_button">
+ <property name="label">gtk-close</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-11">help_button</action-widget>
+ <action-widget response="-7">close_button</action-widget>
+ </action-widgets>
+ </object>
+ <object class="GtkListStore" id="wp_style_liststore">
+ <columns>
+ <!-- column-name column1 -->
+ <column type="gchararray"/>
+ </columns>
+ <data>
+ <row>
+ <col id="0" translatable="yes">Tile</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">Zoom</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">Center</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">Scale</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">Stretch</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">Span</col>
+ </row>
+ </data>
+ </object>
+ <object class="GtkListStore" id="wp_color_liststore">
+ <columns>
+ <!-- column-name gchararray1 -->
+ <column type="gchararray"/>
+ </columns>
+ <data>
+ <row>
+ <col id="0" translatable="yes">Solid color</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">Horizontal gradient</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">Vertical gradient</col>
+ </row>
+ </data>
+ </object>
+ <object class="GtkListStore" id="toolbar_style_liststore">
+ <columns>
+ <!-- column-name gchararray1 -->
+ <column type="gchararray"/>
+ </columns>
+ <data>
+ <row>
+ <col id="0" translatable="yes">Text below items</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">Text beside items</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">Icons only</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">Text only</col>
+ </row>
+ </data>
+ </object>
+ <object class="GtkDialog" id="theme_details">
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="border_width">5</property>
+ <property name="title" translatable="yes">Customize Theme</property>
+ <property name="window_position">center-on-parent</property>
+ <property name="type_hint">dialog</property>
+ <property name="has_separator">False</property>
+ <child internal-child="vbox">
+ <object class="GtkVBox" id="dialog-vbox4">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">2</property>
+ <child>
+ <object class="GtkNotebook" id="notebook2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="border_width">5</property>
+ <child>
+ <object class="GtkVBox" id="vbox27">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="border_width">12</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkVBox" id="gtk_themes_vbox">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkScrolledWindow" id="scrolledwindow3">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="hscrollbar_policy">never</property>
+ <property name="vscrollbar_policy">automatic</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkTreeView" id="gtk_themes_list">
+ <property name="height_request">300</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="headers_visible">False</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHButtonBox" id="hbuttonbox3">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="spacing">6</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="gtk_themes_delete">
+ <property name="label">gtk-delete</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="label41">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label" translatable="yes">Controls</property>
+ </object>
+ <packing>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox2">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="border_width">12</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">18</property>
+ <child>
+ <object class="GtkHBox" id="color_scheme_message_hbox">
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkImage" id="image2">
+ <property name="visible">True</property>
+ <property name="stock">gtk-dialog-info</property>
+ <property name="icon-size">5</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_warning_color_schemes">
+ <property name="width_request">280</property>
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">The current controls theme does not support color schemes.</property>
+ <property name="wrap">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkTable" id="color_scheme_table">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="n_rows">5</property>
+ <property name="n_columns">3</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">12</property>
+ <child>
+ <object class="GtkColorButton" id="tooltip_fg_color">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ <property name="x_options"></property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkColorButton" id="tooltip_bg_color">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ <property name="x_options"></property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label12">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Tooltips:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">tooltip_bg_color</property>
+ </object>
+ <packing>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkColorButton" id="selected_fg_color">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options"></property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkColorButton" id="text_color">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options"></property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkColorButton" id="fg_color">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options"></property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Selected items:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">selected_bg_color</property>
+ </object>
+ <packing>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkColorButton" id="selected_bg_color">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options"></property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkColorButton" id="base_color">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options"></property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkColorButton" id="bg_color">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options"></property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label13">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Input boxes:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">base_color</property>
+ </object>
+ <packing>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Windows:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">bg_color</property>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label7">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label" translatable="yes">Text</property>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label6">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label" translatable="yes">Background</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHButtonBox" id="hbuttonbox4">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="color_scheme_defaults_button">
+ <property name="label" translatable="yes">_Reset to Defaults</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="label18">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label" translatable="yes">Colors</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox29">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="border_width">12</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkScrolledWindow" id="scrolledwindow5">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="hscrollbar_policy">never</property>
+ <property name="vscrollbar_policy">automatic</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkTreeView" id="window_themes_list">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="headers_visible">False</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHButtonBox" id="hbuttonbox6">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="spacing">6</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="window_themes_delete">
+ <property name="label">gtk-delete</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="label42">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label" translatable="yes">Window Border</property>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox30">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="border_width">12</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkScrolledWindow" id="scrolledwindow6">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="hscrollbar_policy">never</property>
+ <property name="vscrollbar_policy">automatic</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkTreeView" id="icon_themes_list">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="headers_visible">False</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHButtonBox" id="hbuttonbox7">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="spacing">6</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="icon_themes_delete">
+ <property name="label">gtk-delete</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="label43">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label" translatable="yes">Icons</property>
+ </object>
+ <packing>
+ <property name="position">3</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="cursor_vbox">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="border_width">12</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkHBox" id="cursor_message_hbox">
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="no_show_all">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkImage" id="image3">
+ <property name="visible">True</property>
+ <property name="stock">gtk-dialog-info</property>
+ <property name="icon-size">5</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label5">
+ <property name="width_request">280</property>
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Changing your cursor theme takes effect the next time you log in.</property>
+ <property name="wrap">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="scrolledwindow8">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="hscrollbar_policy">never</property>
+ <property name="vscrollbar_policy">automatic</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkTreeView" id="cursor_themes_list">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="headers_visible">False</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="cursor_size_hbox">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="cursor_size_label">
+ <property name="label" translatable="yes">_Size:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">cursor_size_scale</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox13">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="cursor_size_small_label">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label" translatable="yes">Small</property>
+ <property name="use_markup">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHScale" id="cursor_size_scale">
+ <property name="width_request">100</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="digits">0</property>
+ <property name="draw_value">False</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="cursor_size_large_label">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label" translatable="yes">Large</property>
+ <property name="use_markup">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHButtonBox" id="hbuttonbox9">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="spacing">6</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="cursor_themes_delete">
+ <property name="label">gtk-delete</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="label44">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label" translatable="yes">Pointer</property>
+ </object>
+ <packing>
+ <property name="position">4</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <object class="GtkHButtonBox" id="dialog-action_area4">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="theme_help_button">
+ <property name="label">gtk-help</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="theme_close_button">
+ <property name="label">gtk-close</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-11">theme_help_button</action-widget>
+ <action-widget response="-7">theme_close_button</action-widget>
+ </action-widgets>
+ </object>
+ <object class="GtkDialog" id="theme_save_dialog">
+ <property name="border_width">6</property>
+ <property name="title" translatable="yes">Save Theme As...</property>
+ <property name="modal">True</property>
+ <property name="type_hint">dialog</property>
+ <property name="has_separator">False</property>
+ <child internal-child="vbox">
+ <object class="GtkVBox" id="dialog-vbox3">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">2</property>
+ <child>
+ <object class="GtkTable" id="table3">
+ <property name="visible">True</property>
+ <property name="border_width">6</property>
+ <property name="n_rows">3</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkEntry" id="save_dialog_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="activates_default">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label49">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Name:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">save_dialog_entry</property>
+ </object>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="scrolledwindow4">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">never</property>
+ <property name="vscrollbar_policy">automatic</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkTextView" id="save_dialog_textview">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="wrap_mode">word</property>
+ <property name="accepts_tab">False</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label50">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0</property>
+ <property name="label" translatable="yes">_Description:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">save_dialog_textview</property>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="save_background_checkbutton">
+ <property name="label" translatable="yes">Save _background image</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <object class="GtkHButtonBox" id="dialog-action_area3">
+ <property name="visible">True</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="save_dialog_cancel_button">
+ <property name="label">gtk-cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="save_dialog_save_button">
+ <property name="label">gtk-save</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-6">save_dialog_cancel_button</action-widget>
+ <action-widget response="-5">save_dialog_save_button</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/capplets/appearance/data/cursor-large-white.pcf b/capplets/appearance/data/cursor-large-white.pcf
new file mode 100644
index 00000000..e1d7b631
--- /dev/null
+++ b/capplets/appearance/data/cursor-large-white.pcf
Binary files differ
diff --git a/capplets/appearance/data/cursor-large.pcf b/capplets/appearance/data/cursor-large.pcf
new file mode 100644
index 00000000..6580b33d
--- /dev/null
+++ b/capplets/appearance/data/cursor-large.pcf
Binary files differ
diff --git a/capplets/appearance/data/cursor-white.pcf b/capplets/appearance/data/cursor-white.pcf
new file mode 100644
index 00000000..bc9932c3
--- /dev/null
+++ b/capplets/appearance/data/cursor-white.pcf
Binary files differ
diff --git a/capplets/appearance/data/gtk-theme-thumbnailing.png b/capplets/appearance/data/gtk-theme-thumbnailing.png
new file mode 100644
index 00000000..52065c7f
--- /dev/null
+++ b/capplets/appearance/data/gtk-theme-thumbnailing.png
Binary files differ
diff --git a/capplets/appearance/data/icon-theme-thumbnailing.png b/capplets/appearance/data/icon-theme-thumbnailing.png
new file mode 100644
index 00000000..6ede83f2
--- /dev/null
+++ b/capplets/appearance/data/icon-theme-thumbnailing.png
Binary files differ
diff --git a/capplets/appearance/data/mate-appearance-properties.desktop.in.in b/capplets/appearance/data/mate-appearance-properties.desktop.in.in
new file mode 100644
index 00000000..f6362193
--- /dev/null
+++ b/capplets/appearance/data/mate-appearance-properties.desktop.in.in
@@ -0,0 +1,14 @@
+[Desktop Entry]
+_Name=Appearance
+_Comment=Customize the look of the desktop
+Exec=mate-appearance-properties %F
+Icon=preferences-desktop-theme
+Terminal=false
+Type=Application
+StartupNotify=true
+Categories=MATE;GTK;Settings;DesktopSettings;
+OnlyShowIn=MATE;
+X-MATE-Bugzilla-Bugzilla=MATE
+X-MATE-Bugzilla-Product=mate-control-center
+X-MATE-Bugzilla-Component=Appearance
+X-MATE-Bugzilla-Version=@VERSION@
diff --git a/capplets/appearance/data/mate-theme-installer.desktop.in.in b/capplets/appearance/data/mate-theme-installer.desktop.in.in
new file mode 100644
index 00000000..3bf6aab5
--- /dev/null
+++ b/capplets/appearance/data/mate-theme-installer.desktop.in.in
@@ -0,0 +1,16 @@
+[Desktop Entry]
+_Name=Theme Installer
+_Comment=Installs themes packages for various parts of the desktop
+Exec=mate-appearance-properties -i %u
+Icon=preferences-desktop-theme
+Terminal=false
+Type=Application
+MimeType=application/x-mate-theme-package;
+StartupNotify=true
+Categories=MATE;GTK;
+NoDisplay=true
+OnlyShowIn=MATE;
+X-MATE-Bugzilla-Bugzilla=MATE
+X-MATE-Bugzilla-Product=mate-control-center
+X-MATE-Bugzilla-Component=Appearance
+X-MATE-Bugzilla-Version=@VERSION@
diff --git a/capplets/appearance/data/mate-theme-package.xml.in b/capplets/appearance/data/mate-theme-package.xml.in
new file mode 100644
index 00000000..58cbdf43
--- /dev/null
+++ b/capplets/appearance/data/mate-theme-package.xml.in
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
+ <mime-type type="application/x-mate-theme-package">
+ <sub-class-of type="application/x-compressed-tar"/>
+ <_comment>Mate Theme Package</_comment>
+ <glob pattern="*.gtp"/>
+ </mime-type>
+</mime-info>
+
diff --git a/capplets/appearance/data/mouse-cursor-normal-large.png b/capplets/appearance/data/mouse-cursor-normal-large.png
new file mode 100644
index 00000000..afef4ea8
--- /dev/null
+++ b/capplets/appearance/data/mouse-cursor-normal-large.png
Binary files differ
diff --git a/capplets/appearance/data/mouse-cursor-normal.png b/capplets/appearance/data/mouse-cursor-normal.png
new file mode 100644
index 00000000..1d9351c8
--- /dev/null
+++ b/capplets/appearance/data/mouse-cursor-normal.png
Binary files differ
diff --git a/capplets/appearance/data/mouse-cursor-white-large.png b/capplets/appearance/data/mouse-cursor-white-large.png
new file mode 100644
index 00000000..8f98438a
--- /dev/null
+++ b/capplets/appearance/data/mouse-cursor-white-large.png
Binary files differ
diff --git a/capplets/appearance/data/mouse-cursor-white.png b/capplets/appearance/data/mouse-cursor-white.png
new file mode 100644
index 00000000..2be63acd
--- /dev/null
+++ b/capplets/appearance/data/mouse-cursor-white.png
Binary files differ
diff --git a/capplets/appearance/data/subpixel-bgr.png b/capplets/appearance/data/subpixel-bgr.png
new file mode 100644
index 00000000..7efd2624
--- /dev/null
+++ b/capplets/appearance/data/subpixel-bgr.png
Binary files differ
diff --git a/capplets/appearance/data/subpixel-rgb.png b/capplets/appearance/data/subpixel-rgb.png
new file mode 100644
index 00000000..58ac1eca
--- /dev/null
+++ b/capplets/appearance/data/subpixel-rgb.png
Binary files differ
diff --git a/capplets/appearance/data/subpixel-vbgr.png b/capplets/appearance/data/subpixel-vbgr.png
new file mode 100644
index 00000000..abd8df01
--- /dev/null
+++ b/capplets/appearance/data/subpixel-vbgr.png
Binary files differ
diff --git a/capplets/appearance/data/subpixel-vrgb.png b/capplets/appearance/data/subpixel-vrgb.png
new file mode 100644
index 00000000..6e609060
--- /dev/null
+++ b/capplets/appearance/data/subpixel-vrgb.png
Binary files differ
diff --git a/capplets/appearance/data/theme-thumbnailing.png b/capplets/appearance/data/theme-thumbnailing.png
new file mode 100644
index 00000000..938edb0e
--- /dev/null
+++ b/capplets/appearance/data/theme-thumbnailing.png
Binary files differ
diff --git a/capplets/appearance/data/window-theme-thumbnailing.png b/capplets/appearance/data/window-theme-thumbnailing.png
new file mode 100644
index 00000000..ce3bd1ab
--- /dev/null
+++ b/capplets/appearance/data/window-theme-thumbnailing.png
Binary files differ
diff --git a/capplets/appearance/mate-wp-info.c b/capplets/appearance/mate-wp-info.c
new file mode 100644
index 00000000..5c799eab
--- /dev/null
+++ b/capplets/appearance/mate-wp-info.c
@@ -0,0 +1,87 @@
+/*
+ * Authors: Rodney Dawes <[email protected]>
+ *
+ * Copyright 2003-2006 Novell, Inc. (www.novell.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include <config.h>
+#include <string.h>
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+#include "mate-wp-info.h"
+
+MateWPInfo * mate_wp_info_new (const gchar * uri,
+ MateDesktopThumbnailFactory * thumbs) {
+ MateWPInfo *wp;
+ GFile *file;
+ GFileInfo *info;
+
+ file = g_file_new_for_commandline_arg (uri);
+
+ info = g_file_query_info (file,
+ G_FILE_ATTRIBUTE_STANDARD_NAME ","
+ G_FILE_ATTRIBUTE_STANDARD_SIZE ","
+ G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE ","
+ G_FILE_ATTRIBUTE_TIME_MODIFIED,
+ G_FILE_QUERY_INFO_NONE,
+ NULL, NULL);
+ g_object_unref (file);
+
+ if (info == NULL || g_file_info_get_content_type (info) == NULL) {
+ if (!strcmp (uri, "(none)")) {
+ wp = g_new0 (MateWPInfo, 1);
+
+ wp->mime_type = g_strdup ("image/x-no-data");
+ wp->uri = g_strdup (uri);
+ wp->name = g_strdup (_("No Desktop Background"));
+ wp->size = 0;
+ } else {
+ wp = NULL;
+ }
+ } else {
+ wp = g_new0 (MateWPInfo, 1);
+
+ wp->uri = g_strdup (uri);
+
+ wp->name = g_strdup (g_file_info_get_name (info));
+ if (g_file_info_get_content_type (info) != NULL)
+ wp->mime_type = g_strdup (g_file_info_get_content_type (info));
+ wp->size = g_file_info_get_size (info);
+ wp->mtime = g_file_info_get_attribute_uint64 (info,
+ G_FILE_ATTRIBUTE_TIME_MODIFIED);
+
+ wp->thumburi = mate_desktop_thumbnail_factory_lookup (thumbs,
+ uri,
+ wp->mtime);
+ }
+
+ if (info != NULL)
+ g_object_unref (info);
+
+ return wp;
+}
+
+void mate_wp_info_free (MateWPInfo * info) {
+ if (info == NULL) {
+ return;
+ }
+
+ g_free (info->uri);
+ g_free (info->thumburi);
+ g_free (info->name);
+ g_free (info->mime_type);
+}
diff --git a/capplets/appearance/mate-wp-info.h b/capplets/appearance/mate-wp-info.h
new file mode 100644
index 00000000..95c94f89
--- /dev/null
+++ b/capplets/appearance/mate-wp-info.h
@@ -0,0 +1,45 @@
+/*
+ * Authors: Rodney Dawes <[email protected]>
+ *
+ * Copyright 2003-2006 Novell, Inc. (www.novell.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef _MATE_WP_INFO_H_
+#define _MATE_WP_INFO_H_
+
+#include <glib.h>
+#include <libmateui/mate-desktop-thumbnail.h>
+
+typedef struct _MateWPInfo MateWPInfo;
+
+struct _MateWPInfo {
+ gchar * uri;
+ gchar * thumburi;
+ gchar * name;
+ gchar * mime_type;
+
+ goffset size;
+
+ time_t mtime;
+};
+
+MateWPInfo * mate_wp_info_new (const gchar * uri,
+ MateDesktopThumbnailFactory * thumbs);
+void mate_wp_info_free (MateWPInfo * info);
+
+#endif
+
diff --git a/capplets/appearance/mate-wp-item.c b/capplets/appearance/mate-wp-item.c
new file mode 100644
index 00000000..de9623f1
--- /dev/null
+++ b/capplets/appearance/mate-wp-item.c
@@ -0,0 +1,307 @@
+/*
+ * Authors: Rodney Dawes <[email protected]>
+ *
+ * Copyright 2003-2006 Novell, Inc. (www.novell.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include <config.h>
+
+#include <glib/gi18n.h>
+#include <mateconf/mateconf-client.h>
+#include <string.h>
+#include "mate-wp-item.h"
+
+static MateConfEnumStringPair options_lookup[] = {
+ { MATE_BG_PLACEMENT_CENTERED, "centered" },
+ { MATE_BG_PLACEMENT_FILL_SCREEN, "stretched" },
+ { MATE_BG_PLACEMENT_SCALED, "scaled" },
+ { MATE_BG_PLACEMENT_ZOOMED, "zoom" },
+ { MATE_BG_PLACEMENT_TILED, "wallpaper" },
+ { MATE_BG_PLACEMENT_SPANNED, "spanned" },
+ { 0, NULL }
+};
+
+static MateConfEnumStringPair shade_lookup[] = {
+ { MATE_BG_COLOR_SOLID, "solid" },
+ { MATE_BG_COLOR_H_GRADIENT, "horizontal-gradient" },
+ { MATE_BG_COLOR_V_GRADIENT, "vertical-gradient" },
+ { 0, NULL }
+};
+
+const gchar *wp_item_option_to_string (MateBGPlacement type)
+{
+ return mateconf_enum_to_string (options_lookup, type);
+}
+
+const gchar *wp_item_shading_to_string (MateBGColorType type)
+{
+ return mateconf_enum_to_string (shade_lookup, type);
+}
+
+MateBGPlacement wp_item_string_to_option (const gchar *option)
+{
+ int i = MATE_BG_PLACEMENT_SCALED;
+ mateconf_string_to_enum (options_lookup, option, &i);
+ return i;
+}
+
+MateBGColorType wp_item_string_to_shading (const gchar *shade_type)
+{
+ int i = MATE_BG_COLOR_SOLID;
+ mateconf_string_to_enum (shade_lookup, shade_type, &i);
+ return i;
+}
+
+static void set_bg_properties (MateWPItem *item)
+{
+ if (item->filename)
+ mate_bg_set_filename (item->bg, item->filename);
+
+ mate_bg_set_color (item->bg, item->shade_type, item->pcolor, item->scolor);
+ mate_bg_set_placement (item->bg, item->options);
+}
+
+void mate_wp_item_ensure_mate_bg (MateWPItem *item)
+{
+ if (!item->bg) {
+ item->bg = mate_bg_new ();
+
+ set_bg_properties (item);
+ }
+}
+
+void mate_wp_item_update (MateWPItem *item) {
+ MateConfClient *client;
+ GdkColor color1 = { 0, 0, 0, 0 }, color2 = { 0, 0, 0, 0 };
+ gchar *s;
+
+ client = mateconf_client_get_default ();
+
+ s = mateconf_client_get_string (client, WP_OPTIONS_KEY, NULL);
+ item->options = wp_item_string_to_option (s);
+ g_free (s);
+
+ s = mateconf_client_get_string (client, WP_SHADING_KEY, NULL);
+ item->shade_type = wp_item_string_to_shading (s);
+ g_free (s);
+
+ s = mateconf_client_get_string (client, WP_PCOLOR_KEY, NULL);
+ if (s != NULL) {
+ gdk_color_parse (s, &color1);
+ g_free (s);
+ }
+
+ s = mateconf_client_get_string (client, WP_SCOLOR_KEY, NULL);
+ if (s != NULL) {
+ gdk_color_parse (s, &color2);
+ g_free (s);
+ }
+
+ g_object_unref (client);
+
+ if (item->pcolor != NULL)
+ gdk_color_free (item->pcolor);
+
+ if (item->scolor != NULL)
+ gdk_color_free (item->scolor);
+
+ item->pcolor = gdk_color_copy (&color1);
+ item->scolor = gdk_color_copy (&color2);
+}
+
+MateWPItem * mate_wp_item_new (const gchar * filename,
+ GHashTable * wallpapers,
+ MateDesktopThumbnailFactory * thumbnails) {
+ MateWPItem *item = g_new0 (MateWPItem, 1);
+
+ item->filename = g_strdup (filename);
+ item->fileinfo = mate_wp_info_new (filename, thumbnails);
+
+ if (item->fileinfo != NULL && item->fileinfo->mime_type != NULL &&
+ (g_str_has_prefix (item->fileinfo->mime_type, "image/") ||
+ strcmp (item->fileinfo->mime_type, "application/xml") == 0)) {
+
+ if (g_utf8_validate (item->fileinfo->name, -1, NULL))
+ item->name = g_strdup (item->fileinfo->name);
+ else
+ item->name = g_filename_to_utf8 (item->fileinfo->name, -1, NULL,
+ NULL, NULL);
+
+ mate_wp_item_update (item);
+ mate_wp_item_ensure_mate_bg (item);
+ mate_wp_item_update_description (item);
+
+ g_hash_table_insert (wallpapers, item->filename, item);
+ } else {
+ mate_wp_item_free (item);
+ item = NULL;
+ }
+
+ return item;
+}
+
+void mate_wp_item_free (MateWPItem * item) {
+ if (item == NULL) {
+ return;
+ }
+
+ g_free (item->name);
+ g_free (item->filename);
+ g_free (item->description);
+
+ if (item->pcolor != NULL)
+ gdk_color_free (item->pcolor);
+
+ if (item->scolor != NULL)
+ gdk_color_free (item->scolor);
+
+ mate_wp_info_free (item->fileinfo);
+ if (item->bg)
+ g_object_unref (item->bg);
+
+ gtk_tree_row_reference_free (item->rowref);
+
+ g_free (item);
+}
+
+static GdkPixbuf *
+add_slideshow_frame (GdkPixbuf *pixbuf)
+{
+ GdkPixbuf *sheet, *sheet2;
+ GdkPixbuf *tmp;
+ gint w, h;
+
+ w = gdk_pixbuf_get_width (pixbuf);
+ h = gdk_pixbuf_get_height (pixbuf);
+
+ sheet = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, w, h);
+ gdk_pixbuf_fill (sheet, 0x00000000);
+ sheet2 = gdk_pixbuf_new_subpixbuf (sheet, 1, 1, w - 2, h - 2);
+ gdk_pixbuf_fill (sheet2, 0xffffffff);
+ g_object_unref (sheet2);
+
+ tmp = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, w + 6, h + 6);
+
+ gdk_pixbuf_fill (tmp, 0x00000000);
+ gdk_pixbuf_composite (sheet, tmp, 6, 6, w, h, 6.0, 6.0, 1.0, 1.0, GDK_INTERP_NEAREST, 255);
+ gdk_pixbuf_composite (sheet, tmp, 3, 3, w, h, 3.0, 3.0, 1.0, 1.0, GDK_INTERP_NEAREST, 255);
+ gdk_pixbuf_composite (pixbuf, tmp, 0, 0, w, h, 0.0, 0.0, 1.0, 1.0, GDK_INTERP_NEAREST, 255);
+
+ g_object_unref (sheet);
+
+ return tmp;
+}
+
+GdkPixbuf * mate_wp_item_get_frame_thumbnail (MateWPItem * item,
+ MateDesktopThumbnailFactory * thumbs,
+ int width,
+ int height,
+ gint frame) {
+ GdkPixbuf *pixbuf = NULL;
+
+ set_bg_properties (item);
+
+ if (frame != -1)
+ pixbuf = mate_bg_create_frame_thumbnail (item->bg, thumbs, gdk_screen_get_default (), width, height, frame);
+ else
+ pixbuf = mate_bg_create_thumbnail (item->bg, thumbs, gdk_screen_get_default(), width, height);
+
+ if (pixbuf && mate_bg_changes_with_time (item->bg))
+ {
+ GdkPixbuf *tmp;
+
+ tmp = add_slideshow_frame (pixbuf);
+ g_object_unref (pixbuf);
+ pixbuf = tmp;
+ }
+
+ mate_bg_get_image_size (item->bg, thumbs, width, height, &item->width, &item->height);
+
+ return pixbuf;
+}
+
+
+GdkPixbuf * mate_wp_item_get_thumbnail (MateWPItem * item,
+ MateDesktopThumbnailFactory * thumbs,
+ gint width,
+ gint height) {
+ return mate_wp_item_get_frame_thumbnail (item, thumbs, width, height, -1);
+}
+
+void mate_wp_item_update_description (MateWPItem * item) {
+ g_free (item->description);
+
+ if (!strcmp (item->filename, "(none)")) {
+ item->description = g_strdup (item->name);
+ } else {
+ const gchar *description;
+ gchar *size;
+ gchar *dirname = g_path_get_dirname (item->filename);
+
+ description = NULL;
+ size = NULL;
+
+ if (strcmp (item->fileinfo->mime_type, "application/xml") == 0)
+ {
+ if (mate_bg_changes_with_time (item->bg))
+ description = _("Slide Show");
+ else if (item->width > 0 && item->height > 0)
+ description = _("Image");
+ }
+ else
+ description = g_content_type_get_description (item->fileinfo->mime_type);
+
+ if (mate_bg_has_multiple_sizes (item->bg))
+ size = g_strdup (_("multiple sizes"));
+ else if (item->width > 0 && item->height > 0) {
+ /* translators: x pixel(s) by y pixel(s) */
+ size = g_strdup_printf (_("%d %s by %d %s"),
+ item->width,
+ ngettext ("pixel", "pixels", item->width),
+ item->height,
+ ngettext ("pixel", "pixels", item->height));
+ }
+
+ if (description && size) {
+ /* translators: <b>wallpaper name</b>
+ * mime type, size
+ * Folder: /path/to/file
+ */
+ item->description = g_markup_printf_escaped (_("<b>%s</b>\n"
+ "%s, %s\n"
+ "Folder: %s"),
+ item->name,
+ description,
+ size,
+ dirname);
+ } else {
+ /* translators: <b>wallpaper name</b>
+ * Image missing
+ * Folder: /path/to/file
+ */
+ item->description = g_markup_printf_escaped (_("<b>%s</b>\n"
+ "%s\n"
+ "Folder: %s"),
+ item->name,
+ _("Image missing"),
+ dirname);
+ }
+
+ g_free (size);
+ g_free (dirname);
+ }
+}
diff --git a/capplets/appearance/mate-wp-item.h b/capplets/appearance/mate-wp-item.h
new file mode 100644
index 00000000..1dd726a3
--- /dev/null
+++ b/capplets/appearance/mate-wp-item.h
@@ -0,0 +1,91 @@
+/*
+ * Authors: Rodney Dawes <[email protected]>
+ *
+ * Copyright 2003-2006 Novell, Inc. (www.novell.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include <glib.h>
+#include <gio/gio.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gtk/gtk.h>
+#include <libmateui/mate-desktop-thumbnail.h>
+#include <libmateui/mate-bg.h>
+
+#include "mate-wp-info.h"
+
+#ifndef _MATE_WP_ITEM_H_
+#define _MATE_WP_ITEM_H_
+
+#define WP_PATH_KEY "/desktop/mate/background"
+#define WP_FILE_KEY WP_PATH_KEY "/picture_filename"
+#define WP_OPTIONS_KEY WP_PATH_KEY "/picture_options"
+#define WP_SHADING_KEY WP_PATH_KEY "/color_shading_type"
+#define WP_PCOLOR_KEY WP_PATH_KEY "/primary_color"
+#define WP_SCOLOR_KEY WP_PATH_KEY "/secondary_color"
+
+typedef struct _MateWPItem MateWPItem;
+
+struct _MateWPItem {
+ MateBG *bg;
+
+ gchar * name;
+ gchar * filename;
+ gchar * description;
+ MateBGPlacement options;
+ MateBGColorType shade_type;
+
+ /* Where the Item is in the List */
+ GtkTreeRowReference * rowref;
+
+ /* Real colors */
+ GdkColor * pcolor;
+ GdkColor * scolor;
+
+ MateWPInfo * fileinfo;
+
+ /* Did the user remove us? */
+ gboolean deleted;
+
+ /* Width and Height of the original image */
+ gint width;
+ gint height;
+};
+
+MateWPItem * mate_wp_item_new (const gchar *filename,
+ GHashTable *wallpapers,
+ MateDesktopThumbnailFactory *thumbnails);
+
+void mate_wp_item_free (MateWPItem *item);
+GdkPixbuf * mate_wp_item_get_thumbnail (MateWPItem *item,
+ MateDesktopThumbnailFactory *thumbs,
+ gint width,
+ gint height);
+GdkPixbuf * mate_wp_item_get_frame_thumbnail (MateWPItem *item,
+ MateDesktopThumbnailFactory *thumbs,
+ gint width,
+ gint height,
+ gint frame);
+void mate_wp_item_update (MateWPItem *item);
+void mate_wp_item_update_description (MateWPItem *item);
+void mate_wp_item_ensure_mate_bg (MateWPItem *item);
+
+const gchar *wp_item_option_to_string (MateBGPlacement type);
+const gchar *wp_item_shading_to_string (MateBGColorType type);
+MateBGPlacement wp_item_string_to_option (const gchar *option);
+MateBGColorType wp_item_string_to_shading (const gchar *shade_type);
+
+#endif
diff --git a/capplets/appearance/mate-wp-xml.c b/capplets/appearance/mate-wp-xml.c
new file mode 100644
index 00000000..2157acf7
--- /dev/null
+++ b/capplets/appearance/mate-wp-xml.c
@@ -0,0 +1,451 @@
+/*
+ * Authors: Rodney Dawes <[email protected]>
+ *
+ * Copyright 2003-2006 Novell, Inc. (www.novell.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "appearance.h"
+#include "mate-wp-item.h"
+#include <gio/gio.h>
+#include <string.h>
+#include <libxml/parser.h>
+
+static gboolean mate_wp_xml_get_bool (const xmlNode * parent,
+ const gchar * prop_name) {
+ xmlChar * prop;
+ gboolean ret_val = FALSE;
+
+ g_return_val_if_fail (parent != NULL, FALSE);
+ g_return_val_if_fail (prop_name != NULL, FALSE);
+
+ prop = xmlGetProp ((xmlNode *) parent, (xmlChar*)prop_name);
+ if (prop != NULL) {
+ if (!g_ascii_strcasecmp ((gchar *)prop, "true") || !g_ascii_strcasecmp ((gchar *)prop, "1")) {
+ ret_val = TRUE;
+ } else {
+ ret_val = FALSE;
+ }
+ g_free (prop);
+ }
+
+ return ret_val;
+}
+
+static void mate_wp_xml_set_bool (const xmlNode * parent,
+ const xmlChar * prop_name, gboolean value) {
+ g_return_if_fail (parent != NULL);
+ g_return_if_fail (prop_name != NULL);
+
+ if (value) {
+ xmlSetProp ((xmlNode *) parent, prop_name, (xmlChar *)"true");
+ } else {
+ xmlSetProp ((xmlNode *) parent, prop_name, (xmlChar *)"false");
+ }
+}
+
+static void mate_wp_load_legacy (AppearanceData *data) {
+ FILE * fp;
+ gchar * foo, * filename;
+
+ filename = g_build_filename (g_get_home_dir (), ".mate2",
+ "wallpapers.list", NULL);
+
+ if (g_file_test (filename, G_FILE_TEST_EXISTS)) {
+ if ((fp = fopen (filename, "r")) != NULL) {
+ foo = (gchar *) g_malloc (sizeof (gchar) * 4096);
+ while (fgets (foo, 4096, fp)) {
+ MateWPItem * item;
+
+ if (foo[strlen (foo) - 1] == '\n') {
+ foo[strlen (foo) - 1] = '\0';
+ }
+
+ item = g_hash_table_lookup (data->wp_hash, foo);
+ if (item != NULL) {
+ continue;
+ }
+
+ if (!g_file_test (foo, G_FILE_TEST_EXISTS)) {
+ continue;
+ }
+
+ item = mate_wp_item_new (foo, data->wp_hash, data->thumb_factory);
+ if (item != NULL && item->fileinfo == NULL) {
+ mate_wp_item_free (item);
+ }
+ }
+ fclose (fp);
+ g_free (foo);
+ }
+ }
+
+ g_free (filename);
+}
+
+static void mate_wp_xml_load_xml (AppearanceData *data,
+ const gchar * filename) {
+ xmlDoc * wplist;
+ xmlNode * root, * list, * wpa;
+ xmlChar * nodelang;
+ const gchar * const * syslangs;
+ GdkColor color1, color2;
+ gint i;
+
+ wplist = xmlParseFile (filename);
+
+ if (!wplist)
+ return;
+
+ syslangs = g_get_language_names ();
+
+ root = xmlDocGetRootElement (wplist);
+
+ for (list = root->children; list != NULL; list = list->next) {
+ if (!strcmp ((gchar *)list->name, "wallpaper")) {
+ MateWPItem * wp;
+ gchar *pcolor = NULL, *scolor = NULL;
+ gchar *s;
+ gboolean have_scale = FALSE, have_shade = FALSE;
+
+ wp = g_new0 (MateWPItem, 1);
+
+ wp->deleted = mate_wp_xml_get_bool (list, "deleted");
+
+ for (wpa = list->children; wpa != NULL; wpa = wpa->next) {
+ if (wpa->type == XML_COMMENT_NODE) {
+ continue;
+ } else if (!strcmp ((gchar *)wpa->name, "filename")) {
+ if (wpa->last != NULL && wpa->last->content != NULL) {
+ const char * none = "(none)";
+ gchar *content = g_strstrip ((gchar *)wpa->last->content);
+
+ if (!strcmp (content, none))
+ wp->filename = g_strdup (content);
+ else if (g_utf8_validate (content, -1, NULL) &&
+ g_file_test (content, G_FILE_TEST_EXISTS))
+ wp->filename = g_strdup (content);
+ else
+ wp->filename = g_filename_from_utf8 (content, -1, NULL, NULL, NULL);
+ } else {
+ break;
+ }
+ } else if (!strcmp ((gchar *)wpa->name, "name")) {
+ if (wpa->last != NULL && wpa->last->content != NULL) {
+ nodelang = xmlNodeGetLang (wpa->last);
+
+ if (wp->name == NULL && nodelang == NULL) {
+ wp->name = g_strdup (g_strstrip ((gchar *)wpa->last->content));
+ } else {
+ for (i = 0; syslangs[i] != NULL; i++) {
+ if (!strcmp (syslangs[i], (gchar *)nodelang)) {
+ g_free (wp->name);
+ wp->name = g_strdup (g_strstrip ((gchar *)wpa->last->content));
+ break;
+ }
+ }
+ }
+
+ xmlFree (nodelang);
+ } else {
+ break;
+ }
+ } else if (!strcmp ((gchar *)wpa->name, "options")) {
+ if (wpa->last != NULL) {
+ wp->options = wp_item_string_to_option (g_strstrip ((gchar *)wpa->last->content));
+ have_scale = TRUE;
+ }
+ } else if (!strcmp ((gchar *)wpa->name, "shade_type")) {
+ if (wpa->last != NULL) {
+ wp->shade_type = wp_item_string_to_shading (g_strstrip ((gchar *)wpa->last->content));
+ have_shade = TRUE;
+ }
+ } else if (!strcmp ((gchar *)wpa->name, "pcolor")) {
+ if (wpa->last != NULL) {
+ pcolor = g_strdup (g_strstrip ((gchar *)wpa->last->content));
+ }
+ } else if (!strcmp ((gchar *)wpa->name, "scolor")) {
+ if (wpa->last != NULL) {
+ scolor = g_strdup (g_strstrip ((gchar *)wpa->last->content));
+ }
+ } else if (!strcmp ((gchar *)wpa->name, "text")) {
+ /* Do nothing here, libxml2 is being weird */
+ } else {
+ g_warning ("Unknown Tag: %s", wpa->name);
+ }
+ }
+
+ /* Make sure we don't already have this one and that filename exists */
+ if (wp->filename == NULL ||
+ g_hash_table_lookup (data->wp_hash, wp->filename) != NULL) {
+
+ mate_wp_item_free (wp);
+ g_free (pcolor);
+ g_free (scolor);
+ continue;
+ }
+
+ /* Verify the colors and alloc some GdkColors here */
+ if (!have_scale) {
+ s = mateconf_client_get_string (data->client, WP_OPTIONS_KEY, NULL);
+ wp->options = wp_item_string_to_option (s);
+ g_free (s);
+ }
+
+ if (!have_shade) {
+ s = mateconf_client_get_string (data->client, WP_SHADING_KEY, NULL);
+ wp->shade_type = wp_item_string_to_shading (s);
+ g_free (s);
+ }
+
+ if (pcolor == NULL) {
+ pcolor = mateconf_client_get_string (data->client,
+ WP_PCOLOR_KEY, NULL);
+ }
+ if (scolor == NULL) {
+ scolor = mateconf_client_get_string (data->client,
+ WP_SCOLOR_KEY, NULL);
+ }
+ gdk_color_parse (pcolor, &color1);
+ gdk_color_parse (scolor, &color2);
+ g_free (pcolor);
+ g_free (scolor);
+
+ wp->pcolor = gdk_color_copy (&color1);
+ wp->scolor = gdk_color_copy (&color2);
+
+ if ((wp->filename != NULL &&
+ g_file_test (wp->filename, G_FILE_TEST_EXISTS)) ||
+ !strcmp (wp->filename, "(none)")) {
+ wp->fileinfo = mate_wp_info_new (wp->filename, data->thumb_factory);
+
+ if (wp->name == NULL || !strcmp (wp->filename, "(none)")) {
+ g_free (wp->name);
+ wp->name = g_strdup (wp->fileinfo->name);
+ }
+
+ mate_wp_item_ensure_mate_bg (wp);
+ mate_wp_item_update_description (wp);
+ g_hash_table_insert (data->wp_hash, wp->filename, wp);
+ } else {
+ mate_wp_item_free (wp);
+ wp = NULL;
+ }
+ }
+ }
+ xmlFreeDoc (wplist);
+}
+
+static void mate_wp_file_changed (GFileMonitor *monitor,
+ GFile *file,
+ GFile *other_file,
+ GFileMonitorEvent event_type,
+ AppearanceData *data) {
+ gchar * filename;
+
+ switch (event_type) {
+ case G_FILE_MONITOR_EVENT_CHANGED:
+ case G_FILE_MONITOR_EVENT_CREATED:
+ filename = g_file_get_path (file);
+ mate_wp_xml_load_xml (data, filename);
+ g_free (filename);
+ break;
+ default:
+ break;
+ }
+}
+
+static void mate_wp_xml_add_monitor (GFile *directory,
+ AppearanceData *data) {
+ GFileMonitor *monitor;
+ GError *error = NULL;
+
+ monitor = g_file_monitor_directory (directory,
+ G_FILE_MONITOR_NONE,
+ NULL,
+ &error);
+ if (error != NULL) {
+ gchar *path;
+
+ path = g_file_get_parse_name (directory);
+ g_warning ("Unable to monitor directory %s: %s",
+ path, error->message);
+ g_error_free (error);
+ g_free (path);
+ return;
+ }
+
+ g_signal_connect (monitor, "changed",
+ G_CALLBACK (mate_wp_file_changed),
+ data);
+}
+
+static void mate_wp_xml_load_from_dir (const gchar *path,
+ AppearanceData *data) {
+ GFile *directory;
+ GFileEnumerator *enumerator;
+ GError *error = NULL;
+ GFileInfo *info;
+
+ if (!g_file_test (path, G_FILE_TEST_IS_DIR)) {
+ return;
+ }
+
+ directory = g_file_new_for_path (path);
+ enumerator = g_file_enumerate_children (directory,
+ G_FILE_ATTRIBUTE_STANDARD_NAME,
+ G_FILE_QUERY_INFO_NONE,
+ NULL,
+ &error);
+ if (error != NULL) {
+ g_warning ("Unable to check directory %s: %s", path, error->message);
+ g_error_free (error);
+ g_object_unref (directory);
+ return;
+ }
+
+ while ((info = g_file_enumerator_next_file (enumerator, NULL, NULL))) {
+ const gchar *filename;
+ gchar *fullpath;
+
+ filename = g_file_info_get_name (info);
+ fullpath = g_build_filename (path, filename, NULL);
+ g_object_unref (info);
+
+ mate_wp_xml_load_xml (data, fullpath);
+ g_free (fullpath);
+ }
+ g_file_enumerator_close (enumerator, NULL, NULL);
+
+ mate_wp_xml_add_monitor (directory, data);
+
+ g_object_unref (directory);
+}
+
+void mate_wp_xml_load_list (AppearanceData *data) {
+ const char * const *system_data_dirs;
+ gchar * datadir;
+ gchar * wpdbfile;
+ gint i;
+
+ wpdbfile = g_build_filename (g_get_home_dir (),
+ ".mate2",
+ "backgrounds.xml",
+ NULL);
+
+ if (g_file_test (wpdbfile, G_FILE_TEST_EXISTS)) {
+ mate_wp_xml_load_xml (data, wpdbfile);
+ } else {
+ g_free (wpdbfile);
+ wpdbfile = g_build_filename (g_get_home_dir (),
+ ".mate2",
+ "wp-list.xml",
+ NULL);
+ if (g_file_test (wpdbfile, G_FILE_TEST_EXISTS)) {
+ mate_wp_xml_load_xml (data, wpdbfile);
+ }
+ }
+ g_free (wpdbfile);
+
+ datadir = g_build_filename (g_get_user_data_dir (),
+ "mate-background-properties",
+ NULL);
+ mate_wp_xml_load_from_dir (datadir, data);
+ g_free (datadir);
+
+ system_data_dirs = g_get_system_data_dirs ();
+ for (i = 0; system_data_dirs[i]; i++) {
+ datadir = g_build_filename (system_data_dirs[i],
+ "mate-background-properties",
+ NULL);
+ mate_wp_xml_load_from_dir (datadir, data);
+ g_free (datadir);
+ }
+
+ mate_wp_xml_load_from_dir (WALLPAPER_DATADIR, data);
+
+ mate_wp_load_legacy (data);
+}
+
+static void mate_wp_list_flatten (const gchar * key, MateWPItem * item,
+ GSList ** list) {
+ g_return_if_fail (key != NULL);
+ g_return_if_fail (item != NULL);
+
+ *list = g_slist_prepend (*list, item);
+}
+
+void mate_wp_xml_save_list (AppearanceData *data) {
+ xmlDoc * wplist;
+ xmlNode * root, * wallpaper, * item;
+ GSList * list = NULL;
+ gchar * wpfile;
+
+ g_hash_table_foreach (data->wp_hash,
+ (GHFunc) mate_wp_list_flatten, &list);
+ g_hash_table_destroy (data->wp_hash);
+ list = g_slist_reverse (list);
+
+ wpfile = g_build_filename (g_get_home_dir (),
+ "/.mate2",
+ "backgrounds.xml",
+ NULL);
+
+ xmlKeepBlanksDefault (0);
+
+ wplist = xmlNewDoc ((xmlChar *)"1.0");
+ xmlCreateIntSubset (wplist, (xmlChar *)"wallpapers", NULL, (xmlChar *)"mate-wp-list.dtd");
+ root = xmlNewNode (NULL, (xmlChar *)"wallpapers");
+ xmlDocSetRootElement (wplist, root);
+
+ while (list != NULL) {
+ MateWPItem * wpitem = list->data;
+ const char * none = "(none)";
+ gchar * filename;
+ const gchar * scale, * shade;
+ gchar * pcolor, * scolor;
+
+ if (!strcmp (wpitem->filename, none) ||
+ (g_utf8_validate (wpitem->filename, -1, NULL) &&
+ g_file_test (wpitem->filename, G_FILE_TEST_EXISTS)))
+ filename = g_strdup (wpitem->filename);
+ else
+ filename = g_filename_to_utf8 (wpitem->filename, -1, NULL, NULL, NULL);
+
+ pcolor = gdk_color_to_string (wpitem->pcolor);
+ scolor = gdk_color_to_string (wpitem->scolor);
+ scale = wp_item_option_to_string (wpitem->options);
+ shade = wp_item_shading_to_string (wpitem->shade_type);
+
+ wallpaper = xmlNewChild (root, NULL, (xmlChar *)"wallpaper", NULL);
+ mate_wp_xml_set_bool (wallpaper, (xmlChar *)"deleted", wpitem->deleted);
+ item = xmlNewTextChild (wallpaper, NULL, (xmlChar *)"name", (xmlChar *)wpitem->name);
+ item = xmlNewTextChild (wallpaper, NULL, (xmlChar *)"filename", (xmlChar *)filename);
+ item = xmlNewTextChild (wallpaper, NULL, (xmlChar *)"options", (xmlChar *)scale);
+ item = xmlNewTextChild (wallpaper, NULL, (xmlChar *)"shade_type", (xmlChar *)shade);
+ item = xmlNewTextChild (wallpaper, NULL, (xmlChar *)"pcolor", (xmlChar *)pcolor);
+ item = xmlNewTextChild (wallpaper, NULL, (xmlChar *)"scolor", (xmlChar *)scolor);
+ g_free (pcolor);
+ g_free (scolor);
+ g_free (filename);
+
+ list = g_slist_delete_link (list, list);
+ mate_wp_item_free (wpitem);
+ }
+ xmlSaveFormatFile (wpfile, wplist, 1);
+ xmlFreeDoc (wplist);
+ g_free (wpfile);
+}
diff --git a/capplets/appearance/mate-wp-xml.h b/capplets/appearance/mate-wp-xml.h
new file mode 100644
index 00000000..795487ff
--- /dev/null
+++ b/capplets/appearance/mate-wp-xml.h
@@ -0,0 +1,28 @@
+/*
+ * Authors: Rodney Dawes <[email protected]>
+ *
+ * Copyright 2003-2006 Novell, Inc. (www.novell.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef _MATE_WP_XML_H_
+#define _MATE_WP_XML_H_
+
+void mate_wp_xml_load_list (AppearanceData *data);
+void mate_wp_xml_save_list (AppearanceData *data);
+
+#endif
+
diff --git a/capplets/appearance/theme-installer.c b/capplets/appearance/theme-installer.c
new file mode 100644
index 00000000..fec1f001
--- /dev/null
+++ b/capplets/appearance/theme-installer.c
@@ -0,0 +1,801 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 The MATE Foundation
+ * Written by Thomas Wood <[email protected]>
+ * Jens Granseuer <[email protected]>
+ * All Rights Reserved
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "appearance.h"
+
+#include <string.h>
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+#include <glib/gstdio.h>
+#include <unistd.h>
+
+#include "capplet-util.h"
+#include "file-transfer-dialog.h"
+#include "theme-installer.h"
+#include "theme-util.h"
+
+enum {
+ THEME_INVALID,
+ THEME_ICON,
+ THEME_MATE,
+ THEME_GTK,
+ THEME_ENGINE,
+ THEME_MARCO,
+ THEME_CURSOR,
+ THEME_ICON_CURSOR
+};
+
+enum {
+ TARGZ,
+ TARBZ,
+ DIRECTORY
+};
+
+static gboolean
+cleanup_tmp_dir (GIOSchedulerJob *job,
+ GCancellable *cancellable,
+ const gchar *tmp_dir)
+{
+ GFile *directory;
+
+ directory = g_file_new_for_path (tmp_dir);
+ capplet_file_delete_recursive (directory, NULL);
+ g_object_unref (directory);
+
+ return FALSE;
+}
+
+static int
+file_theme_type (const gchar *dir)
+{
+ gchar *filename = NULL;
+ gboolean exists;
+
+ if (!dir)
+ return THEME_INVALID;
+
+ filename = g_build_filename (dir, "index.theme", NULL);
+ exists = g_file_test (filename, G_FILE_TEST_IS_REGULAR);
+
+ if (exists) {
+ GPatternSpec *pattern;
+ gchar *file_contents = NULL;
+ gsize file_size;
+ gboolean match;
+
+ g_file_get_contents (filename, &file_contents, &file_size, NULL);
+ g_free (filename);
+
+ pattern = g_pattern_spec_new ("*[Icon Theme]*");
+ match = g_pattern_match_string (pattern, file_contents);
+ g_pattern_spec_free (pattern);
+
+ if (match) {
+ pattern = g_pattern_spec_new ("*Directories=*");
+ match = g_pattern_match_string (pattern, file_contents);
+ g_pattern_spec_free (pattern);
+ g_free (file_contents);
+
+ if (match) {
+ /* check if we have a cursor, too */
+ filename = g_build_filename (dir, "cursors", NULL);
+ exists = g_file_test (filename, G_FILE_TEST_IS_DIR);
+ g_free (filename);
+
+ if (exists)
+ return THEME_ICON_CURSOR;
+ else
+ return THEME_ICON;
+ }
+ return THEME_CURSOR;
+ }
+
+ pattern = g_pattern_spec_new ("*[X-GNOME-Metatheme]*");
+ match = g_pattern_match_string (pattern, file_contents);
+ g_pattern_spec_free (pattern);
+ g_free (file_contents);
+
+ if (match)
+ return THEME_MATE;
+ } else {
+ g_free (filename);
+ }
+
+ filename = g_build_filename (dir, "gtk-2.0", "gtkrc", NULL);
+ exists = g_file_test (filename, G_FILE_TEST_IS_REGULAR);
+ g_free (filename);
+
+ if (exists)
+ return THEME_GTK;
+
+ filename = g_build_filename (dir, "metacity-1", "metacity-theme-1.xml", NULL);
+ exists = g_file_test (filename, G_FILE_TEST_IS_REGULAR);
+ g_free (filename);
+
+ if (exists)
+ return THEME_MARCO;
+
+ /* cursor themes don't necessarily have an index.theme */
+ filename = g_build_filename (dir, "cursors", NULL);
+ exists = g_file_test (filename, G_FILE_TEST_IS_DIR);
+ g_free (filename);
+
+ if (exists)
+ return THEME_CURSOR;
+
+ filename = g_build_filename (dir, "configure", NULL);
+ exists = g_file_test (filename, G_FILE_TEST_IS_EXECUTABLE);
+ g_free (filename);
+
+ if (exists)
+ return THEME_ENGINE;
+
+ return THEME_INVALID;
+}
+
+static void
+transfer_cancel_cb (GtkWidget *dialog,
+ gchar *path)
+{
+ GFile *todelete;
+
+ todelete = g_file_new_for_path (path);
+ capplet_file_delete_recursive (todelete, NULL);
+
+ g_object_unref (todelete);
+ g_free (path);
+ gtk_widget_destroy (dialog);
+}
+
+static void
+missing_utility_message_dialog (GtkWindow *parent,
+ const gchar *utility)
+{
+ GtkWidget *dialog = gtk_message_dialog_new (parent,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ _("Cannot install theme"));
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ _("The %s utility is not installed."), utility);
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+}
+
+/* this works around problems when doing fork/exec in a threaded app
+ * with some locks being held/waited on in different threads.
+ *
+ * we do the idle callback so that the async xfer has finished and
+ * cleaned up its vfs job. otherwise it seems the slave thread gets
+ * woken up and it removes itself from the job queue before it is
+ * supposed to. very strange.
+ *
+ * see bugzilla.gnome.org #86141 for details
+ */
+static gboolean
+process_local_theme_tgz_tbz (GtkWindow *parent,
+ const gchar *util,
+ const gchar *tmp_dir,
+ const gchar *archive)
+{
+ gboolean rc;
+ int status;
+ gchar *command, *filename, *zip, *tar;
+
+ if (!(zip = g_find_program_in_path (util))) {
+ missing_utility_message_dialog (parent, util);
+ return FALSE;
+ }
+ if (!(tar = g_find_program_in_path ("tar"))) {
+ missing_utility_message_dialog (parent, "tar");
+ g_free (zip);
+ return FALSE;
+ }
+
+ filename = g_shell_quote (archive);
+
+ /* this should be something more clever and nonblocking */
+ command = g_strdup_printf ("sh -c 'cd \"%s\"; %s -d -c < \"%s\" | %s xf - '",
+ tmp_dir, zip, filename, tar);
+ g_free (zip);
+ g_free (tar);
+ g_free (filename);
+
+ rc = (g_spawn_command_line_sync (command, NULL, NULL, &status, NULL) && status == 0);
+ g_free (command);
+
+ if (rc == FALSE) {
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new (parent,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ _("Cannot install theme"));
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ _("There was a problem while extracting the theme."));
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+ }
+
+ return rc;
+}
+
+static gboolean
+process_local_theme_archive (GtkWindow *parent,
+ gint filetype,
+ const gchar *tmp_dir,
+ const gchar *archive)
+{
+ if (filetype == TARGZ)
+ return process_local_theme_tgz_tbz (parent, "gzip", tmp_dir, archive);
+ else if (filetype == TARBZ)
+ return process_local_theme_tgz_tbz (parent, "bzip2", tmp_dir, archive);
+ else
+ return FALSE;
+}
+
+static void
+invalid_theme_dialog (GtkWindow *parent,
+ const gchar *filename,
+ gboolean maybe_theme_engine)
+{
+ GtkWidget *dialog;
+ const gchar *primary = _("There was an error installing the selected file");
+ const gchar *secondary = _("\"%s\" does not appear to be a valid theme.");
+ const gchar *engine = _("\"%s\" does not appear to be a valid theme. It may be a theme engine which you need to compile.");
+
+ dialog = gtk_message_dialog_new (parent,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ "%s", primary);
+ if (maybe_theme_engine)
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), engine, filename);
+ else
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), secondary, filename);
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+}
+
+static gboolean
+mate_theme_install_real (GtkWindow *parent,
+ gint filetype,
+ const gchar *tmp_dir,
+ const gchar *theme_name,
+ gboolean ask_user)
+{
+ gboolean success = TRUE;
+ GtkWidget *dialog, *apply_button;
+ GFile *theme_source_dir, *theme_dest_dir;
+ GError *error = NULL;
+ gint theme_type;
+ gchar *target_dir = NULL;
+
+ /* What type of theme is it? */
+ theme_type = file_theme_type (tmp_dir);
+ switch (theme_type) {
+ case THEME_ICON:
+ case THEME_CURSOR:
+ case THEME_ICON_CURSOR:
+ target_dir = g_build_path (G_DIR_SEPARATOR_S,
+ g_get_home_dir (), ".icons",
+ theme_name, NULL);
+ break;
+ case THEME_MATE:
+ target_dir = g_build_path (G_DIR_SEPARATOR_S,
+ g_get_home_dir (), ".themes",
+ theme_name, NULL);
+ break;
+ case THEME_MARCO:
+ case THEME_GTK:
+ target_dir = g_build_path (G_DIR_SEPARATOR_S,
+ g_get_home_dir (), ".themes",
+ theme_name, NULL);
+ break;
+ case THEME_ENGINE:
+ invalid_theme_dialog (parent, theme_name, TRUE);
+ return FALSE;
+ default:
+ invalid_theme_dialog (parent, theme_name, FALSE);
+ return FALSE;
+ }
+
+ /* see if there is an icon theme lurking in this package */
+ if (theme_type == THEME_MATE) {
+ gchar *path;
+
+ path = g_build_path (G_DIR_SEPARATOR_S,
+ tmp_dir, "icons", NULL);
+ if (g_file_test (path, G_FILE_TEST_IS_DIR)
+ && (file_theme_type (path) == THEME_ICON)) {
+ gchar *new_path, *update_icon_cache;
+ GFile *new_file;
+ GFile *src_file;
+
+ src_file = g_file_new_for_path (path);
+ new_path = g_build_path (G_DIR_SEPARATOR_S,
+ g_get_home_dir (),
+ ".icons",
+ theme_name, NULL);
+ new_file = g_file_new_for_path (new_path);
+
+ if (!g_file_move (src_file, new_file, G_FILE_COPY_NONE,
+ NULL, NULL, NULL, &error)) {
+ g_warning ("Error while moving from `%s' to `%s': %s",
+ path, new_path, error->message);
+ g_error_free (error);
+ error = NULL;
+ }
+ g_object_unref (new_file);
+ g_object_unref (src_file);
+
+ /* update icon cache - shouldn't really matter if this fails */
+ update_icon_cache = g_strdup_printf ("gtk-update-icon-cache %s", new_path);
+ g_spawn_command_line_async (update_icon_cache, NULL);
+ g_free (update_icon_cache);
+
+ g_free (new_path);
+ }
+ g_free (path);
+ }
+
+ /* Move the dir to the target dir */
+ theme_source_dir = g_file_new_for_path (tmp_dir);
+ theme_dest_dir = g_file_new_for_path (target_dir);
+
+ if (!g_file_move (theme_source_dir, theme_dest_dir,
+ G_FILE_COPY_OVERWRITE, NULL, NULL,
+ NULL, &error)) {
+ gchar *str;
+
+ str = g_strdup_printf (_("Installation for theme \"%s\" failed."), theme_name);
+ dialog = gtk_message_dialog_new (parent,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ "%s",
+ str);
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ "%s", error->message);
+
+ g_free (str);
+ g_error_free (error);
+ error = NULL;
+
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+ success = FALSE;
+ } else {
+ if (theme_type == THEME_ICON || theme_type == THEME_ICON_CURSOR)
+ {
+ gchar *update_icon_cache;
+
+ /* update icon cache - shouldn't really matter if this fails */
+ update_icon_cache = g_strdup_printf ("gtk-update-icon-cache %s", target_dir);
+ g_spawn_command_line_async (update_icon_cache, NULL);
+
+ g_free (update_icon_cache);
+ }
+
+ if (ask_user) {
+ /* Ask to apply theme (if we can) */
+ if (theme_type == THEME_GTK
+ || theme_type == THEME_MARCO
+ || theme_type == THEME_ICON
+ || theme_type == THEME_CURSOR
+ || theme_type == THEME_ICON_CURSOR) {
+ /* TODO: currently cannot apply "mate themes" */
+ gchar *str;
+
+ str = g_strdup_printf (_("The theme \"%s\" has been installed."), theme_name);
+ dialog = gtk_message_dialog_new_with_markup (parent,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_INFO,
+ GTK_BUTTONS_NONE,
+ "<span weight=\"bold\" size=\"larger\">%s</span>",
+ str);
+ g_free (str);
+
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ _("Would you like to apply it now, or keep your current theme?"));
+
+ gtk_dialog_add_button (GTK_DIALOG (dialog),
+ _("Keep Current Theme"),
+ GTK_RESPONSE_CLOSE);
+
+ apply_button = gtk_button_new_with_label (_("Apply New Theme"));
+ gtk_button_set_image (GTK_BUTTON (apply_button),
+ gtk_image_new_from_stock (GTK_STOCK_APPLY,
+ GTK_ICON_SIZE_BUTTON));
+ gtk_dialog_add_action_widget (GTK_DIALOG (dialog), apply_button, GTK_RESPONSE_APPLY);
+ gtk_widget_set_can_default (apply_button, TRUE);
+ gtk_widget_show (apply_button);
+
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_APPLY);
+
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_APPLY) {
+ /* apply theme here! */
+ MateConfClient *mateconf_client;
+
+ mateconf_client = mateconf_client_get_default ();
+
+ switch (theme_type) {
+ case THEME_GTK:
+ mateconf_client_set_string (mateconf_client, GTK_THEME_KEY, theme_name, NULL);
+ break;
+ case THEME_MARCO:
+ mateconf_client_set_string (mateconf_client, MARCO_THEME_KEY, theme_name, NULL);
+ break;
+ case THEME_ICON:
+ mateconf_client_set_string (mateconf_client, ICON_THEME_KEY, theme_name, NULL);
+ break;
+ case THEME_CURSOR:
+ mateconf_client_set_string (mateconf_client, CURSOR_THEME_KEY, theme_name, NULL);
+ break;
+ case THEME_ICON_CURSOR:
+ mateconf_client_set_string (mateconf_client, ICON_THEME_KEY, theme_name, NULL);
+ mateconf_client_set_string (mateconf_client, CURSOR_THEME_KEY, theme_name, NULL);
+ break;
+ default:
+ break;
+ }
+
+ g_object_unref (mateconf_client);
+ }
+ } else {
+ dialog = gtk_message_dialog_new (parent,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_INFO,
+ GTK_BUTTONS_OK,
+ _("MATE Theme %s correctly installed"),
+ theme_name);
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ }
+ gtk_widget_destroy (dialog);
+ }
+ }
+
+ g_free (target_dir);
+
+ return success;
+}
+
+static void
+process_local_theme (GtkWindow *parent,
+ const char *path)
+{
+ GtkWidget *dialog;
+ gint filetype;
+
+ if (g_str_has_suffix (path, ".tar.gz")
+ || g_str_has_suffix (path, ".tgz")
+ || g_str_has_suffix(path, ".gtp")) {
+ filetype = TARGZ;
+ } else if (g_str_has_suffix (path, ".tar.bz2")) {
+ filetype = TARBZ;
+ } else if (g_file_test (path, G_FILE_TEST_IS_DIR)) {
+ filetype = DIRECTORY;
+ } else {
+ gchar *filename;
+ filename = g_path_get_basename (path);
+ invalid_theme_dialog (parent, filename, FALSE);
+ g_free (filename);
+ return;
+ }
+
+ if (filetype == DIRECTORY) {
+ gchar *name = g_path_get_basename (path);
+ mate_theme_install_real (parent,
+ filetype,
+ path,
+ name,
+ TRUE);
+ g_free (name);
+ } else {
+ /* Create a temp directory and uncompress file there */
+ GDir *dir;
+ const gchar *name;
+ gchar *tmp_dir;
+ gboolean ok;
+ gint n_themes;
+ GFile *todelete;
+
+ tmp_dir = g_strdup_printf ("%s/.themes/.theme-%u",
+ g_get_home_dir (),
+ g_random_int ());
+
+ if ((g_mkdir (tmp_dir, 0700)) != 0) {
+ dialog = gtk_message_dialog_new (parent,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ _("Failed to create temporary directory"));
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+ g_free (tmp_dir);
+ return;
+ }
+
+ if (!process_local_theme_archive (parent, filetype, tmp_dir, path)
+ || ((dir = g_dir_open (tmp_dir, 0, NULL)) == NULL)) {
+ g_io_scheduler_push_job ((GIOSchedulerJobFunc) cleanup_tmp_dir,
+ g_strdup (tmp_dir),
+ g_free,
+ G_PRIORITY_DEFAULT,
+ NULL);
+ g_free (tmp_dir);
+ return;
+ }
+
+ todelete = g_file_new_for_path (path);
+ g_file_delete (todelete, NULL, NULL);
+ g_object_unref (todelete);
+
+ /* See whether we have multiple themes to install. If so,
+ * we won't ask the user whether to apply the new theme
+ * after installation. */
+ n_themes = 0;
+ for (name = g_dir_read_name (dir);
+ name && n_themes <= 1;
+ name = g_dir_read_name (dir)) {
+ gchar *theme_dir;
+
+ theme_dir = g_build_filename (tmp_dir, name, NULL);
+
+ if (g_file_test (theme_dir, G_FILE_TEST_IS_DIR))
+ ++n_themes;
+
+ g_free (theme_dir);
+ }
+ g_dir_rewind (dir);
+
+ ok = TRUE;
+ for (name = g_dir_read_name (dir); name && ok;
+ name = g_dir_read_name (dir)) {
+ gchar *theme_dir;
+
+ theme_dir = g_build_filename (tmp_dir, name, NULL);
+
+ if (g_file_test (theme_dir, G_FILE_TEST_IS_DIR))
+ ok = mate_theme_install_real (parent,
+ filetype,
+ theme_dir,
+ name,
+ n_themes == 1);
+
+ g_free (theme_dir);
+ }
+ g_dir_close (dir);
+
+ if (ok && n_themes > 1) {
+ dialog = gtk_message_dialog_new (parent,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_INFO,
+ GTK_BUTTONS_OK,
+ _("New themes have been successfully installed."));
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+ }
+ g_io_scheduler_push_job ((GIOSchedulerJobFunc) cleanup_tmp_dir,
+ tmp_dir, g_free,
+ G_PRIORITY_DEFAULT, NULL);
+ }
+}
+
+typedef struct
+{
+ GtkWindow *parent;
+ char *path;
+} TransferData;
+
+static void
+transfer_done_cb (GtkWidget *dialog,
+ TransferData *tdata)
+{
+ gdk_threads_enter ();
+ /* XXX: path should be on the local filesystem by now? */
+
+ if (dialog != NULL) {
+ gtk_widget_destroy (dialog);
+ }
+
+ process_local_theme (tdata->parent, tdata->path);
+
+ g_free (tdata->path);
+ g_free (tdata);
+
+ gdk_threads_leave ();
+}
+
+void
+mate_theme_install (GFile *file,
+ GtkWindow *parent)
+{
+ GtkWidget *dialog;
+ gchar *path, *base;
+ GList *src, *target;
+ const gchar *template;
+ TransferData *tdata;
+
+ if (file == NULL) {
+ dialog = gtk_message_dialog_new (parent,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ _("No theme file location specified to install"));
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+ return;
+ }
+
+ /* see if someone dropped a local directory */
+ if (g_file_is_native (file)
+ && g_file_query_file_type (file, G_FILE_QUERY_INFO_NONE, NULL) == G_FILE_TYPE_DIRECTORY) {
+ path = g_file_get_path (file);
+ process_local_theme (parent, path);
+ g_free (path);
+ return;
+ }
+
+ /* we can't tell if this is an icon theme yet, so just make a
+ * temporary copy in .themes */
+ path = g_build_filename (g_get_home_dir (), ".themes", NULL);
+
+ if (access (path, X_OK | W_OK) != 0) {
+ dialog = gtk_message_dialog_new (parent,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ _("Insufficient permissions to install the theme in:\n%s"), path);
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+ g_free (path);
+ return;
+ }
+
+ base = g_file_get_basename (file);
+
+ if (g_str_has_suffix (base, ".tar.gz")
+ || g_str_has_suffix (base, ".tgz")
+ || g_str_has_suffix (base, ".gtp"))
+ template = "mate-theme-%d.gtp";
+ else if (g_str_has_suffix (base, ".tar.bz2"))
+ template = "mate-theme-%d.tar.bz2";
+ else {
+ invalid_theme_dialog (parent, base, FALSE);
+ g_free (base);
+ return;
+ }
+ g_free (base);
+
+ src = g_list_append (NULL, g_object_ref (file));
+
+ path = NULL;
+ do {
+ gchar *file_tmp;
+
+ g_free (path);
+ file_tmp = g_strdup_printf (template, g_random_int ());
+ path = g_build_filename (g_get_home_dir (), ".themes", file_tmp, NULL);
+ g_free (file_tmp);
+ } while (g_file_test (path, G_FILE_TEST_EXISTS));
+
+ tdata = g_new0 (TransferData, 1);
+ tdata->parent = parent;
+ tdata->path = path;
+
+ dialog = file_transfer_dialog_new_with_parent (parent);
+ g_signal_connect (dialog,
+ "cancel",
+ (GCallback) transfer_cancel_cb, path);
+ g_signal_connect (dialog,
+ "done",
+ (GCallback) transfer_done_cb, tdata);
+
+ target = g_list_append (NULL, g_file_new_for_path (path));
+ file_transfer_dialog_copy_async (FILE_TRANSFER_DIALOG (dialog),
+ src,
+ target,
+ FILE_TRANSFER_DIALOG_DEFAULT,
+ G_PRIORITY_DEFAULT);
+ gtk_widget_show (dialog);
+
+ /* don't free the path since we're using that for the signals */
+ g_list_foreach (src, (GFunc) g_object_unref, NULL);
+ g_list_free (src);
+ g_list_foreach (target, (GFunc) g_object_unref, NULL);
+ g_list_free (target);
+}
+
+void
+mate_theme_installer_run (GtkWindow *parent,
+ const gchar *filename)
+{
+ static gboolean running_theme_install = FALSE;
+ static gchar old_folder[512] = "";
+ GtkWidget *dialog;
+ GtkFileFilter *filter;
+
+ if (running_theme_install)
+ return;
+
+ running_theme_install = TRUE;
+
+ if (filename == NULL)
+ filename = old_folder;
+
+ dialog = gtk_file_chooser_dialog_new (_("Select Theme"),
+ parent,
+ GTK_FILE_CHOOSER_ACTION_OPEN,
+ GTK_STOCK_CANCEL,
+ GTK_RESPONSE_REJECT,
+ GTK_STOCK_OPEN,
+ GTK_RESPONSE_ACCEPT,
+ NULL);
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
+
+ filter = gtk_file_filter_new ();
+ gtk_file_filter_set_name (filter, _("Theme Packages"));
+ gtk_file_filter_add_mime_type (filter, "application/x-bzip-compressed-tar");
+ gtk_file_filter_add_mime_type (filter, "application/x-compressed-tar");
+ gtk_file_filter_add_mime_type (filter, "application/x-mate-theme-package");
+ gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
+
+ filter = gtk_file_filter_new ();
+ gtk_file_filter_set_name (filter, _("All Files"));
+ gtk_file_filter_add_pattern(filter, "*");
+ gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
+
+ if (strcmp (old_folder, ""))
+ gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), old_folder);
+
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
+ gchar *uri_selected, *folder;
+
+ uri_selected = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog));
+
+ folder = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (dialog));
+ g_strlcpy (old_folder, folder, 255);
+ g_free (folder);
+
+ gtk_widget_destroy (dialog);
+
+ if (uri_selected != NULL) {
+ GFile *file = g_file_new_for_uri (uri_selected);
+ g_free (uri_selected);
+
+ mate_theme_install (file, parent);
+ g_object_unref (file);
+ }
+ } else {
+ gtk_widget_destroy (dialog);
+ }
+
+ /*
+ * we're relying on the mate theme info module to pick up changes
+ * to the themes so we don't need to update the model here
+ */
+
+ running_theme_install = FALSE;
+}
diff --git a/capplets/appearance/theme-installer.h b/capplets/appearance/theme-installer.h
new file mode 100644
index 00000000..c0b3f695
--- /dev/null
+++ b/capplets/appearance/theme-installer.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2007 The MATE Foundation
+ * Written by Thomas Wood <[email protected]>
+ * Jens Granseuer <[email protected]>
+ * All Rights Reserved
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef THEME_INSTALLER_H
+#define THEME_INSTALLER_H
+
+void mate_theme_install (GFile *file, GtkWindow *parent);
+void mate_theme_installer_run (GtkWindow *parent, const gchar *filename);
+
+#endif /* THEME_INSTALLER_H */
diff --git a/capplets/appearance/theme-save.c b/capplets/appearance/theme-save.c
new file mode 100644
index 00000000..f4981468
--- /dev/null
+++ b/capplets/appearance/theme-save.c
@@ -0,0 +1,381 @@
+/*
+ * Copyright (C) 2007 The MATE Foundation
+ * Written by Thomas Wood <[email protected]>
+ * Jens Granseuer <[email protected]>
+ * All Rights Reserved
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "appearance.h"
+
+#include <glib/gstdio.h>
+#include <glib/gi18n.h>
+#include <string.h>
+
+#include "theme-save.h"
+#include "theme-util.h"
+#include "capplet-util.h"
+
+static GQuark error_quark;
+enum {
+ INVALID_THEME_NAME
+};
+
+/* taken from mate-desktop-item.c */
+static gchar *
+escape_string_and_dup (const gchar *s)
+{
+ gchar *return_value, *p;
+ const gchar *q;
+ int len = 0;
+
+ if (s == NULL)
+ return g_strdup("");
+
+ q = s;
+ while (*q)
+ {
+ len++;
+ if (strchr ("\n\r\t\\", *q) != NULL)
+ len++;
+ q++;
+ }
+ return_value = p = (gchar *) g_malloc (len + 1);
+ do
+ {
+ switch (*s)
+ {
+ case '\t':
+ *p++ = '\\';
+ *p++ = 't';
+ break;
+ case '\n':
+ *p++ = '\\';
+ *p++ = 'n';
+ break;
+ case '\r':
+ *p++ = '\\';
+ *p++ = 'r';
+ break;
+ case '\\':
+ *p++ = '\\';
+ *p++ = '\\';
+ break;
+ default:
+ *p++ = *s;
+ }
+ }
+ while (*s++);
+ return return_value;
+}
+
+static gboolean
+check_theme_name (const gchar *theme_name,
+ GError **error)
+{
+ if (theme_name == NULL) {
+ g_set_error (error,
+ error_quark,
+ INVALID_THEME_NAME,
+ _("Theme name must be present"));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static gchar *
+str_remove_slash (const gchar *src)
+{
+ const gchar *i;
+ gchar *rtn;
+ gint len = 0;
+ i = src;
+
+ while (*i) {
+ if (*i != '/')
+ len++;
+ i++;
+ }
+
+ rtn = (gchar *) g_malloc (len + 1);
+ while (*src) {
+ if (*src != '/') {
+ *rtn = *src;
+ rtn++;
+ }
+ src++;
+ }
+ *rtn = '\0';
+ return rtn - len;
+}
+
+static gboolean
+setup_directory_structure (const gchar *theme_name,
+ GError **error)
+{
+ gchar *dir, *theme_name_dir;
+ gboolean retval = TRUE;
+
+ theme_name_dir = str_remove_slash (theme_name);
+
+ dir = g_build_filename (g_get_home_dir (), ".themes", NULL);
+ if (!g_file_test (dir, G_FILE_TEST_EXISTS))
+ g_mkdir (dir, 0775);
+ g_free (dir);
+
+ dir = g_build_filename (g_get_home_dir (), ".themes", theme_name_dir, NULL);
+ if (!g_file_test (dir, G_FILE_TEST_EXISTS))
+ g_mkdir (dir, 0775);
+ g_free (dir);
+
+ dir = g_build_filename (g_get_home_dir (), ".themes", theme_name_dir, "index.theme", NULL);
+ g_free (theme_name_dir);
+
+ if (g_file_test (dir, G_FILE_TEST_EXISTS)) {
+ GtkDialog *dialog;
+ GtkWidget *button;
+ gint response;
+
+ dialog = (GtkDialog *) gtk_message_dialog_new (NULL,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_CANCEL,
+ _("The theme already exists. Would you like to replace it?"));
+ button = gtk_dialog_add_button (dialog, _("_Overwrite"), GTK_RESPONSE_ACCEPT);
+ gtk_button_set_image (GTK_BUTTON (button),
+ gtk_image_new_from_stock (GTK_STOCK_SAVE, GTK_ICON_SIZE_BUTTON));
+ response = gtk_dialog_run (dialog);
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+ retval = (response != GTK_RESPONSE_CANCEL);
+ }
+ g_free (dir);
+
+ return retval;
+}
+
+static gboolean
+write_theme_to_disk (MateThemeMetaInfo *theme_info,
+ const gchar *theme_name,
+ const gchar *theme_description,
+ gboolean save_background,
+ GError **error)
+{
+ gchar* dir;
+ gchar* theme_name_dir;
+ GFile* tmp_file;
+ GFile* target_file;
+ GOutputStream* output;
+
+ gchar* str;
+ gchar* current_background;
+
+ MateConfClient* client;
+ const gchar* theme_header = ""
+ "[Desktop Entry]\n"
+ "Name=%s\n"
+ "Type=X-GNOME-Metatheme\n"
+ "Comment=%s\n"
+ "\n"
+ "[X-GNOME-Metatheme]\n"
+ "GtkTheme=%s\n"
+ "MetacityTheme=%s\n"
+ "IconTheme=%s\n";
+
+ theme_name_dir = str_remove_slash (theme_name);
+ dir = g_build_filename (g_get_home_dir (), ".themes", theme_name_dir, "index.theme~", NULL);
+ g_free (theme_name_dir);
+
+ tmp_file = g_file_new_for_path (dir);
+ dir [strlen (dir) - 1] = '\000';
+ target_file = g_file_new_for_path (dir);
+ g_free (dir);
+
+ /* start making the theme file */
+ str = g_strdup_printf(theme_header, theme_name, theme_description, theme_info->gtk_theme_name, theme_info->marco_theme_name, theme_info->icon_theme_name);
+
+ output = G_OUTPUT_STREAM (g_file_replace (tmp_file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, NULL));
+ g_output_stream_write (output, str, strlen (str), NULL, NULL);
+ g_free (str);
+
+ if (theme_info->gtk_color_scheme) {
+ gchar *a, *tmp;
+ tmp = g_strdup (theme_info->gtk_color_scheme);
+ for (a = tmp; *a != '\0'; a++)
+ if (*a == '\n')
+ *a = ',';
+ str = g_strdup_printf ("GtkColorScheme=%s\n", tmp);
+ g_output_stream_write (output, str, strlen (str), NULL, NULL);
+
+ g_free (str);
+ g_free (tmp);
+ }
+
+ if (theme_info->cursor_theme_name) {
+#ifdef HAVE_XCURSOR
+ str = g_strdup_printf ("CursorTheme=%s\n"
+ "CursorSize=%i\n",
+ theme_info->cursor_theme_name,
+ theme_info->cursor_size);
+#else
+ str = g_strdup_printf ("CursorFont=%s\n", theme_info->cursor_theme_name);
+#endif
+ g_output_stream_write (output, str, strlen (str), NULL, NULL);
+ g_free (str);
+ }
+
+ if (theme_info->notification_theme_name) {
+ str = g_strdup_printf ("NotificationTheme=%s\n", theme_info->notification_theme_name);
+ g_output_stream_write (output, str, strlen (str), NULL, NULL);
+ g_free (str);
+ }
+
+ if (save_background) {
+ client = mateconf_client_get_default ();
+ current_background = mateconf_client_get_string (client, BACKGROUND_KEY, NULL);
+
+ if (current_background != NULL) {
+ str = g_strdup_printf ("BackgroundImage=%s\n", current_background);
+
+ g_output_stream_write (output, str, strlen (str), NULL, NULL);
+
+ g_free (current_background);
+ g_free (str);
+ }
+ g_object_unref (client);
+ }
+
+ g_file_move (tmp_file, target_file, G_FILE_COPY_OVERWRITE, NULL, NULL, NULL, NULL);
+ g_output_stream_close (output, NULL, NULL);
+
+ g_object_unref (tmp_file);
+ g_object_unref (target_file);
+
+ return TRUE;
+}
+
+static gboolean
+save_theme_to_disk (MateThemeMetaInfo *theme_info,
+ const gchar *theme_name,
+ const gchar *theme_description,
+ gboolean save_background,
+ GError **error)
+{
+ if (!check_theme_name (theme_name, error))
+ return FALSE;
+
+ if (!setup_directory_structure (theme_name, error))
+ return FALSE;
+
+ if (!write_theme_to_disk (theme_info, theme_name, theme_description, save_background, error))
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+save_dialog_response (GtkWidget *save_dialog,
+ gint response_id,
+ AppearanceData *data)
+{
+ if (response_id == GTK_RESPONSE_OK) {
+ GtkWidget *entry;
+ GtkWidget *text_view;
+ GtkTextBuffer *buffer;
+ GtkTextIter start_iter;
+ GtkTextIter end_iter;
+ gchar *buffer_text;
+ MateThemeMetaInfo *theme_info;
+ gchar *theme_description = NULL;
+ gchar *theme_name = NULL;
+ gboolean save_background;
+ GError *error = NULL;
+
+ entry = appearance_capplet_get_widget (data, "save_dialog_entry");
+ theme_name = escape_string_and_dup (gtk_entry_get_text (GTK_ENTRY (entry)));
+
+ text_view = appearance_capplet_get_widget (data, "save_dialog_textview");
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));
+ gtk_text_buffer_get_start_iter (buffer, &start_iter);
+ gtk_text_buffer_get_end_iter (buffer, &end_iter);
+ buffer_text = gtk_text_buffer_get_text (buffer, &start_iter, &end_iter, FALSE);
+ theme_description = escape_string_and_dup (buffer_text);
+ g_free (buffer_text);
+ theme_info = (MateThemeMetaInfo *) g_object_get_data (G_OBJECT (save_dialog), "meta-theme-info");
+ save_background = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (
+ appearance_capplet_get_widget (data, "save_background_checkbutton")));
+
+ if (save_theme_to_disk (theme_info, theme_name, theme_description, save_background, &error)) {
+ /* remove the custom theme */
+ GtkTreeIter iter;
+
+ if (theme_find_in_model (GTK_TREE_MODEL (data->theme_store), "__custom__", &iter))
+ gtk_list_store_remove (data->theme_store, &iter);
+ }
+
+ g_free (theme_name);
+ g_free (theme_description);
+ g_clear_error (&error);
+ }
+
+ gtk_widget_hide (save_dialog);
+}
+
+static void
+entry_text_changed (GtkEditable *editable,
+ AppearanceData *data)
+{
+ const gchar *text;
+ GtkWidget *button;
+
+ text = gtk_entry_get_text (GTK_ENTRY (editable));
+ button = appearance_capplet_get_widget (data, "save_dialog_save_button");
+
+ gtk_widget_set_sensitive (button, text != NULL && text[0] != '\000');
+}
+
+void
+theme_save_dialog_run (MateThemeMetaInfo *theme_info,
+ AppearanceData *data)
+{
+ GtkWidget *entry;
+ GtkWidget *text_view;
+ GtkTextBuffer *text_buffer;
+
+ entry = appearance_capplet_get_widget (data, "save_dialog_entry");
+ text_view = appearance_capplet_get_widget (data, "save_dialog_textview");
+
+ if (data->theme_save_dialog == NULL) {
+ data->theme_save_dialog = appearance_capplet_get_widget (data, "theme_save_dialog");
+
+ g_signal_connect (data->theme_save_dialog, "response", (GCallback) save_dialog_response, data);
+ g_signal_connect (data->theme_save_dialog, "delete-event", (GCallback) gtk_true, NULL);
+ g_signal_connect (entry, "changed", (GCallback) entry_text_changed, data);
+
+ error_quark = g_quark_from_string ("mate-theme-save");
+ gtk_widget_set_size_request (text_view, 300, 100);
+ }
+
+ gtk_entry_set_text (GTK_ENTRY (entry), "");
+ entry_text_changed (GTK_EDITABLE (entry), data);
+ gtk_widget_grab_focus (entry);
+
+ text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));
+ gtk_text_buffer_set_text (text_buffer, "", 0);
+ g_object_set_data (G_OBJECT (data->theme_save_dialog), "meta-theme-info", theme_info);
+ gtk_window_set_transient_for (GTK_WINDOW (data->theme_save_dialog),
+ GTK_WINDOW (appearance_capplet_get_widget (data, "appearance_window")));
+ gtk_widget_show (data->theme_save_dialog);
+}
diff --git a/capplets/appearance/theme-save.h b/capplets/appearance/theme-save.h
new file mode 100644
index 00000000..e56f4041
--- /dev/null
+++ b/capplets/appearance/theme-save.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2007 The MATE Foundation
+ * Written by Jens Granseuer <[email protected]>
+ * All Rights Reserved
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+void theme_save_dialog_run (MateThemeMetaInfo *theme_info,
+ AppearanceData *data);
diff --git a/capplets/appearance/theme-util.c b/capplets/appearance/theme-util.c
new file mode 100644
index 00000000..2305b0f9
--- /dev/null
+++ b/capplets/appearance/theme-util.c
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2007 The MATE Foundation
+ * Written by Thomas Wood <[email protected]>
+ * Jens Granseuer <[email protected]>
+ * All Rights Reserved
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "appearance.h"
+
+#include <string.h>
+#include <glib/gi18n.h>
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-bindings.h>
+
+#include "capplet-util.h"
+#include "theme-util.h"
+
+gboolean
+theme_is_writable (const gpointer theme)
+{
+ MateThemeCommonInfo *info = theme;
+ GFile *file;
+ GFileInfo *file_info;
+ gboolean writable;
+
+ if (info == NULL || info->path == NULL)
+ return FALSE;
+
+ file = g_file_new_for_path (info->path);
+ file_info = g_file_query_info (file,
+ G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE,
+ G_FILE_QUERY_INFO_NONE,
+ NULL, NULL);
+ g_object_unref (file);
+
+ if (file_info == NULL)
+ return FALSE;
+
+ writable = g_file_info_get_attribute_boolean (file_info,
+ G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE);
+ g_object_unref (file_info);
+
+ return writable;
+}
+
+gboolean
+theme_delete (const gchar *name, ThemeType type)
+{
+ gboolean rc;
+ GtkDialog *dialog;
+ gchar *theme_dir;
+ gint response;
+ MateThemeCommonInfo *theme;
+ GFile *dir;
+ gboolean del_empty_parent;
+
+ dialog = (GtkDialog *) gtk_message_dialog_new (NULL,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_CANCEL,
+ _("Would you like to delete this theme?"));
+ gtk_dialog_add_button (dialog, GTK_STOCK_DELETE, GTK_RESPONSE_ACCEPT);
+ response = gtk_dialog_run (dialog);
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+ if (response != GTK_RESPONSE_ACCEPT)
+ return FALSE;
+
+ /* Most theme types are put into separate subdirectories. For those
+ we want to delete those directories as well. */
+ del_empty_parent = TRUE;
+
+ switch (type) {
+ case THEME_TYPE_GTK:
+ theme = (MateThemeCommonInfo *) mate_theme_info_find (name);
+ theme_dir = g_build_filename (theme->path, "gtk-2.0", NULL);
+ break;
+
+ case THEME_TYPE_ICON:
+ theme = (MateThemeCommonInfo *) mate_theme_icon_info_find (name);
+ theme_dir = g_path_get_dirname (theme->path);
+ del_empty_parent = FALSE;
+ break;
+
+ case THEME_TYPE_WINDOW:
+ theme = (MateThemeCommonInfo *) mate_theme_info_find (name);
+ theme_dir = g_build_filename (theme->path, "marco-1", NULL);
+ break;
+
+ case THEME_TYPE_META:
+ theme = (MateThemeCommonInfo *) mate_theme_meta_info_find (name);
+ theme_dir = g_strdup (theme->path);
+ break;
+
+ case THEME_TYPE_CURSOR:
+ theme = (MateThemeCommonInfo *) mate_theme_cursor_info_find (name);
+ theme_dir = g_build_filename (theme->path, "cursors", NULL);
+ break;
+
+ default:
+ return FALSE;
+ }
+
+ dir = g_file_new_for_path (theme_dir);
+ g_free (theme_dir);
+
+ if (!capplet_file_delete_recursive (dir, NULL)) {
+ GtkWidget *info_dialog = gtk_message_dialog_new (NULL,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ _("Theme cannot be deleted"));
+ gtk_dialog_run (GTK_DIALOG (info_dialog));
+ gtk_widget_destroy (info_dialog);
+ rc = FALSE;
+ } else {
+ if (del_empty_parent) {
+ /* also delete empty parent directories */
+ GFile *parent = g_file_get_parent (dir);
+ g_file_delete (parent, NULL, NULL);
+ g_object_unref (parent);
+ }
+ rc = TRUE;
+ }
+
+ g_object_unref (dir);
+ return rc;
+}
+
+gboolean
+theme_model_iter_last (GtkTreeModel *model, GtkTreeIter *iter)
+{
+ GtkTreeIter walk, prev;
+ gboolean valid;
+
+ valid = gtk_tree_model_get_iter_first (model, &walk);
+
+ if (valid) {
+ do {
+ prev = walk;
+ valid = gtk_tree_model_iter_next (model, &walk);
+ } while (valid);
+
+ *iter = prev;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+gboolean
+theme_find_in_model (GtkTreeModel *model, const gchar *name, GtkTreeIter *iter)
+{
+ GtkTreeIter walk;
+ gboolean valid;
+ gchar *test;
+
+ if (!name)
+ return FALSE;
+
+ for (valid = gtk_tree_model_get_iter_first (model, &walk); valid;
+ valid = gtk_tree_model_iter_next (model, &walk))
+ {
+ gtk_tree_model_get (model, &walk, COL_NAME, &test, -1);
+
+ if (test) {
+ gint cmp = strcmp (test, name);
+ g_free (test);
+
+ if (!cmp) {
+ if (iter)
+ *iter = walk;
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+gboolean
+packagekit_available (void)
+{
+ DBusGConnection *connection;
+ DBusGProxy *proxy;
+ gboolean available = FALSE;
+
+ connection = dbus_g_bus_get (DBUS_BUS_SESSION, NULL);
+ if (connection == NULL) {
+ return FALSE;
+ }
+
+ proxy = dbus_g_proxy_new_for_name (connection,
+ DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS,
+ DBUS_INTERFACE_DBUS);
+
+ org_freedesktop_DBus_name_has_owner (proxy,
+ "org.freedesktop.PackageKit",
+ &available,
+ NULL);
+
+ g_object_unref (proxy);
+ dbus_g_connection_unref (connection);
+
+ return available;
+}
+
+void theme_install_file(GtkWindow* parent, const gchar* path)
+{
+ DBusGConnection* connection;
+ DBusGProxy* proxy;
+ GError* error = NULL;
+ gboolean ret;
+
+ connection = dbus_g_bus_get(DBUS_BUS_SESSION, NULL);
+
+ if (connection == NULL)
+ {
+ g_warning("Could not get session bus");
+ return;
+ }
+
+ proxy = dbus_g_proxy_new_for_name(connection,
+ "org.freedesktop.PackageKit",
+ "/org/freedesktop/PackageKit",
+ "org.freedesktop.PackageKit");
+
+
+ ret = dbus_g_proxy_call(proxy, "InstallProvideFile", &error,
+ G_TYPE_STRING, path,
+ G_TYPE_INVALID, G_TYPE_INVALID);
+
+ g_object_unref(proxy);
+
+ if (!ret)
+ {
+ GtkWidget* dialog = gtk_message_dialog_new(NULL,
+ GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ _("Could not install theme engine"));
+ gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG (dialog), "%s", error->message);
+
+ gtk_dialog_run(GTK_DIALOG(dialog));
+ gtk_widget_destroy(dialog);
+ g_error_free(error);
+ }
+
+ dbus_g_connection_unref(connection);
+}
diff --git a/capplets/appearance/theme-util.h b/capplets/appearance/theme-util.h
new file mode 100644
index 00000000..8bf91302
--- /dev/null
+++ b/capplets/appearance/theme-util.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2007 The MATE Foundation
+ * Written by Jens Granseuer <[email protected]>
+ * All Rights Reserved
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#define GTK_THEME_KEY "/desktop/mate/interface/gtk_theme"
+#define MARCO_THEME_KEY "/apps/marco/general/theme"
+#define ICON_THEME_KEY "/desktop/mate/interface/icon_theme"
+#define NOTIFICATION_THEME_KEY "/apps/notification-daemon/theme"
+#define COLOR_SCHEME_KEY "/desktop/mate/interface/gtk_color_scheme"
+#define LOCKDOWN_KEY "/desktop/mate/lockdown/disable_theme_settings"
+#define BACKGROUND_KEY "/desktop/mate/background/picture_filename"
+#define APPLICATION_FONT_KEY "/desktop/mate/interface/font_name"
+#define DOCUMENTS_FONT_KEY "/desktop/mate/interface/document_font_name"
+#define DESKTOP_FONT_KEY "/apps/caja/preferences/desktop_font"
+#define WINDOWTITLE_FONT_KEY "/apps/marco/general/titlebar_font"
+#define MONOSPACE_FONT_KEY "/desktop/mate/interface/monospace_font_name"
+
+#ifdef HAVE_XCURSOR
+ #define CURSOR_THEME_KEY "/desktop/mate/peripherals/mouse/cursor_theme"
+ #define CURSOR_SIZE_KEY "/desktop/mate/peripherals/mouse/cursor_size"
+#else
+ #define CURSOR_THEME_KEY "/desktop/mate/peripherals/mouse/cursor_font"
+#endif
+
+enum {
+ COL_THUMBNAIL,
+ COL_LABEL,
+ COL_NAME,
+ NUM_COLS
+};
+
+typedef enum {
+ THEME_TYPE_GTK,
+ THEME_TYPE_WINDOW,
+ THEME_TYPE_ICON,
+ THEME_TYPE_META,
+ THEME_TYPE_CURSOR
+} ThemeType;
+
+gboolean theme_is_writable(const gpointer theme);
+gboolean theme_delete(const gchar* name, ThemeType type);
+
+gboolean theme_model_iter_last(GtkTreeModel* model, GtkTreeIter* iter);
+gboolean theme_find_in_model(GtkTreeModel* model, const gchar* name, GtkTreeIter* iter);
+
+void theme_install_file(GtkWindow* parent, const gchar* path);
+gboolean packagekit_available(void);
diff --git a/capplets/common/Makefile.am b/capplets/common/Makefile.am
new file mode 100644
index 00000000..127af950
--- /dev/null
+++ b/capplets/common/Makefile.am
@@ -0,0 +1,63 @@
+EXTRA_DIST =
+
+INCLUDES = \
+ -DMATECC_DATA_DIR="\"$(pkgdatadir)\"" \
+ -DMATELOCALEDIR="\"$(datadir)/locale\"" \
+ -DGTK_ENGINE_DIR="\"$(GTK_ENGINE_DIR)\"" \
+ -DG_LOG_DOMAIN=\"capplet-common\" \
+ -DINSTALL_PREFIX=\"$(prefix)\" \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/libwindow-settings \
+ -DPIXMAP_DIR=\""$(datadir)/mate-control-center/pixmaps"\" \
+ $(CAPPLET_CFLAGS) \
+ $(DBUS_CFLAGS) \
+ $(MATE_DESKTOP_CFLAGS) \
+ $(MARCO_CFLAGS) \
+ $(GSD_DBUS_CFLAGS) \
+ $(GIO_CFLAGS)
+
+
+noinst_LTLIBRARIES = libcommon.la
+
+libcommon_la_SOURCES = \
+ activate-settings-daemon.c \
+ activate-settings-daemon.h \
+ capplet-stock-icons.c \
+ capplet-stock-icons.h \
+ capplet-util.c \
+ capplet-util.h \
+ file-transfer-dialog.c \
+ file-transfer-dialog.h \
+ mateconf-property-editor.c \
+ mateconf-property-editor.h \
+ mateconf-property-editor-marshal.c \
+ mateconf-property-editor-marshal.h \
+ mate-theme-apply.c \
+ mate-theme-apply.h \
+ mate-theme-info.c \
+ mate-theme-info.h \
+ gtkrc-utils.c \
+ gtkrc-utils.h \
+ theme-thumbnail.c \
+ theme-thumbnail.h \
+ wm-common.c \
+ wm-common.h
+
+libcommon_la_LIBADD = \
+ $(top_builddir)/libwindow-settings/libmate-window-settings.la \
+ $(MARCO_LIBS) \
+ $(DBUS_LIBS) \
+ $(MATE_DESKTOP_LIBS) \
+ $(GIO_LIBS)
+
+mate_theme_test_SOURCES = \
+ mate-theme-test.c
+
+mate_theme_test_LDADD = \
+ libcommon.la \
+ $(MATECC_CAPPLETS_LIBS)
+
+noinst_PROGRAMS = \
+ mate-theme-test
+
+-include $(top_srcdir)/git.mk
diff --git a/capplets/common/activate-settings-daemon.c b/capplets/common/activate-settings-daemon.c
new file mode 100644
index 00000000..794f1098
--- /dev/null
+++ b/capplets/common/activate-settings-daemon.c
@@ -0,0 +1,60 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <mate-settings-daemon/mate-settings-client.h>
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+
+#include "activate-settings-daemon.h"
+
+static void popup_error_message (void)
+{
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_OK, _("Unable to start the settings manager 'mate-settings-daemon'.\n"
+ "Without the MATE settings manager running, some preferences may not take effect. This could "
+ "indicate a problem with DBus, or a non-MATE (e.g. KDE) settings manager may already "
+ "be active and conflicting with the MATE settings manager."));
+
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+}
+
+/* Returns FALSE if activation failed, else TRUE */
+gboolean
+activate_settings_daemon (void)
+{
+ DBusGConnection *connection = NULL;
+ DBusGProxy *proxy = NULL;
+ GError *error = NULL;
+
+ connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+ if (connection == NULL)
+ {
+ popup_error_message ();
+ g_error_free (error);
+ return FALSE;
+ }
+
+ proxy = dbus_g_proxy_new_for_name (connection,
+ "org.mate.SettingsDaemon",
+ "/org/mate/SettingsDaemon",
+ "org.mate.SettingsDaemon");
+
+ if (proxy == NULL)
+ {
+ popup_error_message ();
+ return FALSE;
+ }
+
+ if (!org_mate_SettingsDaemon_awake(proxy, &error))
+ {
+ popup_error_message ();
+ g_error_free (error);
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/capplets/common/activate-settings-daemon.h b/capplets/common/activate-settings-daemon.h
new file mode 100644
index 00000000..fc1558d8
--- /dev/null
+++ b/capplets/common/activate-settings-daemon.h
@@ -0,0 +1,9 @@
+#ifndef ACTIVATE_SETINGS_DAEMON
+#define ACTIVATE_SETINGS_DAEMON
+
+#include <glib.h>
+
+/* Returns FALSE if activation failed, else TRUE */
+gboolean activate_settings_daemon (void);
+
+#endif
diff --git a/capplets/common/capplet-stock-icons.c b/capplets/common/capplet-stock-icons.c
new file mode 100644
index 00000000..29b440f5
--- /dev/null
+++ b/capplets/common/capplet-stock-icons.c
@@ -0,0 +1,101 @@
+/*
+ * capplet-stock-icons.c
+ *
+ * Copyright (C) 2002 Sun Microsystems, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors:
+ * Rajkumar Sivasamy <[email protected]>
+ * Taken bits of code from panel-stock-icons.c, Thanks Mark <[email protected]>
+ */
+
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+
+#include "capplet-stock-icons.h"
+
+static GtkIconSize mouse_capplet_dblclck_icon_size = 0;
+
+GtkIconSize
+mouse_capplet_dblclck_icon_get_size (void)
+{
+ return mouse_capplet_dblclck_icon_size;
+}
+
+typedef struct
+{
+ char *stock_id;
+ char *name;
+} CappletStockIcon;
+
+
+static CappletStockIcon items [] = {
+ { MOUSE_DBLCLCK_MAYBE, "double-click-maybe.png"},
+ { MOUSE_DBLCLCK_ON, "double-click-on.png"},
+ { MOUSE_DBLCLCK_OFF, "double-click-off.png"}
+};
+
+static void
+capplet_register_stock_icons (GtkIconFactory *factory)
+{
+ gint i;
+ GtkIconSource *source;
+
+ source = gtk_icon_source_new ();
+
+ for (i = 0; i < G_N_ELEMENTS (items); ++i) {
+ GtkIconSet *icon_set;
+ char *filename;
+ filename = g_build_filename (PIXMAP_DIR, items[i].name, NULL);
+
+ if (!filename) {
+ g_warning (_("Unable to load stock icon '%s'\n"), items[i].name);
+ icon_set = gtk_icon_factory_lookup_default (GTK_STOCK_MISSING_IMAGE);
+ gtk_icon_factory_add (factory, items[i].stock_id, icon_set);
+ continue;
+ }
+
+ gtk_icon_source_set_filename (source, filename);
+ g_free (filename);
+
+ icon_set = gtk_icon_set_new ();
+ gtk_icon_set_add_source (icon_set, source);
+ gtk_icon_factory_add (factory, items[i].stock_id, icon_set);
+ gtk_icon_set_unref (icon_set);
+ }
+ gtk_icon_source_free (source);
+}
+
+void
+capplet_init_stock_icons (void)
+{
+ GtkIconFactory *factory;
+ static gboolean initialized = FALSE;
+
+ if (initialized)
+ return;
+ initialized = TRUE;
+
+ factory = gtk_icon_factory_new ();
+ gtk_icon_factory_add_default (factory);
+ capplet_register_stock_icons (factory);
+
+ mouse_capplet_dblclck_icon_size = gtk_icon_size_register ("mouse-capplet-dblclck-icon",
+ MOUSE_CAPPLET_DBLCLCK_ICON_SIZE,
+ MOUSE_CAPPLET_DBLCLCK_ICON_SIZE);
+ g_object_unref (factory);
+}
diff --git a/capplets/common/capplet-stock-icons.h b/capplets/common/capplet-stock-icons.h
new file mode 100644
index 00000000..8c954cf4
--- /dev/null
+++ b/capplets/common/capplet-stock-icons.h
@@ -0,0 +1,66 @@
+/*
+ * capplet-stock-icons.h
+ *
+ * Copyright (C) 2002 Sun Microsystems, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors:
+ * Rajkumar Sivasamy <[email protected]>
+ * Taken bits of code from panel-stock-icons.h, Thanks Mark <[email protected]>
+ */
+
+#ifndef __CAPPLET_STOCK_ICONS_H__
+#define __CAPPLET_STOCK_ICONS_H__
+
+#include <glib.h>
+#include <gtk/gtk.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define KEYBOARD_CAPPLET_DEFAULT_ICON_SIZE 48
+#define MOUSE_CAPPLET_DEFAULT_WIDTH 120
+#define MOUSE_CAPPLET_DEFAULT_HEIGHT 100
+#define MOUSE_CAPPLET_DBLCLCK_ICON_SIZE 100
+
+/* stock icons */
+#define KEYBOARD_REPEAT "keyboard-repeat"
+#define KEYBOARD_CURSOR "keyboard-cursor"
+#define KEYBOARD_VOLUME "keyboard-volume"
+#define KEYBOARD_BELL "keyboard-bell"
+#define ACCESSX_KEYBOARD_BOUNCE "accessibility-keyboard-bouncekey"
+#define ACCESSX_KEYBOARD_SLOW "accessibility-keyboard-slowkey"
+#define ACCESSX_KEYBOARD_MOUSE "accessibility-keyboard-mousekey"
+#define ACCESSX_KEYBOARD_STICK "accessibility-keyboard-stickykey"
+#define ACCESSX_KEYBOARD_TOGGLE "accessibility-keyboard-togglekey"
+#define MOUSE_DBLCLCK_MAYBE "mouse-dblclck-maybe"
+#define MOUSE_DBLCLCK_ON "mouse-dblclck-on"
+#define MOUSE_DBLCLCK_OFF "mouse-dblclck-off"
+#define MOUSE_RIGHT_HANDED "mouse-right-handed"
+#define MOUSE_LEFT_HANDED "mouse-left-handed"
+
+void capplet_init_stock_icons (void);
+GtkIconSize keyboard_capplet_icon_get_size (void);
+GtkIconSize mouse_capplet_icon_get_size (void);
+GtkIconSize mouse_capplet_dblclck_icon_get_size (void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CAPPLET_STOCK_ICONS_H__ */
diff --git a/capplets/common/capplet-util.c b/capplets/common/capplet-util.c
new file mode 100644
index 00000000..43d9485f
--- /dev/null
+++ b/capplets/common/capplet-util.c
@@ -0,0 +1,205 @@
+/* -*- mode: c; style: linux -*- */
+
+/* capplet-util.c
+ * Copyright (C) 2001 Ximian, Inc.
+ *
+ * Written by Bradford Hovinen <[email protected]>
+ *
+ * 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, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <ctype.h>
+
+/* For stat */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <glib/gi18n.h>
+#include <stdlib.h>
+
+#include "capplet-util.h"
+
+static void
+capplet_error_dialog (GtkWindow *parent, char const *msg, GError *err)
+{
+ if (err != NULL) {
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new (GTK_WINDOW (parent),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ msg, err->message);
+
+ g_signal_connect (G_OBJECT (dialog),
+ "response",
+ G_CALLBACK (gtk_widget_destroy), NULL);
+ gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
+ gtk_widget_show (dialog);
+ g_error_free (err);
+ }
+}
+
+/**
+ * capplet_help :
+ * @parent :
+ * @helpfile :
+ * @section :
+ *
+ * A quick utility routine to display help for capplets, and handle errors in a
+ * Havoc happy way.
+ **/
+void
+capplet_help (GtkWindow *parent, char const *section)
+{
+ GError *error = NULL;
+ char *uri;
+ GdkScreen *screen;
+
+ g_return_if_fail (section != NULL);
+
+ if (!parent)
+ screen = gdk_screen_get_default ();
+ else
+ screen = gtk_widget_get_screen (GTK_WIDGET (parent));
+
+ uri = g_strdup_printf ("ghelp:user-guide#%s", section);
+
+ if (!gtk_show_uri (screen, uri, gtk_get_current_event_time (), &error)) {
+ capplet_error_dialog (
+ parent,
+ _("There was an error displaying help: %s"),
+ error);
+ }
+
+ g_free (uri);
+}
+
+/**
+ * capplet_set_icon :
+ * @window :
+ * @file_name :
+ *
+ * A quick utility routine to avoid the cut-n-paste of bogus code
+ * that caused several bugs.
+ **/
+void
+capplet_set_icon (GtkWidget *window, char const *icon_file_name)
+{
+ /* Make sure that every window gets an icon */
+ gtk_window_set_default_icon_name (icon_file_name);
+ gtk_window_set_icon_name (GTK_WINDOW (window), icon_file_name);
+}
+
+static gboolean
+directory_delete_recursive (GFile *directory, GError **error)
+{
+ GFileEnumerator *enumerator;
+ GFileInfo *info;
+ gboolean success = TRUE;
+
+ enumerator = g_file_enumerate_children (directory,
+ G_FILE_ATTRIBUTE_STANDARD_NAME ","
+ G_FILE_ATTRIBUTE_STANDARD_TYPE,
+ G_FILE_QUERY_INFO_NONE,
+ NULL, error);
+ if (enumerator == NULL)
+ return FALSE;
+
+ while (success &&
+ (info = g_file_enumerator_next_file (enumerator, NULL, NULL))) {
+ GFile *child;
+
+ child = g_file_get_child (directory, g_file_info_get_name (info));
+
+ if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) {
+ success = directory_delete_recursive (child, error);
+ } else {
+ success = g_file_delete (child, NULL, error);
+ }
+ g_object_unref (info);
+ }
+ g_file_enumerator_close (enumerator, NULL, NULL);
+
+ if (success)
+ success = g_file_delete (directory, NULL, error);
+
+ return success;
+}
+
+/**
+ * capplet_file_delete_recursive :
+ * @file :
+ * @error :
+ *
+ * A utility routine to delete files and/or directories,
+ * including non-empty directories.
+ **/
+gboolean
+capplet_file_delete_recursive (GFile *file, GError **error)
+{
+ GFileInfo *info;
+ GFileType type;
+
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ info = g_file_query_info (file,
+ G_FILE_ATTRIBUTE_STANDARD_TYPE,
+ G_FILE_QUERY_INFO_NONE,
+ NULL, error);
+ if (info == NULL)
+ return FALSE;
+
+ type = g_file_info_get_file_type (info);
+ g_object_unref (info);
+
+ if (type == G_FILE_TYPE_DIRECTORY)
+ return directory_delete_recursive (file, error);
+ else
+ return g_file_delete (file, NULL, error);
+}
+
+void
+capplet_init (GOptionContext *context,
+ int *argc,
+ char ***argv)
+{
+ GError *err = NULL;
+
+#ifdef ENABLE_NLS
+ bindtextdomain (GETTEXT_PACKAGE, MATELOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+ textdomain (GETTEXT_PACKAGE);
+#endif
+
+ if (context) {
+#if GLIB_CHECK_VERSION (2, 12, 0)
+ g_option_context_set_translation_domain (context, GETTEXT_PACKAGE);
+#endif
+ g_option_context_add_group (context, gtk_get_option_group (TRUE));
+
+ if (!g_option_context_parse (context, argc, argv, &err)) {
+ g_printerr ("%s\n", err->message);
+ exit (1);
+ }
+ }
+
+ gtk_init (argc, argv);
+}
diff --git a/capplets/common/capplet-util.h b/capplets/common/capplet-util.h
new file mode 100644
index 00000000..b7caf4f0
--- /dev/null
+++ b/capplets/common/capplet-util.h
@@ -0,0 +1,46 @@
+/* -*- mode: c; style: linux -*- */
+
+/* capplet-util.h
+ * Copyright (C) 2001 Ximian, Inc.
+ *
+ * Written by Bradford Hovinen <[email protected]>
+ *
+ * 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, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef __CAPPLET_UTIL_H
+#define __CAPPLET_UTIL_H
+
+#include <gio/gio.h>
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+#include <mateconf/mateconf.h>
+#include <mateconf/mateconf-changeset.h>
+
+/* Macros to make certain repetitive tasks a bit easier */
+
+/* Retrieve a widget from the UI object */
+
+#define WID(s) GTK_WIDGET (gtk_builder_get_object (dialog, s))
+
+/* Some miscellaneous functions useful to all capplets */
+
+void capplet_help (GtkWindow *parent, char const *section);
+void capplet_set_icon (GtkWidget *window, char const *icon_file_name);
+gboolean capplet_file_delete_recursive (GFile *directory, GError **error);
+void capplet_init (GOptionContext *context, int *argc, char ***argv);
+
+#endif /* __CAPPLET_UTIL_H */
diff --git a/capplets/common/file-transfer-dialog.c b/capplets/common/file-transfer-dialog.c
new file mode 100644
index 00000000..a698520f
--- /dev/null
+++ b/capplets/common/file-transfer-dialog.c
@@ -0,0 +1,608 @@
+/* file-transfer-dialog.c
+ * Copyright (C) 2002 Ximian, Inc.
+ *
+ * Written by Rachel Hestilow <[email protected]>
+ * Jens Granseuer <[email protected]>
+ *
+ * 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, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <gio/gio.h>
+#include <limits.h>
+
+#include "file-transfer-dialog.h"
+
+enum
+{
+ PROP_0,
+ PROP_FROM_URI,
+ PROP_TO_URI,
+ PROP_FRACTION_COMPLETE,
+ PROP_NTH_URI,
+ PROP_TOTAL_URIS,
+ PROP_PARENT
+};
+
+enum
+{
+ CANCEL,
+ DONE,
+ LAST_SIGNAL
+};
+
+guint file_transfer_dialog_signals[LAST_SIGNAL] = {0, };
+
+struct _FileTransferDialogPrivate
+{
+ GtkWidget *progress;
+ GtkWidget *status;
+ guint nth;
+ guint total;
+ GCancellable *cancellable;
+};
+
+#define FILE_TRANSFER_DIALOG_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), file_transfer_dialog_get_type (), FileTransferDialogPrivate))
+
+typedef struct _FileTransferJob
+{
+ FileTransferDialog *dialog;
+ GtkDialog *overwrite_dialog;
+ GSList *source_files;
+ GSList *target_files;
+ FileTransferDialogOptions options;
+} FileTransferJob;
+
+/* structure passed to the various callbacks */
+typedef struct {
+ FileTransferDialog *dialog;
+ gchar *source;
+ gchar *target;
+ guint current_file;
+ guint total_files;
+ goffset current_bytes;
+ goffset total_bytes;
+ gint response;
+ GtkDialog *overwrite_dialog;
+} FileTransferData;
+
+G_DEFINE_TYPE (FileTransferDialog, file_transfer_dialog, GTK_TYPE_DIALOG)
+
+static void
+file_transfer_dialog_update_num_files (FileTransferDialog *dlg)
+{
+ gchar *str;
+
+ if (dlg->priv->total <= 1)
+ return;
+
+ str = g_strdup_printf (_("Copying file: %u of %u"),
+ dlg->priv->nth, dlg->priv->total);
+ gtk_progress_bar_set_text (GTK_PROGRESS_BAR (dlg->priv->progress), str);
+ g_free (str);
+}
+
+static void
+file_transfer_dialog_response (GtkDialog *dlg, gint response_id)
+{
+ FileTransferDialog *dialog = FILE_TRANSFER_DIALOG (dlg);
+
+ g_cancellable_cancel (dialog->priv->cancellable);
+}
+
+static void
+file_transfer_dialog_finalize (GObject *object)
+{
+ FileTransferDialog *dlg = FILE_TRANSFER_DIALOG (object);
+
+ if (dlg->priv->cancellable)
+ {
+ g_object_unref (dlg->priv->cancellable);
+ dlg->priv->cancellable = NULL;
+ }
+
+ G_OBJECT_CLASS (file_transfer_dialog_parent_class)->finalize (object);
+}
+
+static void
+file_transfer_dialog_set_prop (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+ FileTransferDialog *dlg = FILE_TRANSFER_DIALOG (object);
+ GFile *file;
+ gchar *str;
+ gchar *str2;
+ gchar *base;
+ gchar *escaped;
+ GtkWindow *parent;
+ guint n;
+
+ switch (prop_id)
+ {
+ case PROP_FROM_URI:
+ file = g_file_new_for_uri (g_value_get_string (value));
+ base = g_file_get_basename (file);
+ escaped = g_uri_escape_string (base, G_URI_RESERVED_CHARS_ALLOWED_IN_PATH, TRUE);
+
+ str = g_strdup_printf (_("Copying '%s'"), escaped);
+ str2 = g_strdup_printf ("<big><b>%s</b></big>", str);
+ gtk_label_set_markup (GTK_LABEL (dlg->priv->status), str2);
+
+ g_free (base);
+ g_free (escaped);
+ g_free (str);
+ g_free (str2);
+ g_object_unref (file);
+ break;
+ case PROP_TO_URI:
+ break;
+ case PROP_FRACTION_COMPLETE:
+ gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (dlg->priv->progress), g_value_get_double (value));
+ break;
+ case PROP_NTH_URI:
+ n = g_value_get_uint (value);
+ if (n != dlg->priv->nth)
+ {
+ dlg->priv->nth = g_value_get_uint (value);
+ file_transfer_dialog_update_num_files (dlg);
+ }
+ break;
+ case PROP_TOTAL_URIS:
+ n = g_value_get_uint (value);
+ if (n != dlg->priv->nth)
+ {
+ dlg->priv->total = g_value_get_uint (value);
+ file_transfer_dialog_update_num_files (dlg);
+ }
+ break;
+ case PROP_PARENT:
+ parent = g_value_get_pointer (value);
+ if (parent)
+ {
+ gtk_window_set_title (GTK_WINDOW (dlg), gtk_window_get_title (parent));
+ gtk_window_set_transient_for (GTK_WINDOW (dlg), parent);
+ }
+ else
+ gtk_window_set_title (GTK_WINDOW (dlg),
+ _("Copying files"));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+file_transfer_dialog_get_prop (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ FileTransferDialog *dlg = FILE_TRANSFER_DIALOG (object);
+
+ switch (prop_id)
+ {
+ case PROP_NTH_URI:
+ g_value_set_uint (value, dlg->priv->nth);
+ break;
+ case PROP_TOTAL_URIS:
+ g_value_set_uint (value, dlg->priv->total);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+file_transfer_dialog_class_init (FileTransferDialogClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = file_transfer_dialog_finalize;
+ object_class->get_property = file_transfer_dialog_get_prop;
+ object_class->set_property = file_transfer_dialog_set_prop;
+
+ GTK_DIALOG_CLASS (klass)->response = file_transfer_dialog_response;
+
+ g_object_class_install_property
+ (object_class, PROP_PARENT,
+ g_param_spec_pointer ("parent",
+ _("Parent Window"),
+ _("Parent window of the dialog"),
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property
+ (object_class, PROP_FROM_URI,
+ g_param_spec_string ("from_uri",
+ _("From URI"),
+ _("URI currently transferring from"),
+ NULL,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property
+ (object_class, PROP_TO_URI,
+ g_param_spec_string ("to_uri",
+ _("To URI"),
+ _("URI currently transferring to"),
+ NULL,
+ G_PARAM_WRITABLE));
+
+ g_object_class_install_property
+ (object_class, PROP_FRACTION_COMPLETE,
+ g_param_spec_double ("fraction_complete",
+ _("Fraction completed"),
+ _("Fraction of transfer currently completed"),
+ 0, 1, 0,
+ G_PARAM_WRITABLE));
+
+ g_object_class_install_property
+ (object_class, PROP_NTH_URI,
+ g_param_spec_uint ("nth_uri",
+ _("Current URI index"),
+ _("Current URI index - starts from 1"),
+ 1, INT_MAX, 1,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property
+ (object_class, PROP_TOTAL_URIS,
+ g_param_spec_uint ("total_uris",
+ _("Total URIs"),
+ _("Total number of URIs"),
+ 1, INT_MAX, 1,
+ G_PARAM_READWRITE));
+
+ file_transfer_dialog_signals[CANCEL] =
+ g_signal_new ("cancel",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_FIRST,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ file_transfer_dialog_signals[DONE] =
+ g_signal_new ("done",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ g_type_class_add_private (klass, sizeof (FileTransferDialogPrivate));
+}
+
+static void
+file_transfer_dialog_init (FileTransferDialog *dlg)
+{
+ GtkWidget *vbox;
+ GtkWidget *hbox;
+ GtkWidget *progress_vbox;
+ GtkWidget *table;
+ char *markup;
+ GtkWidget *content_area;
+
+ content_area = gtk_dialog_get_content_area (GTK_DIALOG (dlg));
+ dlg->priv = FILE_TRANSFER_DIALOG_GET_PRIVATE (dlg);
+ dlg->priv->cancellable = g_cancellable_new ();
+
+ gtk_container_set_border_width (GTK_CONTAINER (content_area), 4);
+ gtk_box_set_spacing (GTK_BOX (content_area), 4);
+
+ gtk_widget_set_size_request (GTK_WIDGET (dlg), 350, -1);
+
+ vbox = gtk_vbox_new (FALSE, 6);
+ gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
+ gtk_box_pack_start (GTK_BOX (content_area), vbox, TRUE, TRUE, 0);
+
+ dlg->priv->status = gtk_label_new (NULL);
+ markup = g_strconcat ("<big><b>", _("Copying files"), "</b></big>", NULL);
+ gtk_label_set_markup (GTK_LABEL (dlg->priv->status), markup);
+ g_free (markup);
+
+ gtk_misc_set_alignment (GTK_MISC (dlg->priv->status), 0.0, 0.0);
+
+ gtk_box_pack_start (GTK_BOX (vbox), dlg->priv->status, FALSE, FALSE, 0);
+
+ hbox = gtk_hbox_new (FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
+
+ table = gtk_table_new (2, 2, FALSE);
+ gtk_table_set_row_spacings (GTK_TABLE (table), 4);
+ gtk_table_set_col_spacings (GTK_TABLE (table), 4);
+
+ gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET (table), FALSE, FALSE, 0);
+
+ progress_vbox = gtk_vbox_new (TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (vbox), progress_vbox, FALSE, FALSE, 0);
+
+ dlg->priv->progress = gtk_progress_bar_new ();
+ gtk_box_pack_start (GTK_BOX (progress_vbox),
+ dlg->priv->progress, FALSE, FALSE, 0);
+
+ gtk_dialog_add_button (GTK_DIALOG (dlg),
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
+
+ gtk_dialog_set_has_separator (GTK_DIALOG (dlg), FALSE);
+ gtk_container_set_border_width (GTK_CONTAINER (dlg), 6);
+
+ gtk_widget_show_all (content_area);
+}
+
+GtkWidget*
+file_transfer_dialog_new (void)
+{
+ return GTK_WIDGET (g_object_new (file_transfer_dialog_get_type (),
+ NULL));
+}
+
+GtkWidget*
+file_transfer_dialog_new_with_parent (GtkWindow *parent)
+{
+ return GTK_WIDGET (g_object_new (file_transfer_dialog_get_type (),
+ "parent", parent, NULL));
+}
+
+static gboolean
+file_transfer_job_update (gpointer user_data)
+{
+ FileTransferData *data = user_data;
+ gdouble fraction;
+ gdouble current_fraction;
+
+ if (data->total_bytes == 0)
+ current_fraction = 0.0;
+ else
+ current_fraction = ((gdouble) data->current_bytes) / data->total_bytes;
+
+ fraction = ((gdouble) data->current_file - 1) / data->total_files +
+ (1.0 / data->total_files) * current_fraction;
+
+ g_object_set (data->dialog,
+ "from_uri", data->source,
+ "to_uri", data->target,
+ "nth_uri", data->current_file,
+ "fraction_complete", fraction,
+ NULL);
+ return FALSE;
+}
+
+static void
+file_transfer_job_progress (goffset current_bytes,
+ goffset total_bytes,
+ gpointer user_data)
+{
+ FileTransferData *data = user_data;
+
+ data->current_bytes = current_bytes;
+ data->total_bytes = total_bytes;
+
+ gdk_threads_enter ();
+ file_transfer_job_update (data);
+ gdk_threads_leave ();
+}
+
+static void
+file_transfer_job_destroy (FileTransferJob *job)
+{
+ g_object_unref (job->dialog);
+ g_slist_foreach (job->source_files, (GFunc) g_object_unref, NULL);
+ g_slist_foreach (job->target_files, (GFunc) g_object_unref, NULL);
+ g_slist_free (job->source_files);
+ g_slist_free (job->target_files);
+ if (job->overwrite_dialog != NULL)
+ gtk_widget_destroy (GTK_WIDGET (job->overwrite_dialog));
+ g_free (job);
+}
+
+static gboolean
+file_transfer_dialog_done (FileTransferDialog *dialog)
+{
+ g_signal_emit (dialog,
+ file_transfer_dialog_signals[DONE],
+ 0, NULL);
+ return FALSE;
+}
+
+static gboolean
+file_transfer_dialog_cancel (FileTransferDialog *dialog)
+{
+ g_signal_emit (dialog,
+ file_transfer_dialog_signals[CANCEL],
+ 0, NULL);
+ return FALSE;
+}
+
+static gboolean
+file_transfer_dialog_overwrite (gpointer user_data)
+{
+ FileTransferData *data = user_data;
+ GtkDialog *dialog;
+
+ dialog = data->overwrite_dialog;
+
+ if (dialog != NULL) {
+ } else {
+ GtkWidget *button;
+
+ dialog = GTK_DIALOG (gtk_message_dialog_new (GTK_WINDOW (data->dialog),
+ GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_NONE,
+ _("File '%s' already exists. Do you want to overwrite it?"),
+ data->target));
+
+ gtk_dialog_add_button (dialog, _("_Skip"), GTK_RESPONSE_NO);
+ gtk_dialog_add_button (dialog, _("Overwrite _All"), GTK_RESPONSE_APPLY);
+
+ button = gtk_button_new_with_label (_("_Overwrite"));
+ gtk_button_set_image (GTK_BUTTON (button),
+ gtk_image_new_from_stock (GTK_STOCK_APPLY,
+ GTK_ICON_SIZE_BUTTON));
+ gtk_dialog_add_action_widget (dialog, button, GTK_RESPONSE_YES);
+ gtk_widget_show (button);
+
+ data->overwrite_dialog = dialog;
+ }
+
+ data->response = gtk_dialog_run (dialog);
+
+ gtk_widget_hide (GTK_WIDGET (dialog));
+ return FALSE;
+}
+
+/* TODO: support transferring directories recursively? */
+static gboolean
+file_transfer_job_schedule (GIOSchedulerJob *io_job,
+ GCancellable *cancellable,
+ FileTransferJob *job)
+{
+ GFile *source, *target;
+ gboolean success;
+ GFileCopyFlags copy_flags = G_FILE_COPY_NONE;
+ FileTransferData data;
+ GError *error;
+ gboolean retry;
+
+ /* take the first file from the list and copy it */
+ source = job->source_files->data;
+ job->source_files = g_slist_delete_link (job->source_files, job->source_files);
+
+ target = job->target_files->data;
+ job->target_files = g_slist_delete_link (job->target_files, job->target_files);
+
+ data.dialog = job->dialog;
+ data.overwrite_dialog = job->overwrite_dialog;
+ data.current_file = job->dialog->priv->nth + 1;
+ data.total_files = job->dialog->priv->total;
+ data.current_bytes = data.total_bytes = 0;
+ data.source = g_file_get_basename (source);
+ data.target = g_file_get_basename (target);
+
+ g_io_scheduler_job_send_to_mainloop (io_job,
+ file_transfer_job_update,
+ &data,
+ NULL);
+
+ if (job->options & FILE_TRANSFER_DIALOG_OVERWRITE)
+ copy_flags |= G_FILE_COPY_OVERWRITE;
+
+ do {
+ retry = FALSE;
+ error = NULL;
+ success = g_file_copy (source, target,
+ copy_flags,
+ job->dialog->priv->cancellable,
+ file_transfer_job_progress,
+ &data,
+ &error);
+
+ if (error != NULL)
+ {
+ if (error->domain == G_IO_ERROR &&
+ error->code == G_IO_ERROR_EXISTS)
+ {
+ /* since the job is run in a thread, we cannot simply run
+ * a dialog here and need to defer it to the mainloop */
+ data.response = GTK_RESPONSE_NONE;
+ g_io_scheduler_job_send_to_mainloop (io_job,
+ file_transfer_dialog_overwrite,
+ &data,
+ NULL);
+
+ if (data.response == GTK_RESPONSE_YES) {
+ retry = TRUE;
+ copy_flags |= G_FILE_COPY_OVERWRITE;
+ } else if (data.response == GTK_RESPONSE_APPLY) {
+ retry = TRUE;
+ job->options |= FILE_TRANSFER_DIALOG_OVERWRITE;
+ copy_flags |= G_FILE_COPY_OVERWRITE;
+ } else {
+ success = TRUE;
+ }
+
+ job->overwrite_dialog = data.overwrite_dialog;
+ }
+ g_error_free (error);
+ }
+ } while (retry);
+
+ g_object_unref (source);
+ g_object_unref (target);
+
+ g_free (data.source);
+ g_free (data.target);
+
+ if (success)
+ {
+ if (job->source_files == NULL)
+ {
+ g_io_scheduler_job_send_to_mainloop_async (io_job,
+ (GSourceFunc) file_transfer_dialog_done,
+ g_object_ref (job->dialog),
+ g_object_unref);
+ return FALSE;
+ }
+ }
+ else /* error on copy or cancelled */
+ {
+ g_io_scheduler_job_send_to_mainloop_async (io_job,
+ (GSourceFunc) file_transfer_dialog_cancel,
+ g_object_ref (job->dialog),
+ g_object_unref);
+ return FALSE;
+ }
+
+ /* more work to do... */
+ return TRUE;
+}
+
+void
+file_transfer_dialog_copy_async (FileTransferDialog *dlg,
+ GList *source_files,
+ GList *target_files,
+ FileTransferDialogOptions options,
+ int priority)
+{
+ FileTransferJob *job;
+ GList *l;
+ guint n;
+
+ job = g_new0 (FileTransferJob, 1);
+ job->dialog = g_object_ref (dlg);
+ job->options = options;
+
+ /* we need to copy the list contents for private use */
+ n = 0;
+ for (l = g_list_last (source_files); l; l = l->prev, ++n)
+ {
+ job->source_files = g_slist_prepend (job->source_files,
+ g_object_ref (l->data));
+ }
+ for (l = g_list_last (target_files); l; l = l->prev)
+ {
+ job->target_files = g_slist_prepend (job->target_files,
+ g_object_ref (l->data));
+ }
+
+ g_object_set (dlg, "total_uris", n, NULL);
+
+ g_io_scheduler_push_job ((GIOSchedulerJobFunc) file_transfer_job_schedule,
+ job,
+ (GDestroyNotify) file_transfer_job_destroy,
+ priority,
+ dlg->priv->cancellable);
+}
diff --git a/capplets/common/file-transfer-dialog.h b/capplets/common/file-transfer-dialog.h
new file mode 100644
index 00000000..0b867005
--- /dev/null
+++ b/capplets/common/file-transfer-dialog.h
@@ -0,0 +1,73 @@
+/* -*- mode: c; style: linux -*- */
+
+/* file-transfer-dialog.h
+ * Copyright (C) 2002 Ximian, Inc.
+ *
+ * Written by Rachel Hestilow <[email protected]>
+ *
+ * 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, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef __FILE_TRANSFER_DIALOG_H__
+#define __FILE_TRANSFER_DIALOG_H__
+
+#include <gtk/gtk.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define FILE_TRANSFER_DIALOG(obj) G_TYPE_CHECK_INSTANCE_CAST (obj, file_transfer_dialog_get_type (), FileTransferDialog)
+#define FILE_TRANSFER_DIALOG_CLASS(klass) G_TYPE_CHECK_CLASS_CAST (klass, file_transfer_dialog_get_type (), FileTransferDialogClass)
+#define IS_FILE_TRANSFER_DIALOG(obj) G_TYPE_CHECK_INSTANCE_TYPE (obj, file_transfer_dialog_get_type ())
+
+typedef struct _FileTransferDialog FileTransferDialog;
+typedef struct _FileTransferDialogClass FileTransferDialogClass;
+typedef struct _FileTransferDialogPrivate FileTransferDialogPrivate;
+
+typedef enum {
+ FILE_TRANSFER_DIALOG_DEFAULT = 1 << 0,
+ FILE_TRANSFER_DIALOG_OVERWRITE = 1 << 1
+} FileTransferDialogOptions;
+
+struct _FileTransferDialog
+{
+ GtkDialog dialog;
+
+ FileTransferDialogPrivate *priv;
+};
+
+struct _FileTransferDialogClass
+{
+ GtkDialogClass parent_class;
+};
+
+GType file_transfer_dialog_get_type (void);
+GtkWidget* file_transfer_dialog_new (void);
+GtkWidget* file_transfer_dialog_new_with_parent (GtkWindow *parent);
+
+void file_transfer_dialog_copy_async (FileTransferDialog *dlg,
+ GList *source_files,
+ GList *target_files,
+ FileTransferDialogOptions options,
+ int priority);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __FILE_TRANSFER_DIALOG_H__ */
diff --git a/capplets/common/gtkrc-utils.c b/capplets/common/gtkrc-utils.c
new file mode 100644
index 00000000..be03faa5
--- /dev/null
+++ b/capplets/common/gtkrc-utils.c
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2007 The MATE Foundation
+ * Written by Thomas Wood <[email protected]>
+ * Jens Granseuer <[email protected]>
+ * All Rights Reserved
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <unistd.h>
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <fcntl.h>
+#include <gtk/gtk.h>
+
+#define INCLUDE_SYMBOL ((gpointer) 1)
+#define ENGINE_SYMBOL ((gpointer) 2)
+#define COLOR_SCHEME_SYMBOL ((gpointer) 3)
+
+gchar* gtkrc_find_named(const gchar* name)
+{
+ /* find the gtkrc of the named theme
+ * taken from gtkrc.c (gtk_rc_parse_named)
+ */
+ gchar* path = NULL;
+ const gchar* home_dir;
+ const gchar* subpath = "gtk-2.0" G_DIR_SEPARATOR_S "gtkrc";
+
+ /* First look in the users home directory
+ */
+ home_dir = g_get_home_dir();
+
+ if (home_dir)
+ {
+ path = g_build_filename(home_dir, ".themes", name, subpath, NULL);
+
+ if (!g_file_test (path, G_FILE_TEST_EXISTS))
+ {
+ g_free (path);
+ path = NULL;
+ }
+ }
+
+ if (!path)
+ {
+ gchar* theme_dir = gtk_rc_get_theme_dir();
+ path = g_build_filename(theme_dir, name, subpath, NULL);
+ g_free(theme_dir);
+
+ if (!g_file_test(path, G_FILE_TEST_EXISTS))
+ {
+ g_free (path);
+ path = NULL;
+ }
+ }
+
+ return path;
+
+}
+
+void gtkrc_get_details(gchar* filename, GSList** engines, GSList** symbolic_colors)
+{
+ gint file = -1;
+ GSList* files = NULL;
+ GSList* read_files = NULL;
+ GTokenType token;
+ GScanner *scanner = g_scanner_new (NULL);
+
+ g_scanner_scope_add_symbol (scanner, 0, "include", INCLUDE_SYMBOL);
+
+ if (engines != NULL)
+ {
+ g_scanner_scope_add_symbol (scanner, 0, "engine", ENGINE_SYMBOL);
+ }
+
+ files = g_slist_prepend (files, g_strdup (filename));
+
+ while (files != NULL)
+ {
+ filename = files->data;
+ files = g_slist_delete_link (files, files);
+
+ if (filename == NULL)
+ continue;
+
+ if (g_slist_find_custom (read_files, filename, (GCompareFunc) strcmp))
+ {
+ g_warning ("Recursion in the gtkrc detected!");
+ g_free (filename);
+ continue; /* skip this file since we've done it before... */
+ }
+
+ read_files = g_slist_prepend (read_files, filename);
+
+ file = g_open (filename, O_RDONLY);
+ if (file == -1)
+ {
+ g_warning ("Could not open file \"%s\"", filename);
+ }
+ else
+ {
+ g_scanner_input_file (scanner, file);
+ while ((token = g_scanner_get_next_token (scanner)) != G_TOKEN_EOF)
+ {
+ GTokenType string_token;
+ if (token == '@')
+ {
+ if (symbolic_colors == NULL)
+ continue;
+ token = g_scanner_get_next_token (scanner);
+ if (token != G_TOKEN_IDENTIFIER)
+ continue;
+ if (!g_slist_find_custom (*symbolic_colors, scanner->value.v_identifier, (GCompareFunc) strcmp))
+ *symbolic_colors = g_slist_append (*symbolic_colors, g_strdup (scanner->value.v_identifier));
+ continue;
+ }
+
+ if (token != G_TOKEN_SYMBOL)
+ continue;
+
+ if (scanner->value.v_symbol == INCLUDE_SYMBOL)
+ {
+ string_token = g_scanner_get_next_token (scanner);
+ if (string_token != G_TOKEN_STRING)
+ continue;
+ if (g_path_is_absolute (scanner->value.v_string))
+ {
+ files = g_slist_prepend (files, g_strdup (scanner->value.v_string));
+ }
+ else
+ {
+ gchar *basedir = g_path_get_dirname (filename);
+ files = g_slist_prepend (files, g_build_path (G_DIR_SEPARATOR_S, basedir, scanner->value.v_string, NULL));
+ g_free (basedir);
+ }
+ }
+ else if (scanner->value.v_symbol == ENGINE_SYMBOL)
+ {
+ string_token = g_scanner_get_next_token (scanner);
+ if (string_token != G_TOKEN_STRING || scanner->value.v_string[0] == '\0')
+ continue;
+ if (!g_slist_find_custom (*engines, scanner->value.v_string, (GCompareFunc) strcmp))
+ *engines = g_slist_append (*engines, g_strdup (scanner->value.v_string));
+ }
+
+ }
+ close (file);
+ }
+ }
+
+ g_slist_foreach (read_files, (GFunc) g_free, NULL);
+ g_slist_free (read_files);
+
+ g_scanner_destroy (scanner);
+}
+
+
+gchar *
+gtkrc_get_color_scheme (const gchar *gtkrc_file)
+{
+ gint file = -1;
+ gchar *result = NULL;
+ GSList *files = NULL;
+ GSList *read_files = NULL;
+ GTokenType token;
+ GScanner *scanner = gtk_rc_scanner_new ();
+
+ g_scanner_scope_add_symbol (scanner, 0, "include", INCLUDE_SYMBOL);
+ g_scanner_scope_add_symbol (scanner, 0, "gtk_color_scheme", COLOR_SCHEME_SYMBOL);
+ g_scanner_scope_add_symbol (scanner, 0, "gtk-color-scheme", COLOR_SCHEME_SYMBOL);
+
+ files = g_slist_prepend (files, g_strdup (gtkrc_file));
+ while (files != NULL)
+ {
+ gchar *filename = files->data;
+ files = g_slist_delete_link (files, files);
+
+ if (filename == NULL)
+ continue;
+
+ if (g_slist_find_custom (read_files, filename, (GCompareFunc) strcmp))
+ {
+ g_warning ("Recursion in the gtkrc detected!");
+ g_free (filename);
+ continue; /* skip this file since we've done it before... */
+ }
+
+ read_files = g_slist_prepend (read_files, filename);
+
+ file = g_open (filename, O_RDONLY);
+ if (file == -1)
+ {
+ g_warning ("Could not open file \"%s\"", filename);
+ }
+ else
+ {
+ g_scanner_input_file (scanner, file);
+ while ((token = g_scanner_get_next_token (scanner)) != G_TOKEN_EOF)
+ {
+ if (GINT_TO_POINTER (token) == COLOR_SCHEME_SYMBOL)
+ {
+ if (g_scanner_get_next_token (scanner) == '=')
+ {
+ token = g_scanner_get_next_token (scanner);
+ if (token == G_TOKEN_STRING)
+ {
+ g_free (result);
+ result = g_strdup (scanner->value.v_string);
+ }
+ }
+ }
+ }
+ close (file);
+ }
+ }
+
+ g_slist_foreach (read_files, (GFunc) g_free, NULL);
+ g_slist_free (read_files);
+
+ g_scanner_destroy (scanner);
+ return result;
+}
+
+gchar* gtkrc_get_color_scheme_for_theme(const gchar* theme_name)
+{
+ /* try to find the color scheme from the gtkrc */
+ gchar* gtkrc_file;
+ gchar* scheme = NULL;
+
+ gtkrc_file = gtkrc_find_named(theme_name);
+
+ if (gtkrc_file)
+ {
+ scheme = gtkrc_get_color_scheme(gtkrc_file);
+ g_free(gtkrc_file);
+ }
+
+ return scheme;
+}
diff --git a/capplets/common/gtkrc-utils.h b/capplets/common/gtkrc-utils.h
new file mode 100644
index 00000000..1023fe14
--- /dev/null
+++ b/capplets/common/gtkrc-utils.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2007 The MATE Foundation
+ * Written by Thomas Wood <[email protected]>
+ * Jens Granseuer <[email protected]>
+ * All Rights Reserved
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+void gtkrc_get_details (gchar *filename, GSList **engines, GSList **symbolic_colors);
+gchar * gtkrc_find_named (const gchar *name);
+gchar * gtkrc_get_color_scheme (const gchar *filename);
+gchar * gtkrc_get_color_scheme_for_theme (const gchar *theme_name);
diff --git a/capplets/common/mate-theme-apply.c b/capplets/common/mate-theme-apply.c
new file mode 100644
index 00000000..b1c772e8
--- /dev/null
+++ b/capplets/common/mate-theme-apply.c
@@ -0,0 +1,136 @@
+/* -*- mode: C; c-basic-offset: 4 -*-
+ * themus - utilities for MATE themes
+ * Copyright (C) 2002 Jonathan Blandford <[email protected]>
+ *
+ * This library 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.1 of the License, or (at your option) any later version.
+ *
+ * This library 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.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <mateconf/mateconf-client.h>
+#include <mate-wm-manager.h>
+#include "mate-theme-apply.h"
+#include "gtkrc-utils.h"
+
+#define GTK_THEME_KEY "/desktop/mate/interface/gtk_theme"
+#define COLOR_SCHEME_KEY "/desktop/mate/interface/gtk_color_scheme"
+#define ICON_THEME_KEY "/desktop/mate/interface/icon_theme"
+#define FONT_KEY "/desktop/mate/interface/font_name"
+#define CURSOR_FONT_KEY "/desktop/mate/peripherals/mouse/cursor_font"
+#define CURSOR_THEME_KEY "/desktop/mate/peripherals/mouse/cursor_theme"
+#define CURSOR_SIZE_KEY "/desktop/mate/peripherals/mouse/cursor_size"
+#define NOTIFICATION_THEME_KEY "/apps/notification-daemon/theme"
+
+#define compare(x,y) (!x && y) || (x && !y) || (x && y && strcmp (x, y))
+
+void
+mate_meta_theme_set (MateThemeMetaInfo *meta_theme_info)
+{
+ MateConfClient *client;
+ gchar *old_key;
+ gint old_key_int;
+ MateWindowManager *window_manager;
+ MateWMSettings wm_settings;
+
+ mate_wm_manager_init ();
+
+ window_manager = mate_wm_manager_get_current (gdk_display_get_default_screen (gdk_display_get_default ()));
+
+ client = mateconf_client_get_default ();
+
+ /* Set the gtk+ key */
+ old_key = mateconf_client_get_string (client, GTK_THEME_KEY, NULL);
+ if (compare (old_key, meta_theme_info->gtk_theme_name))
+ {
+ mateconf_client_set_string (client, GTK_THEME_KEY, meta_theme_info->gtk_theme_name, NULL);
+ }
+ g_free (old_key);
+
+ /* Set the color scheme key */
+ old_key = mateconf_client_get_string (client, COLOR_SCHEME_KEY, NULL);
+ if (compare (old_key, meta_theme_info->gtk_color_scheme))
+ {
+ /* only save the color scheme if it differs from the default
+ scheme for the selected gtk theme */
+ gchar *newval, *gtkcols;
+
+ newval = meta_theme_info->gtk_color_scheme;
+ gtkcols = gtkrc_get_color_scheme_for_theme (meta_theme_info->gtk_theme_name);
+
+ if (newval == NULL || !strcmp (newval, "") ||
+ mate_theme_color_scheme_equal (newval, gtkcols))
+ {
+ mateconf_client_unset (client, COLOR_SCHEME_KEY, NULL);
+ }
+ else
+ {
+ mateconf_client_set_string (client, COLOR_SCHEME_KEY, newval, NULL);
+ }
+ g_free (gtkcols);
+ }
+ g_free (old_key);
+
+ /* Set the wm key */
+ wm_settings.flags = MATE_WM_SETTING_THEME;
+ wm_settings.theme = meta_theme_info->marco_theme_name;
+ if (window_manager)
+ mate_window_manager_change_settings (window_manager, &wm_settings);
+
+ /* set the icon theme */
+ old_key = mateconf_client_get_string (client, ICON_THEME_KEY, NULL);
+ if (compare (old_key, meta_theme_info->icon_theme_name))
+ {
+ mateconf_client_set_string (client, ICON_THEME_KEY, meta_theme_info->icon_theme_name, NULL);
+ }
+ g_free (old_key);
+
+ /* set the notification theme */
+ if (meta_theme_info->notification_theme_name != NULL)
+ {
+ old_key = mateconf_client_get_string (client, NOTIFICATION_THEME_KEY, NULL);
+ if (compare (old_key, meta_theme_info->notification_theme_name))
+ {
+ mateconf_client_set_string (client, NOTIFICATION_THEME_KEY, meta_theme_info->notification_theme_name, NULL);
+ }
+ g_free (old_key);
+ }
+
+ /* Set the cursor theme key */
+#ifdef HAVE_XCURSOR
+ old_key = mateconf_client_get_string (client, CURSOR_THEME_KEY, NULL);
+ if (compare (old_key, meta_theme_info->cursor_theme_name))
+ {
+ mateconf_client_set_string (client, CURSOR_THEME_KEY, meta_theme_info->cursor_theme_name, NULL);
+ }
+
+ old_key_int = mateconf_client_get_int (client, CURSOR_SIZE_KEY, NULL);
+ if (old_key_int != meta_theme_info->cursor_size)
+ {
+ mateconf_client_set_int (client, CURSOR_SIZE_KEY, meta_theme_info->cursor_size, NULL);
+ }
+#else
+ old_key = mateconf_client_get_string (client, CURSOR_FONT_KEY, NULL);
+ if (compare (old_key, meta_theme_info->cursor_theme_name))
+ {
+ mateconf_client_set_string (client, CURSOR_FONT_KEY, meta_theme_info->cursor_theme_name, NULL);
+ }
+#endif
+
+ g_free (old_key);
+ g_object_unref (client);
+}
diff --git a/capplets/common/mate-theme-apply.h b/capplets/common/mate-theme-apply.h
new file mode 100644
index 00000000..d89d8d06
--- /dev/null
+++ b/capplets/common/mate-theme-apply.h
@@ -0,0 +1,33 @@
+/* mate-theme-info.h - MATE Theme information
+
+ Copyright (C) 2002 Jonathan Blandford <[email protected]>
+ All rights reserved.
+
+ This file is part of the Mate Library.
+
+ The Mate Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Mate Library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Mate Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+/*
+ @NOTATION@
+ */
+
+#ifndef THEME_APPLY_H
+#define THEME_APPLY_H
+
+#include "mate-theme-info.h"
+
+void mate_meta_theme_set (MateThemeMetaInfo *meta_theme_info);
+
+#endif /* THEME_APPLY_H */
diff --git a/capplets/common/mate-theme-info.c b/capplets/common/mate-theme-info.c
new file mode 100644
index 00000000..aead0b34
--- /dev/null
+++ b/capplets/common/mate-theme-info.c
@@ -0,0 +1,1988 @@
+/* mate-theme-info.c - MATE Theme information
+ *
+ * Copyright (C) 2002 Jonathan Blandford <[email protected]>
+ * Copyright (C) 2011 Perberos
+ * All rights reserved.
+ *
+ * This file is part of the Mate Library.
+ *
+ * The Mate Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Mate Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Mate Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+ #include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <glib/gi18n.h>
+#include <gmodule.h>
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+#include <gio/gio.h>
+#include <string.h>
+#include <libmate/mate-desktop-item.h>
+#include "mate-theme-info.h"
+#include "gtkrc-utils.h"
+
+#ifdef HAVE_XCURSOR
+ #include <X11/Xcursor/Xcursor.h>
+#endif
+
+#define THEME_NAME "X-GNOME-Metatheme/Name"
+#define THEME_COMMENT "X-GNOME-Metatheme/Comment"
+#define GTK_THEME_KEY "X-GNOME-Metatheme/GtkTheme"
+#define GTK_COLOR_SCHEME_KEY "X-GNOME-Metatheme/GtkColorScheme"
+#define MARCO_THEME_KEY "X-GNOME-Metatheme/MetacityTheme"
+#define ICON_THEME_KEY "X-GNOME-Metatheme/IconTheme"
+#define CURSOR_THEME_KEY "X-GNOME-Metatheme/CursorTheme"
+#define NOTIFICATION_THEME_KEY "X-GNOME-Metatheme/NotificationTheme"
+#define CURSOR_SIZE_KEY "X-GNOME-Metatheme/CursorSize"
+#define SOUND_THEME_KEY "X-GNOME-Metatheme/SoundTheme"
+#define APPLICATION_FONT_KEY "X-GNOME-Metatheme/ApplicationFont"
+#define DOCUMENTS_FONT_KEY "X-GNOME-Metatheme/DocumentsFont"
+#define DESKTOP_FONT_KEY "X-GNOME-Metatheme/DesktopFont"
+#define WINDOWTITLE_FONT_KEY "X-GNOME-Metatheme/WindowTitleFont"
+#define MONOSPACE_FONT_KEY "X-GNOME-Metatheme/MonospaceFont"
+#define BACKGROUND_IMAGE_KEY "X-GNOME-Metatheme/BackgroundImage"
+#define HIDDEN_KEY "X-GNOME-Metatheme/Hidden"
+
+/* Terminology used in this lib:
+ *
+ * /usr/share/themes, ~/.themes -- top_theme_dir
+ * top_theme_dir/theme_name/ -- common_theme_dir
+ * /usr/share/icons, ~/.icons -- top_icon_theme_dir
+ * top_icon_theme_dir/theme_name/ -- icon_common_theme_dir
+ *
+ */
+
+typedef struct _ThemeCallbackData {
+ ThemeChangedCallback func;
+ gpointer data;
+} ThemeCallbackData;
+
+typedef struct {
+ GFileMonitor* common_theme_dir_handle;
+ GFileMonitor* gtk2_dir_handle;
+ GFileMonitor* keybinding_dir_handle;
+ GFileMonitor* marco_dir_handle;
+ gint priority;
+} CommonThemeDirMonitorData;
+
+typedef struct {
+ GFileMonitor* common_icon_theme_dir_handle;
+ gint priority;
+} CommonIconThemeDirMonitorData;
+
+typedef struct {
+ GHashTable* handle_hash;
+ gint priority;
+} CallbackTuple;
+
+
+/* Hash tables */
+
+/* The hashes_by_dir are indexed by an escaped uri of the common_theme_dir that
+ * that particular theme is part of. The data pointed to by them is a
+ * MateTheme{Meta,Icon,}Info struct. Note that the uri is of the form
+ * "file:///home/username/.themes/foo", and not "/home/username/.themes/foo"
+ */
+
+/* The hashes_by_name are hashed by the index of the theme. The data pointed to
+ * by them is a GList whose data elements are MateTheme{Meta,Icon,}Info
+ * structs. This is because a theme can be found both in the users ~/.theme as
+ * well as globally in $prefix. All access to them must be done via helper
+ * functions.
+ */
+static GList* callbacks = NULL;
+
+static GHashTable* meta_theme_hash_by_uri;
+static GHashTable* meta_theme_hash_by_name;
+static GHashTable* icon_theme_hash_by_uri;
+static GHashTable* icon_theme_hash_by_name;
+static GHashTable* cursor_theme_hash_by_uri;
+static GHashTable* cursor_theme_hash_by_name;
+static GHashTable* theme_hash_by_uri;
+static GHashTable* theme_hash_by_name;
+static gboolean initting = FALSE;
+
+/* private functions */
+static gint safe_strcmp(const gchar* a_str, const gchar* b_str)
+{
+ if (a_str && b_str)
+ {
+ return strcmp(a_str, b_str);
+ }
+ else
+ {
+ return a_str - b_str;
+ }
+}
+
+static GFileType
+get_file_type (GFile *file)
+{
+ GFileType file_type = G_FILE_TYPE_UNKNOWN;
+ GFileInfo *file_info;
+
+ file_info = g_file_query_info (file,
+ G_FILE_ATTRIBUTE_STANDARD_TYPE,
+ G_FILE_QUERY_INFO_NONE,
+ NULL, NULL);
+ if (file_info != NULL) {
+ file_type = g_file_info_get_file_type (file_info);
+ g_object_unref (file_info);
+ }
+
+ return file_type;
+}
+
+static void
+add_theme_to_hash_by_name (GHashTable *hash_table,
+ gpointer data)
+{
+ MateThemeCommonInfo *info = data;
+ GList *list;
+
+ list = g_hash_table_lookup (hash_table, info->name);
+ if (list == NULL) {
+ list = g_list_append (list, info);
+ } else {
+ GList *list_ptr = list;
+ gboolean added = FALSE;
+
+ while (list_ptr) {
+ gint theme_priority;
+
+ theme_priority = ((MateThemeCommonInfo *) list_ptr->data)->priority;
+
+ if (theme_priority == info->priority) {
+ /* Swap it in */
+ list_ptr->data = info;
+ added = TRUE;
+ break;
+ } else if (theme_priority > info->priority) {
+ list = g_list_insert_before (list, list_ptr, info);
+ added = TRUE;
+ break;
+ }
+ list_ptr = list_ptr->next;
+ }
+ if (!added)
+ list = g_list_append (list, info);
+ }
+ g_hash_table_insert (hash_table, g_strdup (info->name), list);
+}
+
+static void
+remove_theme_from_hash_by_name (GHashTable *hash_table,
+ gpointer data)
+{
+ MateThemeCommonInfo *info = data;
+ GList *list;
+
+ list = g_hash_table_lookup (hash_table, info->name);
+
+ list = g_list_remove (list, info);
+ if (list == NULL)
+ g_hash_table_remove (hash_table, info->name);
+ else
+ g_hash_table_insert (hash_table, g_strdup (info->name), list);
+}
+
+static MateThemeCommonInfo *
+get_theme_from_hash_by_name (GHashTable *hash_table,
+ const gchar *name,
+ gint priority)
+{
+ GList *list;
+
+ list = g_hash_table_lookup (hash_table, name);
+
+ /* -1 implies return the first one */
+ if (priority == -1) {
+ return list ? list->data : NULL;
+ }
+
+ while (list) {
+ MateThemeCommonInfo *info = (MateThemeCommonInfo *) list->data;
+
+ if (info->priority == priority)
+ return info;
+
+ list = list->next;
+ }
+ return NULL;
+}
+
+static gint
+theme_compare (MateThemeCommonInfo *a,
+ MateThemeCommonInfo *b)
+{
+ gint cmp;
+
+ g_return_val_if_fail (a->type == b->type, a->type - b->type);
+
+ switch (a->type) {
+ case MATE_THEME_TYPE_METATHEME:
+ cmp = mate_theme_meta_info_compare (
+ (MateThemeMetaInfo *) a, (MateThemeMetaInfo *) b);
+ break;
+ case MATE_THEME_TYPE_ICON:
+ cmp = mate_theme_icon_info_compare (
+ (MateThemeIconInfo *) a, (MateThemeIconInfo *) b);
+ break;
+ case MATE_THEME_TYPE_CURSOR:
+ cmp = mate_theme_cursor_info_compare (
+ (MateThemeCursorInfo *) a, (MateThemeCursorInfo *) b);
+ break;
+ default:
+ /* not supported at this time */
+ g_assert_not_reached ();
+ }
+
+ return cmp;
+}
+
+static void
+theme_free (MateThemeCommonInfo *info)
+{
+ switch (info->type) {
+ case MATE_THEME_TYPE_METATHEME:
+ mate_theme_meta_info_free ((MateThemeMetaInfo *) info);
+ break;
+ case MATE_THEME_TYPE_ICON:
+ mate_theme_icon_info_free ((MateThemeIconInfo *) info);
+ break;
+ case MATE_THEME_TYPE_REGULAR:
+ mate_theme_info_free ((MateThemeInfo *) info);
+ break;
+ case MATE_THEME_TYPE_CURSOR:
+ mate_theme_cursor_info_free ((MateThemeCursorInfo *) info);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+GQuark mate_theme_info_error_quark(void)
+{
+ return g_quark_from_static_string("mate-theme-info-error-quark");
+}
+
+MateThemeMetaInfo* mate_theme_read_meta_theme(GFile* meta_theme_uri)
+{
+ MateThemeMetaInfo* meta_theme_info;
+ GFile* common_theme_dir_uri;
+ MateDesktopItem* meta_theme_ditem;
+ gchar* meta_theme_file;
+ const gchar* str;
+ gchar* scheme;
+
+ meta_theme_file = g_file_get_uri(meta_theme_uri);
+ meta_theme_ditem = mate_desktop_item_new_from_uri(meta_theme_file, 0, NULL);
+ g_free(meta_theme_file);
+
+ if (meta_theme_ditem == NULL)
+ return NULL;
+
+ common_theme_dir_uri = g_file_get_parent(meta_theme_uri);
+ meta_theme_info = mate_theme_meta_info_new();
+ meta_theme_info->path = g_file_get_path(meta_theme_uri);
+ meta_theme_info->name = g_file_get_basename(common_theme_dir_uri);
+ g_object_unref(common_theme_dir_uri);
+
+ str = mate_desktop_item_get_localestring(meta_theme_ditem, THEME_NAME);
+
+ if (!str)
+ {
+ str = mate_desktop_item_get_localestring(meta_theme_ditem, MATE_DESKTOP_ITEM_NAME);
+ if (!str)
+ { /* shouldn't reach */
+ mate_theme_meta_info_free(meta_theme_info);
+ return NULL;
+ }
+ }
+
+ meta_theme_info->readable_name = g_strdup(str);
+
+ str = mate_desktop_item_get_localestring(meta_theme_ditem, THEME_COMMENT);
+
+ if (str == NULL)
+ str = mate_desktop_item_get_localestring(meta_theme_ditem, MATE_DESKTOP_ITEM_COMMENT);
+
+ if (str != NULL)
+ meta_theme_info->comment = g_strdup(str);
+
+ str = mate_desktop_item_get_string(meta_theme_ditem, MATE_DESKTOP_ITEM_ICON);
+
+ if (str != NULL)
+ meta_theme_info->icon_file = g_strdup(str);
+
+ str = mate_desktop_item_get_string(meta_theme_ditem, GTK_THEME_KEY);
+
+ if (str == NULL)
+ {
+ mate_theme_meta_info_free(meta_theme_info);
+ return NULL;
+ }
+ meta_theme_info->gtk_theme_name = g_strdup(str);
+
+ str = mate_desktop_item_get_string(meta_theme_ditem, GTK_COLOR_SCHEME_KEY);
+
+ if (str == NULL || str[0] == '\0')
+ scheme = gtkrc_get_color_scheme_for_theme(meta_theme_info->gtk_theme_name);
+ else
+ scheme = g_strdup(str);
+
+ if (scheme != NULL)
+ {
+ meta_theme_info->gtk_color_scheme = scheme;
+
+ for (; *scheme != '\0'; scheme++)
+ if (*scheme == ',')
+ *scheme = '\n';
+ }
+
+ str = mate_desktop_item_get_string (meta_theme_ditem, MARCO_THEME_KEY);
+
+ if (str == NULL)
+ {
+ mate_theme_meta_info_free (meta_theme_info);
+ return NULL;
+ }
+
+ meta_theme_info->marco_theme_name = g_strdup (str);
+
+ str = mate_desktop_item_get_string(meta_theme_ditem, ICON_THEME_KEY);
+
+ if (str == NULL)
+ {
+ mate_theme_meta_info_free(meta_theme_info);
+ return NULL;
+ }
+
+ meta_theme_info->icon_theme_name = g_strdup(str);
+
+ str = mate_desktop_item_get_string(meta_theme_ditem, NOTIFICATION_THEME_KEY);
+
+ if (str != NULL)
+ meta_theme_info->notification_theme_name = g_strdup(str);
+
+ str = mate_desktop_item_get_string(meta_theme_ditem, CURSOR_THEME_KEY);
+
+ if (str != NULL)
+ {
+ meta_theme_info->cursor_theme_name = g_strdup(str);
+
+ str = mate_desktop_item_get_string(meta_theme_ditem, CURSOR_SIZE_KEY);
+
+ if (str)
+ meta_theme_info->cursor_size = (int) g_ascii_strtoll(str, NULL, 10);
+ else
+ meta_theme_info->cursor_size = 18;
+ }
+ else
+ {
+ meta_theme_info->cursor_theme_name = g_strdup("default");
+ meta_theme_info->cursor_size = 18;
+ }
+
+ str = mate_desktop_item_get_string(meta_theme_ditem, APPLICATION_FONT_KEY);
+
+ if (str != NULL)
+ meta_theme_info->application_font = g_strdup(str);
+
+ str = mate_desktop_item_get_string(meta_theme_ditem, DOCUMENTS_FONT_KEY);
+
+ if (str != NULL)
+ meta_theme_info->documents_font = g_strdup(str);
+
+ str = mate_desktop_item_get_string(meta_theme_ditem, DESKTOP_FONT_KEY);
+
+ if (str != NULL)
+ meta_theme_info->desktop_font = g_strdup(str);
+
+ str = mate_desktop_item_get_string(meta_theme_ditem, WINDOWTITLE_FONT_KEY);
+
+ if (str != NULL)
+ meta_theme_info->windowtitle_font = g_strdup(str);
+
+ str = mate_desktop_item_get_string(meta_theme_ditem, MONOSPACE_FONT_KEY);
+
+ if (str != NULL)
+ meta_theme_info->monospace_font = g_strdup(str);
+
+ str = mate_desktop_item_get_string(meta_theme_ditem, BACKGROUND_IMAGE_KEY);
+
+ if (str != NULL)
+ meta_theme_info->background_image = g_strdup(str);
+
+ meta_theme_info->hidden = mate_desktop_item_get_boolean(meta_theme_ditem, HIDDEN_KEY);
+
+ mate_desktop_item_unref(meta_theme_ditem);
+
+ return meta_theme_info;
+}
+
+static MateThemeIconInfo *
+read_icon_theme (GFile *icon_theme_uri)
+{
+ MateThemeIconInfo *icon_theme_info;
+ MateDesktopItem *icon_theme_ditem;
+ gchar *icon_theme_file;
+ gchar *dir_name;
+ const gchar *name;
+ const gchar *directories;
+
+ icon_theme_file = g_file_get_uri (icon_theme_uri);
+ icon_theme_ditem = mate_desktop_item_new_from_uri (icon_theme_file, 0, NULL);
+ g_free (icon_theme_file);
+
+ if (icon_theme_ditem == NULL)
+ return NULL;
+
+ name = mate_desktop_item_get_localestring (icon_theme_ditem, "Icon Theme/Name");
+ if (!name) {
+ name = mate_desktop_item_get_localestring (icon_theme_ditem, MATE_DESKTOP_ITEM_NAME);
+ if (!name) {
+ mate_desktop_item_unref (icon_theme_ditem);
+ return NULL;
+ }
+ }
+
+ /* If index.theme has no Directories entry, it is only a cursor theme */
+ directories = mate_desktop_item_get_string (icon_theme_ditem, "Icon Theme/Directories");
+ if (directories == NULL) {
+ mate_desktop_item_unref (icon_theme_ditem);
+ return NULL;
+ }
+
+ icon_theme_info = mate_theme_icon_info_new ();
+ icon_theme_info->readable_name = g_strdup (name);
+ icon_theme_info->path = g_file_get_path (icon_theme_uri);
+ icon_theme_info->hidden = mate_desktop_item_get_boolean (icon_theme_ditem, "Icon Theme/Hidden");
+ dir_name = g_path_get_dirname (icon_theme_info->path);
+ icon_theme_info->name = g_path_get_basename (dir_name);
+ g_free (dir_name);
+
+ mate_desktop_item_unref (icon_theme_ditem);
+
+ return icon_theme_info;
+}
+
+#ifdef HAVE_XCURSOR
+static void
+add_default_cursor_theme ()
+{
+ MateThemeCursorInfo *theme_info;
+
+ theme_info = mate_theme_cursor_info_new ();
+ theme_info->path = g_strdup ("builtin");
+ theme_info->name = g_strdup ("default");
+ theme_info->readable_name = g_strdup (_("Default Pointer"));
+ theme_info->sizes = g_array_sized_new (FALSE, FALSE, sizeof (gint), 0);
+
+ g_hash_table_insert (cursor_theme_hash_by_uri, theme_info->path, theme_info);
+ add_theme_to_hash_by_name (cursor_theme_hash_by_name, theme_info);
+}
+
+static GdkPixbuf *
+gdk_pixbuf_from_xcursor_image (XcursorImage *cursor)
+{
+ GdkPixbuf *pixbuf;
+#define BUF_SIZE sizeof(guint32) * cursor->width * cursor->height
+ guchar *buf = g_malloc0 (BUF_SIZE);
+ guchar *it;
+
+ for (it = buf; it < (buf + BUF_SIZE); it += 4) {
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+ /* on little endianess it's BGRA to RGBA */
+ it[0] = ((guchar *) (cursor->pixels))[it - buf + 2];
+ it[1] = ((guchar *) (cursor->pixels))[it - buf + 1];
+ it[2] = ((guchar *) (cursor->pixels))[it - buf + 0];
+ it[3] = ((guchar *) (cursor->pixels))[it - buf + 3];
+#else
+ /* on big endianess it's ARGB to RGBA */
+ it[0] = ((guchar *) cursor->pixels)[it - buf + 1];
+ it[1] = ((guchar *) cursor->pixels)[it - buf + 2];
+ it[2] = ((guchar *) cursor->pixels)[it - buf + 3];
+ it[3] = ((guchar *) cursor->pixels)[it - buf + 0];
+#endif
+ }
+
+ pixbuf = gdk_pixbuf_new_from_data ((const guchar *) buf,
+ GDK_COLORSPACE_RGB, TRUE, 8,
+ cursor->width, cursor->height,
+ cursor->width * 4,
+ (GdkPixbufDestroyNotify) g_free,
+ NULL);
+
+ if (!pixbuf)
+ g_free (buf);
+
+ return pixbuf;
+}
+
+static MateThemeCursorInfo *
+read_cursor_theme (GFile *cursor_theme_uri)
+{
+ MateThemeCursorInfo *cursor_theme_info = NULL;
+ GFile *parent_uri, *cursors_uri;
+
+ const gint filter_sizes[] = { 12, 16, 24, 32, 36, 40, 48, 64 };
+ const gint num_sizes = G_N_ELEMENTS (filter_sizes);
+
+ parent_uri = g_file_get_parent (cursor_theme_uri);
+ cursors_uri = g_file_get_child (parent_uri, "cursors");
+
+ if (get_file_type (cursors_uri) == G_FILE_TYPE_DIRECTORY) {
+ GArray *sizes;
+ XcursorImage *cursor;
+ GdkPixbuf *thumbnail = NULL;
+ gchar *name;
+ gint i;
+
+ name = g_file_get_basename (parent_uri);
+
+ sizes = g_array_sized_new (FALSE, FALSE, sizeof (gint), num_sizes);
+
+ for (i = 0; i < num_sizes; ++i) {
+ cursor = XcursorLibraryLoadImage ("left_ptr", name, filter_sizes[i]);
+
+ if (cursor) {
+ if (cursor->size == filter_sizes[i]) {
+ g_array_append_val (sizes, filter_sizes[i]);
+
+ if (thumbnail == NULL && i >= 1)
+ thumbnail = gdk_pixbuf_from_xcursor_image (cursor);
+ }
+
+ XcursorImageDestroy (cursor);
+ }
+ }
+
+ if (sizes->len == 0) {
+ g_array_free (sizes, TRUE);
+ g_free (name);
+ } else {
+ MateDesktopItem *cursor_theme_ditem;
+ gchar *cursor_theme_file;
+
+ if (!thumbnail) {
+ cursor = XcursorLibraryLoadImage ("left_ptr", name,
+ g_array_index (sizes, gint, 0));
+ if (cursor) {
+ thumbnail = gdk_pixbuf_from_xcursor_image (cursor);
+ XcursorImageDestroy (cursor);
+ }
+ }
+
+ cursor_theme_info = mate_theme_cursor_info_new ();
+ cursor_theme_info->path = g_file_get_path (parent_uri);
+ cursor_theme_info->name = name;
+ cursor_theme_info->sizes = sizes;
+ cursor_theme_info->thumbnail = thumbnail;
+
+ cursor_theme_file = g_file_get_path (cursor_theme_uri);
+ cursor_theme_ditem = mate_desktop_item_new_from_file (cursor_theme_file, 0, NULL);
+ g_free (cursor_theme_file);
+
+ if (cursor_theme_ditem != NULL) {
+ const gchar *readable_name;
+
+ readable_name = mate_desktop_item_get_string (cursor_theme_ditem,
+ "Icon Theme/Name");
+ if (readable_name)
+ cursor_theme_info->readable_name = g_strdup (readable_name);
+ else
+ cursor_theme_info->readable_name = g_strdup (name);
+
+ cursor_theme_info->hidden = mate_desktop_item_get_boolean (cursor_theme_ditem,
+ "Icon Theme/Hidden");
+
+ mate_desktop_item_unref (cursor_theme_ditem);
+ } else {
+ cursor_theme_info->readable_name = g_strdup (name);
+ }
+ }
+ }
+
+ g_object_unref (cursors_uri);
+ g_object_unref (parent_uri);
+
+ return cursor_theme_info;
+}
+
+#else /* !HAVE_XCURSOR */
+
+static gchar *
+read_current_cursor_font (void)
+{
+ DIR *dir;
+ gchar *dir_name;
+ struct dirent *file_dirent;
+
+ dir_name = g_build_filename (g_get_home_dir (), ".mate2/share/cursor-fonts", NULL);
+ if (! g_file_test (dir_name, G_FILE_TEST_EXISTS)) {
+ g_free (dir_name);
+ return NULL;
+ }
+
+ dir = opendir (dir_name);
+
+ while ((file_dirent = readdir (dir)) != NULL) {
+ struct stat st;
+ gchar *link_name;
+
+ link_name = g_build_filename (dir_name, file_dirent->d_name, NULL);
+ if (lstat (link_name, &st)) {
+ g_free (link_name);
+ continue;
+ }
+
+ if (S_ISLNK (st.st_mode)) {
+ gint length;
+ gchar target[256];
+
+ length = readlink (link_name, target, 255);
+ if (length > 0) {
+ gchar *retval;
+ target[length] = '\0';
+ retval = g_strdup (target);
+ g_free (link_name);
+ closedir (dir);
+ return retval;
+ }
+
+ }
+ g_free (link_name);
+ }
+ g_free (dir_name);
+ closedir (dir);
+ return NULL;
+}
+
+static void
+read_cursor_fonts (void)
+{
+ gchar *cursor_font;
+ gint i;
+
+ const gchar *builtins[][4] = {
+ {
+ "mate/cursor-fonts/cursor-normal.pcf",
+ N_("Default Pointer"),
+ N_("Default Pointer - Current"),
+ "mouse-cursor-normal.png"
+ }, {
+ "mate/cursor-fonts/cursor-white.pcf",
+ N_("White Pointer"),
+ N_("White Pointer - Current"),
+ "mouse-cursor-white.png"
+ }, {
+ "mate/cursor-fonts/cursor-large.pcf",
+ N_("Large Pointer"),
+ N_("Large Pointer - Current"),
+ "mouse-cursor-normal-large.png"
+ }, {
+ "mate/cursor-fonts/cursor-large-white.pcf",
+ N_("Large White Pointer - Current"),
+ N_("Large White Pointer"),
+ "mouse-cursor-white-large.png"
+ }
+ };
+
+ cursor_font = read_current_cursor_font();
+
+ if (!cursor_font)
+ cursor_font = g_strdup (builtins[0][0]);
+
+ for (i = 0; i < G_N_ELEMENTS (builtins); i++) {
+ MateThemeCursorInfo *theme_info;
+ gchar *filename;
+
+ theme_info = mate_theme_cursor_info_new ();
+
+ filename = g_build_filename (MATECC_DATA_DIR, "pixmaps", builtins[i][3], NULL);
+ theme_info->thumbnail = gdk_pixbuf_new_from_file (filename, NULL);
+ g_free (filename);
+
+ theme_info->path = g_build_filename (MATECC_DATA_DIR, builtins[i][0], NULL);
+ theme_info->name = g_strdup (theme_info->path);
+
+ if (!strcmp (theme_info->path, cursor_font))
+ theme_info->readable_name = g_strdup (_(builtins[i][2]));
+ else
+ theme_info->readable_name = g_strdup (_(builtins[i][1]));
+
+ g_hash_table_insert (cursor_theme_hash_by_uri, theme_info->path, theme_info);
+ add_theme_to_hash_by_name (cursor_theme_hash_by_name, theme_info);
+ }
+
+ g_free (cursor_font);
+}
+#endif /* HAVE_XCURSOR */
+
+static void
+handle_change_signal (gpointer data,
+ MateThemeChangeType change_type,
+ MateThemeElement element_type)
+{
+#ifdef DEBUG
+ gchar *type_str = NULL;
+ gchar *change_str = NULL;
+ gchar *element_str = NULL;
+#endif
+ MateThemeCommonInfo *theme = data;
+ GList *list;
+
+ if (initting)
+ return;
+
+ for (list = callbacks; list; list = list->next) {
+ ThemeCallbackData *callback_data = list->data;
+ (* callback_data->func) (theme, change_type, element_type, callback_data->data);
+ }
+
+#ifdef DEBUG
+ if (theme->type == MATE_THEME_TYPE_METATHEME)
+ type_str = "meta";
+ else if (theme->type == MATE_THEME_TYPE_ICON)
+ type_str = "icon";
+ else if (theme->type == MATE_THEME_TYPE_CURSOR)
+ type_str = "cursor";
+ else if (theme->type == MATE_THEME_TYPE_REGULAR) {
+ if (element_type & MATE_THEME_GTK_2)
+ element_str = "gtk-2";
+ else if (element_type & MATE_THEME_GTK_2_KEYBINDING)
+ element_str = "keybinding";
+ else if (element_type & MATE_THEME_MARCO)
+ element_str = "marco";
+ }
+
+ if (change_type == MATE_THEME_CHANGE_CREATED)
+ change_str = "created";
+ else if (change_type == MATE_THEME_CHANGE_CHANGED)
+ change_str = "changed";
+ else if (change_type == MATE_THEME_CHANGE_DELETED)
+ change_str = "deleted";
+
+ if (type == MATE_THEME_TYPE_REGULAR) {
+ g_print ("theme \"%s\" has a theme of type %s (priority %d) has been %s\n",
+ theme->name,
+ element_str,
+ theme->priority,
+ type_str);
+ } else if (type_str != NULL) {
+ g_print ("%s theme \"%s\" (priority %d) has been %s\n",
+ type_str,
+ theme->name,
+ theme->priority,
+ type_str);
+ }
+#endif
+}
+
+/* index_uri should point to the gtkrc file that was modified */
+static void
+update_theme_index (GFile *index_uri,
+ MateThemeElement key_element,
+ gint priority)
+{
+ gboolean theme_exists;
+ MateThemeInfo *theme_info;
+ GFile *parent;
+ GFile *common_theme_dir_uri;
+ gchar *common_theme_dir;
+
+ /* First, we determine the new state of the file. We do no more
+ * sophisticated a test than "files exists and is a file" */
+ theme_exists = (get_file_type (index_uri) == G_FILE_TYPE_REGULAR);
+
+ /* Next, we see what currently exists */
+ parent = g_file_get_parent (index_uri);
+ common_theme_dir_uri = g_file_get_parent (parent);
+ common_theme_dir = g_file_get_path (common_theme_dir_uri);
+
+ theme_info = g_hash_table_lookup (theme_hash_by_uri, common_theme_dir);
+ if (theme_info == NULL) {
+ if (theme_exists) {
+ theme_info = mate_theme_info_new ();
+ theme_info->path = g_strdup (common_theme_dir);
+ theme_info->name = g_file_get_basename (common_theme_dir_uri);
+ theme_info->readable_name = g_strdup (theme_info->name);
+ theme_info->priority = priority;
+ if (key_element & MATE_THEME_GTK_2)
+ theme_info->has_gtk = TRUE;
+ else if (key_element & MATE_THEME_GTK_2_KEYBINDING)
+ theme_info->has_keybinding = TRUE;
+ else if (key_element & MATE_THEME_MARCO)
+ theme_info->has_marco = TRUE;
+
+ g_hash_table_insert (theme_hash_by_uri, g_strdup (common_theme_dir), theme_info);
+ add_theme_to_hash_by_name (theme_hash_by_name, theme_info);
+ handle_change_signal (theme_info, MATE_THEME_CHANGE_CREATED, key_element);
+ }
+ } else {
+ gboolean theme_used_to_exist = FALSE;
+
+ if (key_element & MATE_THEME_GTK_2) {
+ theme_used_to_exist = theme_info->has_gtk;
+ theme_info->has_gtk = theme_exists;
+ } else if (key_element & MATE_THEME_GTK_2_KEYBINDING) {
+ theme_used_to_exist = theme_info->has_keybinding;
+ theme_info->has_keybinding = theme_exists;
+ } else if (key_element & MATE_THEME_MARCO) {
+ theme_used_to_exist = theme_info->has_marco;
+ theme_info->has_marco = theme_exists;
+ }
+
+ if (!theme_info->has_marco && !theme_info->has_keybinding && !theme_info->has_gtk) {
+ g_hash_table_remove (theme_hash_by_uri, common_theme_dir);
+ remove_theme_from_hash_by_name (theme_hash_by_name, theme_info);
+ }
+
+ if (theme_exists && theme_used_to_exist) {
+ handle_change_signal (theme_info, MATE_THEME_CHANGE_CHANGED, key_element);
+ } else if (theme_exists && !theme_used_to_exist) {
+ handle_change_signal (theme_info, MATE_THEME_CHANGE_CREATED, key_element);
+ } else if (!theme_exists && theme_used_to_exist) {
+ handle_change_signal (theme_info, MATE_THEME_CHANGE_DELETED, key_element);
+ }
+
+ if (!theme_info->has_marco && !theme_info->has_keybinding && !theme_info->has_gtk) {
+ mate_theme_info_free (theme_info);
+ }
+ }
+
+ g_free (common_theme_dir);
+ g_object_unref (parent);
+ g_object_unref (common_theme_dir_uri);
+}
+
+static void
+update_gtk2_index (GFile *gtk2_index_uri,
+ gint priority)
+{
+ update_theme_index (gtk2_index_uri, MATE_THEME_GTK_2, priority);
+}
+
+static void
+update_keybinding_index (GFile *keybinding_index_uri,
+ gint priority)
+{
+ update_theme_index (keybinding_index_uri, MATE_THEME_GTK_2_KEYBINDING, priority);
+}
+
+static void
+update_marco_index (GFile *marco_index_uri,
+ gint priority)
+{
+ update_theme_index (marco_index_uri, MATE_THEME_MARCO, priority);
+}
+
+static void
+update_common_theme_dir_index (GFile *theme_index_uri,
+ MateThemeType type,
+ gint priority)
+{
+ gboolean theme_exists;
+ MateThemeCommonInfo *theme_info = NULL;
+ MateThemeCommonInfo *old_theme_info;
+ GFile *common_theme_dir_uri;
+ gchar *common_theme_dir;
+ GHashTable *hash_by_uri;
+ GHashTable *hash_by_name;
+
+ if (type == MATE_THEME_TYPE_ICON) {
+ hash_by_uri = icon_theme_hash_by_uri;
+ hash_by_name = icon_theme_hash_by_name;
+ } else if (type == MATE_THEME_TYPE_CURSOR) {
+ hash_by_uri = cursor_theme_hash_by_uri;
+ hash_by_name = cursor_theme_hash_by_name;
+ } else {
+ hash_by_uri = meta_theme_hash_by_uri;
+ hash_by_name = meta_theme_hash_by_name;
+ }
+
+ if (type != MATE_THEME_TYPE_CURSOR) {
+ /* First, we determine the new state of the file. */
+ if (get_file_type (theme_index_uri) == G_FILE_TYPE_REGULAR) {
+ /* It's an interesting file. Let's try to load it. */
+ if (type == MATE_THEME_TYPE_ICON)
+ theme_info = (MateThemeCommonInfo *) read_icon_theme (theme_index_uri);
+ else
+ theme_info = (MateThemeCommonInfo *) mate_theme_read_meta_theme (theme_index_uri);
+ } else {
+ theme_info = NULL;
+ }
+
+ }
+#ifdef HAVE_XCURSOR
+ /* cursor themes don't necessarily have an index file, so try those in any case */
+ else {
+ theme_info = (MateThemeCommonInfo *) read_cursor_theme (theme_index_uri);
+ }
+#endif
+
+ if (theme_info) {
+ theme_info->priority = priority;
+ theme_exists = TRUE;
+ } else {
+ theme_exists = FALSE;
+ }
+
+ /* Next, we see what currently exists */
+ common_theme_dir_uri = g_file_get_parent (theme_index_uri);
+ common_theme_dir = g_file_get_path (common_theme_dir_uri);
+ g_object_unref (common_theme_dir_uri);
+
+ old_theme_info = (MateThemeCommonInfo *) g_hash_table_lookup (hash_by_uri, common_theme_dir);
+
+ if (old_theme_info == NULL) {
+ if (theme_exists) {
+ g_hash_table_insert (hash_by_uri, g_strdup (common_theme_dir), theme_info);
+ add_theme_to_hash_by_name (hash_by_name, theme_info);
+ handle_change_signal (theme_info, MATE_THEME_CHANGE_CREATED, 0);
+ }
+ } else {
+ if (theme_exists) {
+ if (theme_compare (theme_info, old_theme_info) != 0) {
+ /* Remove old theme */
+ g_hash_table_remove (hash_by_uri, common_theme_dir);
+ remove_theme_from_hash_by_name (hash_by_name, old_theme_info);
+ g_hash_table_insert (hash_by_uri, g_strdup (common_theme_dir), theme_info);
+ add_theme_to_hash_by_name (hash_by_name, theme_info);
+ handle_change_signal (theme_info, MATE_THEME_CHANGE_CHANGED, 0);
+ theme_free (old_theme_info);
+ } else {
+ theme_free (theme_info);
+ }
+ } else {
+ g_hash_table_remove (hash_by_uri, common_theme_dir);
+ remove_theme_from_hash_by_name (hash_by_name, old_theme_info);
+
+ handle_change_signal (old_theme_info, MATE_THEME_CHANGE_DELETED, 0);
+ theme_free (old_theme_info);
+ }
+ }
+
+ g_free (common_theme_dir);
+}
+
+static void
+update_meta_theme_index (GFile *meta_theme_index_uri,
+ gint priority)
+{
+ update_common_theme_dir_index (meta_theme_index_uri, MATE_THEME_TYPE_METATHEME, priority);
+}
+
+static void
+update_icon_theme_index (GFile *icon_theme_index_uri,
+ gint priority)
+{
+ update_common_theme_dir_index (icon_theme_index_uri, MATE_THEME_TYPE_ICON, priority);
+}
+
+static void
+update_cursor_theme_index (GFile *cursor_theme_index_uri,
+ gint priority)
+{
+#ifdef HAVE_XCURSOR
+ update_common_theme_dir_index (cursor_theme_index_uri, MATE_THEME_TYPE_CURSOR, priority);
+#endif
+}
+
+static void
+gtk2_dir_changed (GFileMonitor *monitor,
+ GFile *file,
+ GFile *other_file,
+ GFileMonitorEvent event_type,
+ CommonThemeDirMonitorData *monitor_data)
+{
+ gchar *affected_file;
+
+ affected_file = g_file_get_basename (file);
+
+ /* The only file we care about is gtkrc */
+ if (!strcmp (affected_file, "gtkrc")) {
+ update_gtk2_index (file, monitor_data->priority);
+ }
+
+ g_free (affected_file);
+}
+
+static void
+keybinding_dir_changed (GFileMonitor *monitor,
+ GFile *file,
+ GFile *other_file,
+ GFileMonitorEvent event_type,
+ CommonThemeDirMonitorData *monitor_data)
+{
+ gchar *affected_file;
+
+ affected_file = g_file_get_basename (file);
+
+ /* The only file we care about is gtkrc */
+ if (!strcmp (affected_file, "gtkrc")) {
+ update_keybinding_index (file, monitor_data->priority);
+ }
+
+ g_free (affected_file);
+}
+
+static void
+marco_dir_changed (GFileMonitor *monitor,
+ GFile *file,
+ GFile *other_file,
+ GFileMonitorEvent event_type,
+ CommonThemeDirMonitorData *monitor_data)
+{
+ gchar *affected_file;
+
+ affected_file = g_file_get_basename (file);
+
+ /* The only file we care about is marco-theme-1.xml */
+ if (!strcmp (affected_file, "metacity-theme-1.xml")) {
+ update_marco_index (file, monitor_data->priority);
+ }
+
+ g_free (affected_file);
+}
+
+static void
+common_theme_dir_changed (GFileMonitor *monitor,
+ GFile *file,
+ GFile *other_file,
+ GFileMonitorEvent event_type,
+ CommonThemeDirMonitorData *monitor_data)
+{
+ gchar *affected_file;
+
+ affected_file = g_file_get_basename (file);
+
+ /* The only file we care about is index.theme */
+ if (!strcmp (affected_file, "index.theme")) {
+ update_meta_theme_index (file, monitor_data->priority);
+ }
+
+ g_free (affected_file);
+}
+
+static void
+common_icon_theme_dir_changed (GFileMonitor *monitor,
+ GFile *file,
+ GFile *other_file,
+ GFileMonitorEvent event_type,
+ CommonIconThemeDirMonitorData *monitor_data)
+{
+ gchar *affected_file;
+
+ affected_file = g_file_get_basename (file);
+
+ /* The only file we care about is index.theme */
+ if (!strcmp (affected_file, "index.theme")) {
+ update_icon_theme_index (file, monitor_data->priority);
+ update_cursor_theme_index (file, monitor_data->priority);
+ }
+ /* and the cursors subdir for cursor themes */
+ else if (!strcmp (affected_file, "cursors")) {
+ /* always call update_cursor_theme_index with the index.theme URI */
+ GFile *parent, *index;
+
+ parent = g_file_get_parent (file);
+ index = g_file_get_child (parent, "index.theme");
+ g_object_unref (parent);
+
+ update_cursor_theme_index (index, monitor_data->priority);
+
+ g_object_unref (index);
+ }
+
+ g_free (affected_file);
+}
+
+/* Add a monitor to a common_theme_dir. */
+static gboolean
+add_common_theme_dir_monitor (GFile *theme_dir_uri,
+ CommonThemeDirMonitorData *monitor_data,
+ GError **error)
+{
+ GFile *uri, *subdir;
+ GFileMonitor *monitor;
+
+ uri = g_file_get_child (theme_dir_uri, "index.theme");
+ update_meta_theme_index (uri, monitor_data->priority);
+ g_object_unref (uri);
+
+ /* Add the handle for this directory */
+ monitor = g_file_monitor_file (theme_dir_uri, G_FILE_MONITOR_NONE, NULL, NULL);
+ if (monitor == NULL)
+ return FALSE;
+
+ g_signal_connect (monitor, "changed",
+ (GCallback) common_theme_dir_changed, monitor_data);
+
+ monitor_data->common_theme_dir_handle = monitor;
+
+
+ /* gtk-2 theme subdir */
+ subdir = g_file_get_child (theme_dir_uri, "gtk-2.0");
+ uri = g_file_get_child (subdir, "gtkrc");
+ if (g_file_query_exists (uri, NULL)) {
+ update_gtk2_index (uri, monitor_data->priority);
+ }
+ g_object_unref (uri);
+
+ monitor = g_file_monitor_directory (subdir, G_FILE_MONITOR_NONE, NULL, NULL);
+ if (monitor != NULL) {
+ g_signal_connect (monitor, "changed",
+ (GCallback) gtk2_dir_changed, monitor_data);
+ }
+ monitor_data->gtk2_dir_handle = monitor;
+ g_object_unref (subdir);
+
+ /* keybinding theme subdir */
+ subdir = g_file_get_child (theme_dir_uri, "gtk-2.0-key");
+ uri = g_file_get_child (subdir, "gtkrc");
+ if (g_file_query_exists (uri, NULL)) {
+ update_keybinding_index (uri, monitor_data->priority);
+ }
+ g_object_unref (uri);
+
+ monitor = g_file_monitor_directory (subdir, G_FILE_MONITOR_NONE, NULL, NULL);
+ if (monitor != NULL) {
+ g_signal_connect (monitor, "changed",
+ (GCallback) keybinding_dir_changed, monitor_data);
+ }
+ monitor_data->keybinding_dir_handle = monitor;
+ g_object_unref (subdir);
+
+ /* marco theme subdir */
+ subdir = g_file_get_child (theme_dir_uri, "metacity-1");
+ uri = g_file_get_child (subdir, "metacity-theme-1.xml");
+ if (g_file_query_exists (uri, NULL)) {
+ update_marco_index (uri, monitor_data->priority);
+ }
+ g_object_unref (uri);
+
+ monitor = g_file_monitor_directory (subdir, G_FILE_MONITOR_NONE, NULL, NULL);
+ if (monitor != NULL) {
+ g_signal_connect (monitor, "changed",
+ (GCallback) marco_dir_changed, monitor_data);
+ }
+ monitor_data->marco_dir_handle = monitor;
+ g_object_unref (subdir);
+
+ return TRUE;
+}
+
+static gboolean
+add_common_icon_theme_dir_monitor (GFile *theme_dir_uri,
+ CommonIconThemeDirMonitorData *monitor_data,
+ GError **error)
+{
+ GFile *index_uri;
+ GFileMonitor *monitor;
+
+ /* Add the handle for this directory */
+ index_uri = g_file_get_child (theme_dir_uri, "index.theme");
+ update_icon_theme_index (index_uri, monitor_data->priority);
+ update_cursor_theme_index (index_uri, monitor_data->priority);
+ g_object_unref (index_uri);
+
+ monitor = g_file_monitor_file (theme_dir_uri, G_FILE_MONITOR_NONE, NULL, NULL);
+ if (monitor == NULL)
+ return FALSE;
+
+ g_signal_connect (monitor, "changed",
+ (GCallback) common_icon_theme_dir_changed, monitor_data);
+
+ monitor_data->common_icon_theme_dir_handle = monitor;
+ return TRUE;
+}
+
+static void
+remove_common_theme_dir_monitor (CommonThemeDirMonitorData *monitor_data)
+{
+ g_file_monitor_cancel (monitor_data->common_theme_dir_handle);
+ g_file_monitor_cancel (monitor_data->gtk2_dir_handle);
+ g_file_monitor_cancel (monitor_data->keybinding_dir_handle);
+ g_file_monitor_cancel (monitor_data->marco_dir_handle);
+}
+
+static void
+remove_common_icon_theme_dir_monitor (CommonIconThemeDirMonitorData *monitor_data)
+{
+ g_file_monitor_cancel (monitor_data->common_icon_theme_dir_handle);
+}
+
+static void
+top_theme_dir_changed (GFileMonitor *monitor,
+ GFile *file,
+ GFile *other_file,
+ GFileMonitorEvent event_type,
+ CallbackTuple *tuple)
+{
+ GHashTable *handle_hash;
+ CommonThemeDirMonitorData *monitor_data;
+ gint priority;
+
+ handle_hash = tuple->handle_hash;
+ priority = tuple->priority;
+
+ if (event_type == G_FILE_MONITOR_EVENT_CREATED) {
+ if (get_file_type (file) == G_FILE_TYPE_DIRECTORY) {
+ monitor_data = g_new0 (CommonThemeDirMonitorData, 1);
+ monitor_data->priority = priority;
+ add_common_theme_dir_monitor (file, monitor_data, NULL);
+ g_hash_table_insert (handle_hash, g_file_get_basename (file), monitor_data);
+ }
+
+ } else if (event_type == G_FILE_MONITOR_EVENT_DELETED) {
+ gchar *name;
+
+ name = g_file_get_basename (file);
+ monitor_data = g_hash_table_lookup (handle_hash, name);
+ if (monitor_data != NULL) {
+ remove_common_theme_dir_monitor (monitor_data);
+ g_hash_table_remove (handle_hash, name);
+ }
+ g_free (name);
+ }
+}
+
+static void
+top_icon_theme_dir_changed (GFileMonitor *monitor,
+ GFile *file,
+ GFile *other_file,
+ GFileMonitorEvent event_type,
+ CallbackTuple *tuple)
+{
+ GHashTable *handle_hash;
+ CommonIconThemeDirMonitorData *monitor_data;
+ gint priority;
+
+ handle_hash = tuple->handle_hash;
+ priority = tuple->priority;
+
+ if (event_type == G_FILE_MONITOR_EVENT_CREATED) {
+ if (get_file_type (file) == G_FILE_TYPE_DIRECTORY) {
+ monitor_data = g_new0 (CommonIconThemeDirMonitorData, 1);
+ monitor_data->priority = priority;
+ add_common_icon_theme_dir_monitor (file, monitor_data, NULL);
+ g_hash_table_insert (handle_hash, g_file_get_basename (file), monitor_data);
+ }
+
+ } else if (event_type == G_FILE_MONITOR_EVENT_DELETED) {
+ gchar *name;
+
+ name = g_file_get_basename (file);
+ monitor_data = g_hash_table_lookup (handle_hash, name);
+ if (monitor_data != NULL) {
+ remove_common_icon_theme_dir_monitor (monitor_data);
+ g_hash_table_remove (handle_hash, name);
+ }
+ g_free (name);
+ }
+}
+
+/* Add a monitor to a top dir. These monitors persist for the duration of the
+ * lib.
+ */
+static gboolean
+real_add_top_theme_dir_monitor (GFile *uri,
+ gint priority,
+ gboolean icon_theme,
+ GError **error)
+{
+ GFileInfo *file_info;
+ GFileMonitor *monitor;
+ GFileEnumerator *enumerator;
+ CallbackTuple *tuple;
+
+ /* Check the URI */
+ if (get_file_type (uri) != G_FILE_TYPE_DIRECTORY)
+ return FALSE;
+
+ /* handle_hash is a hash of common_theme_dir names to their monitor_data. We
+ * use it to remove the monitor handles when a dir is removed.
+ */
+ tuple = g_new (CallbackTuple, 1);
+ tuple->handle_hash = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, (GDestroyNotify) g_free);
+ tuple->priority = priority;
+
+ /* Monitor the top directory */
+ monitor = g_file_monitor_directory (uri, G_FILE_MONITOR_NONE, NULL, NULL);
+ if (monitor != NULL) {
+ g_signal_connect (monitor, "changed",
+ (GCallback) (icon_theme ? top_icon_theme_dir_changed : top_theme_dir_changed),
+ tuple);
+ }
+
+ /* Go through the directory to add monitoring */
+ enumerator = g_file_enumerate_children (uri,
+ G_FILE_ATTRIBUTE_STANDARD_TYPE ","
+ G_FILE_ATTRIBUTE_STANDARD_NAME,
+ G_FILE_QUERY_INFO_NONE,
+ NULL, NULL);
+ if (enumerator == NULL)
+ return FALSE;
+
+ while ((file_info = g_file_enumerator_next_file (enumerator, NULL, NULL))) {
+ GFileType type = g_file_info_get_file_type (file_info);
+
+ if (type == G_FILE_TYPE_DIRECTORY || type == G_FILE_TYPE_SYMBOLIC_LINK) {
+ GFile *child;
+ const gchar *name;
+ gpointer data;
+
+ /* Add the directory */
+ name = g_file_info_get_name (file_info);
+ child = g_file_get_child (uri, name);
+
+ if (icon_theme) {
+ CommonIconThemeDirMonitorData *monitor_data;
+ monitor_data = g_new0 (CommonIconThemeDirMonitorData, 1);
+ monitor_data->priority = priority;
+ add_common_icon_theme_dir_monitor (child, monitor_data, error);
+ data = monitor_data;
+ } else {
+ CommonThemeDirMonitorData *monitor_data;
+ monitor_data = g_new0 (CommonThemeDirMonitorData, 1);
+ monitor_data->priority = priority;
+ add_common_theme_dir_monitor (child, monitor_data, error);
+ data = monitor_data;
+ }
+ g_object_unref (child);
+
+ g_hash_table_insert (tuple->handle_hash, g_strdup (name), data);
+ }
+ g_object_unref (file_info);
+ }
+ g_file_enumerator_close (enumerator, NULL, NULL);
+
+ return TRUE;
+}
+
+static gboolean
+add_top_theme_dir_monitor (GFile *uri,
+ gint priority,
+ GError **error)
+{
+ return real_add_top_theme_dir_monitor (uri, priority, FALSE, error);
+}
+
+static gboolean
+add_top_icon_theme_dir_monitor (GFile *uri,
+ gint priority,
+ GError **error)
+{
+ return real_add_top_theme_dir_monitor (uri, priority, TRUE, error);
+}
+
+/* Public functions */
+
+/* GTK/Marco/keybinding Themes */
+MateThemeInfo *
+mate_theme_info_new (void)
+{
+ MateThemeInfo *theme_info;
+
+ theme_info = g_new0 (MateThemeInfo, 1);
+ theme_info->type = MATE_THEME_TYPE_REGULAR;
+
+ return theme_info;
+}
+
+void
+mate_theme_info_free (MateThemeInfo *theme_info)
+{
+ g_free (theme_info->path);
+ g_free (theme_info->name);
+ g_free (theme_info->readable_name);
+ g_free (theme_info);
+}
+
+MateThemeInfo *
+mate_theme_info_find (const gchar *theme_name)
+{
+ return (MateThemeInfo *)
+ get_theme_from_hash_by_name (theme_hash_by_name, theme_name, -1);
+}
+
+struct MateThemeInfoHashData
+{
+ gconstpointer user_data;
+ GList *list;
+};
+
+static void
+mate_theme_info_find_by_type_helper (gpointer key,
+ GList *list,
+ struct MateThemeInfoHashData *hash_data)
+{
+ guint elements = GPOINTER_TO_INT (hash_data->user_data);
+
+ do {
+ MateThemeInfo *theme_info = list->data;
+
+ if ((elements & MATE_THEME_MARCO && theme_info->has_marco) ||
+ (elements & MATE_THEME_GTK_2 && theme_info->has_gtk) ||
+ (elements & MATE_THEME_GTK_2_KEYBINDING && theme_info->has_keybinding)) {
+ hash_data->list = g_list_prepend (hash_data->list, theme_info);
+ return;
+ }
+
+ list = list->next;
+ } while (list);
+}
+
+GList *
+mate_theme_info_find_by_type (guint elements)
+{
+ struct MateThemeInfoHashData data;
+ data.user_data = GINT_TO_POINTER (elements);
+ data.list = NULL;
+
+ g_hash_table_foreach (theme_hash_by_name,
+ (GHFunc) mate_theme_info_find_by_type_helper,
+ &data);
+
+ return data.list;
+}
+
+static void mate_theme_info_find_all_helper(const gchar* key, GList* list, GList** themes)
+{
+ /* only return visible themes */
+ if (!((MateThemeCommonInfo*) list->data)->hidden)
+ {
+ *themes = g_list_prepend(*themes, list->data);
+ }
+}
+
+gchar* gtk_theme_info_missing_engine(const gchar* gtk_theme, gboolean nameOnly)
+{
+ gchar* engine = NULL;
+ gchar* gtkrc;
+
+ gtkrc = gtkrc_find_named(gtk_theme);
+
+ if (gtkrc)
+ {
+ GSList* engines = NULL;
+ GSList* l;
+
+ gtkrc_get_details(gtkrc, &engines, NULL);
+
+ g_free(gtkrc);
+
+ for (l = engines; l; l = l->next)
+ {
+ #if 1 // set to 0 if you can not compile with the follow code
+ GtkThemeEngine* a = gtk_theme_engine_get((const gchar*) l->data);
+
+ if (!a)
+ {
+ if (nameOnly)
+ {
+ engine = g_strdup(l->data);
+ }
+ else
+ {
+ // esto necesita más trabajo, pero creo que debian no se
+ // salva ni con el anterior fix.
+ // GTK_ENGINE_DIR aún sigue conteniendo un path erroneo.
+ engine = g_module_build_path(GTK_ENGINE_DIR, l->data);
+ }
+
+ break;
+ }
+
+ #else
+
+ /* This code do not work on distros with more of one gtk theme
+ * engine path. Like debian. But yes on others like Archlinux.
+ * Example, debian use:
+ * /usr/lib/i386-linux-gnu/2.10.0/engines/
+ * and /usr/lib/2.10.0/engines/
+ *
+ * some links
+ * http://forums.linuxmint.com/viewtopic.php?f=190&t=85015
+ */
+ gchar* full = g_module_build_path(GTK_ENGINE_DIR, l->data);
+
+ gboolean found = g_file_test(full, G_FILE_TEST_EXISTS);
+
+ if (!found)
+ {
+ if (nameOnly)
+ {
+ engine = g_strdup(l->data);
+ g_free(full);
+ }
+ else
+ {
+ engine = full;
+ }
+
+ break;
+ }
+
+ g_free(full);
+ #endif
+ }
+
+ g_slist_foreach(engines, (GFunc) g_free, NULL);
+ g_slist_free(engines);
+ }
+
+ return engine;
+}
+
+/* Icon themes */
+MateThemeIconInfo *
+mate_theme_icon_info_new (void)
+{
+ MateThemeIconInfo *icon_theme_info;
+
+ icon_theme_info = g_new0 (MateThemeIconInfo, 1);
+ icon_theme_info->type = MATE_THEME_TYPE_ICON;
+
+ return icon_theme_info;
+}
+
+void
+mate_theme_icon_info_free (MateThemeIconInfo *icon_theme_info)
+{
+ g_free (icon_theme_info->name);
+ g_free (icon_theme_info->readable_name);
+ g_free (icon_theme_info->path);
+ g_free (icon_theme_info);
+}
+
+MateThemeIconInfo *
+mate_theme_icon_info_find (const gchar *icon_theme_name)
+{
+ g_return_val_if_fail (icon_theme_name != NULL, NULL);
+
+ return (MateThemeIconInfo *)
+ get_theme_from_hash_by_name (icon_theme_hash_by_name, icon_theme_name, -1);
+}
+
+GList *
+mate_theme_icon_info_find_all (void)
+{
+ GList *list = NULL;
+
+ g_hash_table_foreach (icon_theme_hash_by_name,
+ (GHFunc) mate_theme_info_find_all_helper,
+ &list);
+
+ return list;
+}
+
+gint
+mate_theme_icon_info_compare (MateThemeIconInfo *a,
+ MateThemeIconInfo *b)
+{
+ gint cmp;
+
+ cmp = safe_strcmp (a->path, b->path);
+ if (cmp != 0) return cmp;
+
+ return safe_strcmp (a->name, b->name);
+}
+
+/* Cursor themes */
+MateThemeCursorInfo *
+mate_theme_cursor_info_new (void)
+{
+ MateThemeCursorInfo *theme_info;
+
+ theme_info = g_new0 (MateThemeCursorInfo, 1);
+ theme_info->type = MATE_THEME_TYPE_CURSOR;
+
+ return theme_info;
+}
+
+void
+mate_theme_cursor_info_free (MateThemeCursorInfo *cursor_theme_info)
+{
+ g_free (cursor_theme_info->name);
+ g_free (cursor_theme_info->readable_name);
+ g_free (cursor_theme_info->path);
+ g_array_free (cursor_theme_info->sizes, TRUE);
+ if (cursor_theme_info->thumbnail != NULL)
+ g_object_unref (cursor_theme_info->thumbnail);
+ g_free (cursor_theme_info);
+}
+
+MateThemeCursorInfo *
+mate_theme_cursor_info_find (const gchar *cursor_theme_name)
+{
+ g_return_val_if_fail (cursor_theme_name != NULL, NULL);
+
+ return (MateThemeCursorInfo *)
+ get_theme_from_hash_by_name (cursor_theme_hash_by_name, cursor_theme_name, -1);
+}
+
+GList *
+mate_theme_cursor_info_find_all (void)
+{
+ GList *list = NULL;
+
+ g_hash_table_foreach (cursor_theme_hash_by_name,
+ (GHFunc) mate_theme_info_find_all_helper,
+ &list);
+
+ return list;
+}
+
+gint
+mate_theme_cursor_info_compare (MateThemeCursorInfo *a,
+ MateThemeCursorInfo *b)
+{
+ gint cmp;
+
+ cmp = safe_strcmp (a->path, b->path);
+ if (cmp != 0) return cmp;
+
+ return safe_strcmp (a->name, b->name);
+}
+
+/* Meta themes */
+MateThemeMetaInfo* mate_theme_meta_info_new(void)
+{
+ MateThemeMetaInfo* theme_info;
+
+ theme_info = g_new0(MateThemeMetaInfo, 1);
+ theme_info->type = MATE_THEME_TYPE_METATHEME;
+
+ return theme_info;
+}
+
+void mate_theme_meta_info_free(MateThemeMetaInfo* meta_theme_info)
+{
+ g_free(meta_theme_info->path);
+ g_free(meta_theme_info->readable_name);
+ g_free(meta_theme_info->name);
+ g_free(meta_theme_info->comment);
+ g_free(meta_theme_info->application_font);
+ g_free(meta_theme_info->documents_font);
+ g_free(meta_theme_info->desktop_font);
+ g_free(meta_theme_info->windowtitle_font);
+ g_free(meta_theme_info->monospace_font);
+ g_free(meta_theme_info->background_image);
+ g_free(meta_theme_info->gtk_theme_name);
+ g_free(meta_theme_info->gtk_color_scheme);
+ g_free(meta_theme_info->icon_theme_name);
+ g_free(meta_theme_info->marco_theme_name);
+ g_free(meta_theme_info->notification_theme_name);
+ g_free(meta_theme_info);
+}
+
+gboolean mate_theme_meta_info_validate(const MateThemeMetaInfo* info, GError** error)
+{
+ MateThemeInfo* theme;
+ gchar* engine;
+
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ theme = mate_theme_info_find (info->gtk_theme_name);
+
+ if (!theme || !theme->has_gtk)
+ {
+ g_set_error (error, MATE_THEME_ERROR, MATE_THEME_ERROR_GTK_THEME_NOT_AVAILABLE,
+ _("This theme will not look as intended because the required GTK+ theme '%s' is not installed."),
+ info->gtk_theme_name);
+ return FALSE;
+ }
+
+ theme = mate_theme_info_find (info->marco_theme_name);
+
+ if (!theme || !theme->has_marco)
+ {
+ g_set_error (error, MATE_THEME_ERROR, MATE_THEME_ERROR_WM_THEME_NOT_AVAILABLE,
+ _("This theme will not look as intended because the required window manager theme '%s' is not installed."),
+ info->marco_theme_name);
+ return FALSE;
+ }
+
+ if (!mate_theme_icon_info_find (info->icon_theme_name))
+ {
+ g_set_error (error, MATE_THEME_ERROR, MATE_THEME_ERROR_ICON_THEME_NOT_AVAILABLE,
+ _("This theme will not look as intended because the required icon theme '%s' is not installed."),
+ info->icon_theme_name);
+ return FALSE;
+ }
+
+ /* check for gtk theme engines */
+ engine = gtk_theme_info_missing_engine(info->gtk_theme_name, TRUE);
+
+ if (engine != NULL)
+ {
+ g_set_error (error, MATE_THEME_ERROR, MATE_THEME_ERROR_GTK_ENGINE_NOT_AVAILABLE,
+ _("This theme will not look as intended because the required GTK+ theme engine '%s' is not installed."),
+ engine);
+ g_free (engine);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+MateThemeMetaInfo* mate_theme_meta_info_find(const char* meta_theme_name)
+{
+ g_return_val_if_fail(meta_theme_name != NULL, NULL);
+
+ return (MateThemeMetaInfo*) get_theme_from_hash_by_name (meta_theme_hash_by_name, meta_theme_name, -1);
+}
+
+GList* mate_theme_meta_info_find_all(void)
+{
+ GList* list = NULL;
+
+ g_hash_table_foreach (meta_theme_hash_by_name, (GHFunc) mate_theme_info_find_all_helper, &list);
+
+ return list;
+}
+
+gint
+mate_theme_meta_info_compare (MateThemeMetaInfo *a,
+ MateThemeMetaInfo *b)
+{
+ gint cmp;
+
+ cmp = safe_strcmp (a->path, b->path);
+ if (cmp != 0) return cmp;
+
+ cmp = safe_strcmp (a->readable_name, b->readable_name);
+ if (cmp != 0) return cmp;
+
+ cmp = safe_strcmp (a->name, b->name);
+ if (cmp != 0) return cmp;
+
+ cmp = safe_strcmp (a->comment, b->comment);
+ if (cmp != 0) return cmp;
+
+ cmp = safe_strcmp (a->icon_file, b->icon_file);
+ if (cmp != 0) return cmp;
+
+ cmp = safe_strcmp (a->gtk_theme_name, b->gtk_theme_name);
+ if (cmp != 0) return cmp;
+
+ cmp = safe_strcmp (a->gtk_color_scheme, b->gtk_color_scheme);
+ if (cmp != 0) return cmp;
+
+ cmp = safe_strcmp (a->marco_theme_name, b->marco_theme_name);
+ if (cmp != 0) return cmp;
+
+ cmp = safe_strcmp (a->icon_theme_name, b->icon_theme_name);
+ if (cmp != 0) return cmp;
+
+ cmp = safe_strcmp (a->notification_theme_name, b->notification_theme_name);
+ if (cmp != 0) return cmp;
+
+ cmp = safe_strcmp (a->sound_theme_name, b->sound_theme_name);
+ if (cmp != 0) return cmp;
+
+ cmp = safe_strcmp (a->application_font, b->application_font);
+ if (cmp != 0) return cmp;
+
+ cmp = safe_strcmp (a->documents_font, b->documents_font);
+ if (cmp != 0) return cmp;
+
+ cmp = safe_strcmp (a->desktop_font, b->desktop_font);
+ if (cmp != 0) return cmp;
+
+ cmp = safe_strcmp (a->windowtitle_font, b->windowtitle_font);
+ if (cmp != 0) return cmp;
+
+ cmp = safe_strcmp (a->monospace_font, b->monospace_font);
+ if (cmp != 0) return cmp;
+
+ return safe_strcmp (a->background_image, b->background_image);
+}
+
+void
+mate_theme_info_register_theme_change (ThemeChangedCallback func,
+ gpointer data)
+{
+ ThemeCallbackData *callback_data;
+
+ g_return_if_fail (func != NULL);
+
+ callback_data = g_new (ThemeCallbackData, 1);
+ callback_data->func = func;
+ callback_data->data = data;
+
+ callbacks = g_list_prepend (callbacks, callback_data);
+}
+
+gboolean
+mate_theme_color_scheme_parse (const gchar *scheme, GdkColor *colors)
+{
+ gchar **color_scheme_strings, **color_scheme_pair, *current_string;
+ gint i;
+
+ if (!scheme || !strcmp (scheme, ""))
+ return FALSE;
+
+ /* initialise the array */
+ for (i = 0; i < NUM_SYMBOLIC_COLORS; i++)
+ colors[i].red = colors[i].green = colors[i].blue = 0;
+
+ /* The color scheme string consists of name:color pairs, separated by
+ * newlines, so first we split the string up by new line */
+
+ color_scheme_strings = g_strsplit (scheme, "\n", 0);
+
+ /* loop through the name:color pairs, and save the color if we recognise the name */
+ i = 0;
+ while ((current_string = color_scheme_strings[i++])) {
+ color_scheme_pair = g_strsplit (current_string, ":", 0);
+
+ if (color_scheme_pair[0] != NULL && color_scheme_pair[1] != NULL) {
+ g_strstrip (color_scheme_pair[0]);
+ g_strstrip (color_scheme_pair[1]);
+
+ if (!strcmp ("fg_color", color_scheme_pair[0]))
+ gdk_color_parse (color_scheme_pair[1], &colors[COLOR_FG]);
+ else if (!strcmp ("bg_color", color_scheme_pair[0]))
+ gdk_color_parse (color_scheme_pair[1], &colors[COLOR_BG]);
+ else if (!strcmp ("text_color", color_scheme_pair[0]))
+ gdk_color_parse (color_scheme_pair[1], &colors[COLOR_TEXT]);
+ else if (!strcmp ("base_color", color_scheme_pair[0]))
+ gdk_color_parse (color_scheme_pair[1], &colors[COLOR_BASE]);
+ else if (!strcmp ("selected_fg_color", color_scheme_pair[0]))
+ gdk_color_parse (color_scheme_pair[1], &colors[COLOR_SELECTED_FG]);
+ else if (!strcmp ("selected_bg_color", color_scheme_pair[0]))
+ gdk_color_parse (color_scheme_pair[1], &colors[COLOR_SELECTED_BG]);
+ else if (!strcmp ("tooltip_fg_color", color_scheme_pair[0]))
+ gdk_color_parse (color_scheme_pair[1], &colors[COLOR_TOOLTIP_FG]);
+ else if (!strcmp ("tooltip_bg_color", color_scheme_pair[0]))
+ gdk_color_parse (color_scheme_pair[1], &colors[COLOR_TOOLTIP_BG]);
+ }
+
+ g_strfreev (color_scheme_pair);
+ }
+
+ g_strfreev (color_scheme_strings);
+
+ return TRUE;
+}
+
+gboolean
+mate_theme_color_scheme_equal (const gchar *s1, const gchar *s2)
+{
+ GdkColor c1[NUM_SYMBOLIC_COLORS], c2[NUM_SYMBOLIC_COLORS];
+ int i;
+
+ if (!mate_theme_color_scheme_parse (s1, c1) ||
+ !mate_theme_color_scheme_parse (s2, c2))
+ return FALSE;
+
+ for (i = 0; i < NUM_SYMBOLIC_COLORS; ++i) {
+ if (!gdk_color_equal (&c1[i], &c2[i]))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+void
+mate_theme_init ()
+{
+ GFile *top_theme_dir;
+ gchar *top_theme_dir_string;
+ static gboolean initted = FALSE;
+ gchar **search_path;
+ gint i, n;
+
+ if (initted)
+ return;
+
+ initting = TRUE;
+
+ meta_theme_hash_by_uri = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+ meta_theme_hash_by_name = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+ icon_theme_hash_by_uri = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+ icon_theme_hash_by_name = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+ cursor_theme_hash_by_uri = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+ cursor_theme_hash_by_name = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+ theme_hash_by_uri = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+ theme_hash_by_name = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+ /* Add all the toplevel theme dirs. */
+ /* $datadir/themes */
+ top_theme_dir_string = gtk_rc_get_theme_dir ();
+ top_theme_dir = g_file_new_for_path (top_theme_dir_string);
+ g_free (top_theme_dir_string);
+ add_top_theme_dir_monitor (top_theme_dir, 1, NULL);
+ g_object_unref (top_theme_dir);
+
+ /* ~/.themes */
+ top_theme_dir_string = g_build_filename (g_get_home_dir (), ".themes", NULL);
+ top_theme_dir = g_file_new_for_path (top_theme_dir_string);
+ g_free (top_theme_dir_string);
+ if (!g_file_query_exists (top_theme_dir, NULL))
+ g_file_make_directory (top_theme_dir, NULL, NULL);
+ add_top_theme_dir_monitor (top_theme_dir, 0, NULL);
+ g_object_unref (top_theme_dir);
+
+ /* ~/.icons */
+ top_theme_dir_string = g_build_filename (g_get_home_dir (), ".icons", NULL);
+ top_theme_dir = g_file_new_for_path (top_theme_dir_string);
+ g_free (top_theme_dir_string);
+ if (!g_file_query_exists (top_theme_dir, NULL))
+ g_file_make_directory (top_theme_dir, NULL, NULL);
+ g_object_unref (top_theme_dir);
+
+ /* icon theme search path */
+ gtk_icon_theme_get_search_path (gtk_icon_theme_get_default (), &search_path, &n);
+ for (i = 0; i < n; ++i) {
+ top_theme_dir = g_file_new_for_path (search_path[i]);
+ add_top_icon_theme_dir_monitor (top_theme_dir, i, NULL);
+ g_object_unref (top_theme_dir);
+ }
+ g_strfreev (search_path);
+
+#ifdef XCURSOR_ICONDIR
+ /* if there's a separate xcursors dir, add that as well */
+ if (strcmp (XCURSOR_ICONDIR, top_theme_dir_string) &&
+ strcmp (XCURSOR_ICONDIR, "/usr/share/icons")) {
+ top_theme_dir = g_file_new_for_path (XCURSOR_ICONDIR);
+ add_top_icon_theme_dir_monitor (top_theme_dir, 1, NULL);
+ g_object_unref (top_theme_dir);
+ }
+#endif
+
+#ifdef HAVE_XCURSOR
+ /* make sure we have the default theme */
+ if (!mate_theme_cursor_info_find ("default"))
+ add_default_cursor_theme ();
+#else
+ /* If we don't have Xcursor, use the built-in cursor fonts instead */
+ read_cursor_fonts ();
+#endif
+
+ /* done */
+ initted = TRUE;
+ initting = FALSE;
+}
diff --git a/capplets/common/mate-theme-info.h b/capplets/common/mate-theme-info.h
new file mode 100644
index 00000000..095e98ae
--- /dev/null
+++ b/capplets/common/mate-theme-info.h
@@ -0,0 +1,190 @@
+/* mate-theme-info.h - MATE Theme information
+
+ Copyright (C) 2002 Jonathan Blandford <[email protected]>
+ All rights reserved.
+
+ This file is part of the Mate Library.
+
+ The Mate Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Mate Library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Mate Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef MATE_THEME_INFO_H
+#define MATE_THEME_INFO_H
+
+#include <glib.h>
+#include <gio/gio.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gdk/gdk.h>
+
+typedef enum {
+ MATE_THEME_TYPE_METATHEME,
+ MATE_THEME_TYPE_ICON,
+ MATE_THEME_TYPE_CURSOR,
+ MATE_THEME_TYPE_REGULAR
+} MateThemeType;
+
+typedef enum {
+ MATE_THEME_CHANGE_CREATED,
+ MATE_THEME_CHANGE_DELETED,
+ MATE_THEME_CHANGE_CHANGED
+} MateThemeChangeType;
+
+typedef enum {
+ MATE_THEME_MARCO = 1 << 0,
+ MATE_THEME_GTK_2 = 1 << 1,
+ MATE_THEME_GTK_2_KEYBINDING = 1 << 2
+} MateThemeElement;
+
+typedef struct _MateThemeCommonInfo MateThemeCommonInfo;
+typedef struct _MateThemeCommonInfo MateThemeIconInfo;
+struct _MateThemeCommonInfo
+{
+ MateThemeType type;
+ gchar* path;
+ gchar* name;
+ gchar* readable_name;
+ gint priority;
+ gboolean hidden;
+};
+
+typedef struct _MateThemeInfo MateThemeInfo;
+struct _MateThemeInfo
+{
+ MateThemeType type;
+ gchar* path;
+ gchar* name;
+ gchar* readable_name;
+ gint priority;
+ gboolean hidden;
+
+ guint has_gtk : 1;
+ guint has_keybinding : 1;
+ guint has_marco : 1;
+};
+
+typedef struct _MateThemeCursorInfo MateThemeCursorInfo;
+struct _MateThemeCursorInfo {
+ MateThemeType type;
+ gchar* path;
+ gchar* name;
+ gchar* readable_name;
+ gint priority;
+ gboolean hidden;
+
+ GArray* sizes;
+ GdkPixbuf* thumbnail;
+};
+
+typedef struct _MateThemeMetaInfo MateThemeMetaInfo;
+struct _MateThemeMetaInfo {
+ MateThemeType type;
+ gchar* path;
+ gchar* name;
+ gchar* readable_name;
+ gint priority;
+ gboolean hidden;
+
+ gchar* comment;
+ gchar* icon_file;
+
+ gchar* gtk_theme_name;
+ gchar* gtk_color_scheme;
+ gchar* marco_theme_name;
+ gchar* icon_theme_name;
+ gchar* notification_theme_name;
+ gchar* sound_theme_name;
+ gchar* cursor_theme_name;
+ guint cursor_size;
+
+ gchar* application_font;
+ gchar* documents_font;
+ gchar* desktop_font;
+ gchar* windowtitle_font;
+ gchar* monospace_font;
+ gchar* background_image;
+};
+
+enum {
+ COLOR_FG,
+ COLOR_BG,
+ COLOR_TEXT,
+ COLOR_BASE,
+ COLOR_SELECTED_FG,
+ COLOR_SELECTED_BG,
+ COLOR_TOOLTIP_FG,
+ COLOR_TOOLTIP_BG,
+ NUM_SYMBOLIC_COLORS
+};
+
+typedef void (*ThemeChangedCallback) (MateThemeCommonInfo* theme, MateThemeChangeType change_type, MateThemeElement element_type, gpointer user_data);
+
+#define MATE_THEME_ERROR mate_theme_info_error_quark()
+
+enum {
+ MATE_THEME_ERROR_GTK_THEME_NOT_AVAILABLE = 1,
+ MATE_THEME_ERROR_WM_THEME_NOT_AVAILABLE,
+ MATE_THEME_ERROR_ICON_THEME_NOT_AVAILABLE,
+ MATE_THEME_ERROR_GTK_ENGINE_NOT_AVAILABLE,
+ MATE_THEME_ERROR_UNKNOWN
+};
+
+
+/* GTK/Marco/keybinding Themes */
+MateThemeInfo *mate_theme_info_new (void);
+void mate_theme_info_free (MateThemeInfo *theme_info);
+MateThemeInfo *mate_theme_info_find (const gchar *theme_name);
+GList *mate_theme_info_find_by_type (guint elements);
+GQuark mate_theme_info_error_quark (void);
+gchar *gtk_theme_info_missing_engine (const gchar *gtk_theme,
+ gboolean nameOnly);
+
+/* Icon Themes */
+MateThemeIconInfo *mate_theme_icon_info_new (void);
+void mate_theme_icon_info_free (MateThemeIconInfo *icon_theme_info);
+MateThemeIconInfo *mate_theme_icon_info_find (const gchar *icon_theme_name);
+GList *mate_theme_icon_info_find_all (void);
+gint mate_theme_icon_info_compare (MateThemeIconInfo *a,
+ MateThemeIconInfo *b);
+
+/* Cursor Themes */
+MateThemeCursorInfo *mate_theme_cursor_info_new (void);
+void mate_theme_cursor_info_free (MateThemeCursorInfo *info);
+MateThemeCursorInfo *mate_theme_cursor_info_find (const gchar *name);
+GList *mate_theme_cursor_info_find_all (void);
+gint mate_theme_cursor_info_compare (MateThemeCursorInfo *a,
+ MateThemeCursorInfo *b);
+
+/* Meta themes*/
+MateThemeMetaInfo *mate_theme_meta_info_new (void);
+void mate_theme_meta_info_free (MateThemeMetaInfo *meta_theme_info);
+MateThemeMetaInfo *mate_theme_meta_info_find (const gchar *meta_theme_name);
+GList *mate_theme_meta_info_find_all (void);
+gint mate_theme_meta_info_compare (MateThemeMetaInfo *a,
+ MateThemeMetaInfo *b);
+gboolean mate_theme_meta_info_validate (const MateThemeMetaInfo *info,
+ GError **error);
+MateThemeMetaInfo *mate_theme_read_meta_theme (GFile *meta_theme_uri);
+
+/* Other */
+void mate_theme_init (void);
+void mate_theme_info_register_theme_change (ThemeChangedCallback func,
+ gpointer data);
+
+gboolean mate_theme_color_scheme_parse (const gchar *scheme,
+ GdkColor *colors);
+gboolean mate_theme_color_scheme_equal (const gchar *s1,
+ const gchar *s2);
+
+#endif /* MATE_THEME_INFO_H */
diff --git a/capplets/common/mate-theme-test.c b/capplets/common/mate-theme-test.c
new file mode 100644
index 00000000..0c3c51f9
--- /dev/null
+++ b/capplets/common/mate-theme-test.c
@@ -0,0 +1,134 @@
+#include <config.h>
+#include <gtk/gtk.h>
+#include <string.h>
+#include <libmate/mate-desktop-item.h>
+#include "mate-theme-info.h"
+
+int
+main (int argc, char *argv[])
+{
+ GList *themes, *list;
+
+ g_thread_init (NULL);
+ gtk_init (&argc, &argv);
+ mate_theme_init ();
+
+ themes = mate_theme_meta_info_find_all ();
+ if (themes == NULL)
+ {
+ g_print ("No meta themes were found.\n");
+ }
+ else
+ {
+ g_print ("%d meta themes were found:\n", g_list_length (themes));
+ for (list = themes; list; list = list->next)
+ {
+ MateThemeMetaInfo *meta_theme_info;
+
+ meta_theme_info = list->data;
+ g_print ("\t%s\n", meta_theme_info->readable_name);
+ }
+ }
+ g_list_free (themes);
+
+ themes = mate_theme_icon_info_find_all ();
+ if (themes == NULL)
+ {
+ g_print ("No icon themes were found.\n");
+ }
+ else
+ {
+ g_print ("%d icon themes were found:\n", g_list_length (themes));
+ for (list = themes; list; list = list->next)
+ {
+ MateThemeIconInfo *icon_theme_info;
+
+ icon_theme_info = list->data;
+ g_print ("\t%s\n", icon_theme_info->name);
+ }
+ }
+ g_list_free (themes);
+
+ themes = mate_theme_info_find_by_type (MATE_THEME_MARCO);
+ if (themes == NULL)
+ {
+ g_print ("No marco themes were found.\n");
+ }
+ else
+ {
+ g_print ("%d marco themes were found:\n", g_list_length (themes));
+ for (list = themes; list; list = list->next)
+ {
+ MateThemeInfo *theme_info;
+
+ theme_info = list->data;
+ g_print ("\t%s\n", theme_info->name);
+ }
+ }
+ g_list_free (themes);
+
+ themes = mate_theme_info_find_by_type (MATE_THEME_GTK_2);
+ if (themes == NULL)
+ {
+ gchar *str;
+
+ g_print ("No gtk-2 themes were found. The following directories were tested:\n");
+ str = gtk_rc_get_theme_dir ();
+ g_print ("\t%s\n", str);
+ g_free (str);
+ str = g_build_filename (g_get_home_dir (), ".themes", NULL);
+ g_print ("\t%s\n", str);
+ g_free (str);
+ }
+ else
+ {
+ g_print ("%d gtk-2 themes were found:\n", g_list_length (themes));
+ for (list = themes; list; list = list->next)
+ {
+ MateThemeInfo *theme_info;
+
+ theme_info = list->data;
+ g_print ("\t%s\n", theme_info->name);
+ }
+ }
+ g_list_free (themes);
+
+ themes = mate_theme_info_find_by_type (MATE_THEME_GTK_2_KEYBINDING);
+ if (themes == NULL)
+ {
+ g_print ("No keybinding themes were found.\n");
+ }
+ else
+ {
+ g_print ("%d keybinding themes were found:\n", g_list_length (themes));
+ for (list = themes; list; list = list->next)
+ {
+ MateThemeInfo *theme_info;
+
+ theme_info = list->data;
+ g_print ("\t%s\n", theme_info->name);
+ }
+ }
+ g_list_free (themes);
+
+ themes = mate_theme_cursor_info_find_all ();
+ if (themes == NULL)
+ {
+ g_print ("No cursor themes were found.\n");
+ }
+ else
+ {
+ g_print ("%d cursor themes were found:\n", g_list_length (themes));
+ for (list = themes; list; list = list->next)
+ {
+ MateThemeCursorInfo *cursor_theme_info;
+
+ cursor_theme_info = list->data;
+ g_print ("\t%s\n", cursor_theme_info->name);
+ }
+ }
+ g_list_free (themes);
+
+ return 0;
+}
+
diff --git a/capplets/common/mateconf-property-editor-marshal.c b/capplets/common/mateconf-property-editor-marshal.c
new file mode 100644
index 00000000..9bead349
--- /dev/null
+++ b/capplets/common/mateconf-property-editor-marshal.c
@@ -0,0 +1,41 @@
+#include <glib.h>
+#include <glib-object.h>
+#include "mateconf-property-editor-marshal.h"
+
+/* VOID:STRING,POINTER (peditor-marshal.list:25) */
+void
+mateconf_property_editor_marshal_VOID__STRING_POINTER (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data)
+{
+ typedef void (*GMarshalFunc_VOID__STRING_POINTER) (gpointer data1,
+ gpointer arg_1,
+ gpointer arg_2,
+ gpointer data2);
+ register GMarshalFunc_VOID__STRING_POINTER callback;
+ register GCClosure *cc = (GCClosure*) closure;
+ register gpointer data1, data2;
+
+ g_return_if_fail (n_param_values == 3);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ }
+ else
+ {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback = (GMarshalFunc_VOID__STRING_POINTER) (marshal_data ? marshal_data : cc->callback);
+
+ callback (data1,
+ (char*) g_value_get_string (param_values + 1),
+ g_value_get_pointer (param_values + 2),
+ data2);
+}
+
diff --git a/capplets/common/mateconf-property-editor-marshal.h b/capplets/common/mateconf-property-editor-marshal.h
new file mode 100644
index 00000000..e26505cf
--- /dev/null
+++ b/capplets/common/mateconf-property-editor-marshal.h
@@ -0,0 +1,19 @@
+
+#include <gobject/gmarshal.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* VOID:STRING,POINTER (peditor-marshal.list:25) */
+extern void mateconf_property_editor_marshal_VOID__STRING_POINTER (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/capplets/common/mateconf-property-editor.c b/capplets/common/mateconf-property-editor.c
new file mode 100644
index 00000000..f565a168
--- /dev/null
+++ b/capplets/common/mateconf-property-editor.c
@@ -0,0 +1,1801 @@
+/* -*- mode: c; style: linux -*- */
+
+/* mateconf-property-editor.c
+ * Copyright (C) 2001 Ximian, Inc.
+ *
+ * Written by Bradford Hovinen <[email protected]>
+ *
+ * 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, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+#include "mateconf-property-editor.h"
+#include "mateconf-property-editor-marshal.h"
+
+enum {
+ VALUE_CHANGED,
+ LAST_SIGNAL
+};
+
+enum {
+ PROP_0,
+ PROP_KEY,
+ PROP_CALLBACK,
+ PROP_CHANGESET,
+ PROP_CONV_TO_WIDGET_CB,
+ PROP_CONV_FROM_WIDGET_CB,
+ PROP_UI_CONTROL,
+ PROP_DATA,
+ PROP_DATA_FREE_CB
+};
+
+struct _MateConfPropertyEditorPrivate
+{
+ gchar *key;
+ guint handler_id;
+ MateConfChangeSet *changeset;
+ GObject *ui_control;
+ MateConfPEditorValueConvFn conv_to_widget_cb;
+ MateConfPEditorValueConvFn conv_from_widget_cb;
+ MateConfClientNotifyFunc callback;
+ gboolean inited;
+
+ gpointer data;
+ GFreeFunc data_free_cb;
+};
+
+typedef struct
+{
+ GType enum_type;
+ MateConfPEditorGetValueFn enum_val_true_fn;
+ gpointer enum_val_true_fn_data;
+ guint enum_val_false;
+ gboolean use_nick;
+} MateConfPropertyEditorEnumData;
+
+static guint peditor_signals[LAST_SIGNAL];
+
+static void mateconf_property_editor_set_prop (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void mateconf_property_editor_get_prop (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+static void mateconf_property_editor_finalize (GObject *object);
+
+static GObject *mateconf_peditor_new (const gchar *key,
+ MateConfClientNotifyFunc cb,
+ MateConfChangeSet *changeset,
+ GObject *ui_control,
+ const gchar *first_prop_name,
+ va_list var_args,
+ const gchar *first_custom,
+ ...);
+
+G_DEFINE_TYPE (MateConfPropertyEditor, mateconf_property_editor, G_TYPE_OBJECT)
+
+#define MATECONF_PROPERTY_EDITOR_GET_PRIVATE(object) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((object), mateconf_property_editor_get_type (), MateConfPropertyEditorPrivate))
+
+
+static MateConfValue*
+mateconf_property_editor_conv_default (MateConfPropertyEditor *peditor,
+ const MateConfValue *value)
+{
+ return mateconf_value_copy (value);
+}
+
+static void
+mateconf_property_editor_init (MateConfPropertyEditor *mateconf_property_editor)
+{
+ mateconf_property_editor->p = MATECONF_PROPERTY_EDITOR_GET_PRIVATE (mateconf_property_editor);
+ mateconf_property_editor->p->conv_to_widget_cb = mateconf_property_editor_conv_default;
+ mateconf_property_editor->p->conv_from_widget_cb = mateconf_property_editor_conv_default;
+ mateconf_property_editor->p->inited = FALSE;
+}
+
+static void
+mateconf_property_editor_class_init (MateConfPropertyEditorClass *class)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (class);
+
+ object_class->finalize = mateconf_property_editor_finalize;
+ object_class->set_property = mateconf_property_editor_set_prop;
+ object_class->get_property = mateconf_property_editor_get_prop;
+
+ g_object_class_install_property
+ (object_class, PROP_KEY,
+ g_param_spec_string ("key",
+ _("Key"),
+ _("MateConf key to which this property editor is attached"),
+ NULL,
+ G_PARAM_READWRITE));
+ g_object_class_install_property
+ (object_class, PROP_CALLBACK,
+ g_param_spec_pointer ("callback",
+ _("Callback"),
+ _("Issue this callback when the value associated with key gets changed"),
+ G_PARAM_WRITABLE));
+ g_object_class_install_property
+ (object_class, PROP_CHANGESET,
+ g_param_spec_pointer ("changeset",
+ _("Change set"),
+ _("MateConf change set containing data to be forwarded to the mateconf client on apply"),
+ G_PARAM_READWRITE));
+ g_object_class_install_property
+ (object_class, PROP_CONV_TO_WIDGET_CB,
+ g_param_spec_pointer ("conv-to-widget-cb",
+ _("Conversion to widget callback"),
+ _("Callback to be issued when data are to be converted from MateConf to the widget"),
+ G_PARAM_WRITABLE));
+ g_object_class_install_property
+ (object_class, PROP_CONV_FROM_WIDGET_CB,
+ g_param_spec_pointer ("conv-from-widget-cb",
+ _("Conversion from widget callback"),
+ _("Callback to be issued when data are to be converted to MateConf from the widget"),
+ G_PARAM_WRITABLE));
+ g_object_class_install_property
+ (object_class, PROP_UI_CONTROL,
+ g_param_spec_object ("ui-control",
+ _("UI Control"),
+ _("Object that controls the property (normally a widget)"),
+ G_TYPE_OBJECT,
+ G_PARAM_WRITABLE));
+
+ peditor_signals[VALUE_CHANGED] =
+ g_signal_new ("value-changed",
+ G_TYPE_FROM_CLASS (object_class), 0,
+ G_STRUCT_OFFSET (MateConfPropertyEditorClass, value_changed),
+ NULL, NULL,
+ (GSignalCMarshaller) mateconf_property_editor_marshal_VOID__STRING_POINTER,
+ G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_POINTER);
+
+ g_object_class_install_property
+ (object_class, PROP_DATA,
+ g_param_spec_pointer ("data",
+ _("Property editor object data"),
+ _("Custom data required by the specific property editor"),
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property
+ (object_class, PROP_DATA_FREE_CB,
+ g_param_spec_pointer ("data-free-cb",
+ _("Property editor data freeing callback"),
+ _("Callback to be issued when property editor object data is to be freed"),
+ G_PARAM_WRITABLE));
+
+ g_type_class_add_private (class, sizeof (MateConfPropertyEditorPrivate));
+}
+
+static void
+mateconf_property_editor_set_prop (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ MateConfPropertyEditor *peditor;
+ MateConfClient *client;
+ MateConfNotifyFunc cb;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_MATECONF_PROPERTY_EDITOR (object));
+
+ peditor = MATECONF_PROPERTY_EDITOR (object);
+
+ switch (prop_id) {
+ case PROP_KEY:
+ peditor->p->key = g_value_dup_string (value);
+ break;
+
+ case PROP_CALLBACK:
+ client = mateconf_client_get_default ();
+ cb = g_value_get_pointer (value);
+ peditor->p->callback = (MateConfClientNotifyFunc) cb;
+ if (peditor->p->handler_id != 0) {
+ mateconf_client_notify_remove (client,
+ peditor->p->handler_id);
+ }
+ peditor->p->handler_id =
+ mateconf_client_notify_add (client, peditor->p->key,
+ peditor->p->callback,
+ peditor, NULL, NULL);
+ g_object_unref (client);
+ break;
+
+ case PROP_CHANGESET:
+ peditor->p->changeset = g_value_get_pointer (value);
+ break;
+
+ case PROP_CONV_TO_WIDGET_CB:
+ peditor->p->conv_to_widget_cb = g_value_get_pointer (value);
+ break;
+
+ case PROP_CONV_FROM_WIDGET_CB:
+ peditor->p->conv_from_widget_cb = g_value_get_pointer (value);
+ break;
+
+ case PROP_UI_CONTROL:
+ peditor->p->ui_control = g_value_get_object (value);
+ g_object_weak_ref (peditor->p->ui_control, (GWeakNotify) g_object_unref, object);
+ break;
+ case PROP_DATA:
+ peditor->p->data = g_value_get_pointer (value);
+ break;
+ case PROP_DATA_FREE_CB:
+ peditor->p->data_free_cb = g_value_get_pointer (value);
+ break;
+ default:
+ g_warning ("Bad argument set");
+ break;
+ }
+}
+
+static void
+mateconf_property_editor_get_prop (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ MateConfPropertyEditor *peditor;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_MATECONF_PROPERTY_EDITOR (object));
+
+ peditor = MATECONF_PROPERTY_EDITOR (object);
+
+ switch (prop_id) {
+ case PROP_KEY:
+ g_value_set_string (value, peditor->p->key);
+ break;
+
+ case PROP_CHANGESET:
+ g_value_set_pointer (value, peditor->p->changeset);
+ break;
+
+ case PROP_DATA:
+ g_value_set_pointer (value, peditor->p->data);
+ break;
+ default:
+ g_warning ("Bad argument get");
+ break;
+ }
+}
+
+static void
+mateconf_property_editor_finalize (GObject *object)
+{
+ MateConfPropertyEditor *mateconf_property_editor;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_MATECONF_PROPERTY_EDITOR (object));
+
+ mateconf_property_editor = MATECONF_PROPERTY_EDITOR (object);
+
+ g_free (mateconf_property_editor->p->key);
+
+ if (mateconf_property_editor->p->data_free_cb)
+ mateconf_property_editor->p->data_free_cb (mateconf_property_editor->p->data);
+
+ if (mateconf_property_editor->p->handler_id != 0) {
+ MateConfClient *client;
+
+ client = mateconf_client_get_default ();
+ mateconf_client_notify_remove (client,
+ mateconf_property_editor->p->handler_id);
+ g_object_unref (client);
+ }
+
+ G_OBJECT_CLASS (mateconf_property_editor_parent_class)->finalize (object);
+}
+
+static GObject *
+mateconf_peditor_new (const gchar *key,
+ MateConfClientNotifyFunc cb,
+ MateConfChangeSet *changeset,
+ GObject *ui_control,
+ const gchar *first_prop_name,
+ va_list var_args,
+ const gchar *first_custom,
+ ...)
+{
+ GObject *obj;
+ MateConfClient *client;
+ MateConfEntry *mateconf_entry;
+
+ g_return_val_if_fail (key != NULL, NULL);
+ g_return_val_if_fail (cb != NULL, NULL);
+
+ obj = g_object_new (mateconf_property_editor_get_type (),
+ "key", key,
+ "callback", cb,
+ "changeset", changeset,
+ "ui-control", ui_control,
+ NULL);
+
+ g_object_set_valist (obj, first_prop_name, var_args);
+
+ if (first_custom)
+ {
+ va_list custom_args;
+ va_start (custom_args, first_custom);
+ g_object_set_valist (obj, first_custom, custom_args);
+ va_end (custom_args);
+ }
+
+ client = mateconf_client_get_default ();
+ mateconf_entry = mateconf_client_get_entry (client, MATECONF_PROPERTY_EDITOR (obj)->p->key, NULL, TRUE, NULL);
+ MATECONF_PROPERTY_EDITOR (obj)->p->callback (client, 0, mateconf_entry, obj);
+ MATECONF_PROPERTY_EDITOR (obj)->p->inited = TRUE;
+ if (mateconf_entry)
+ mateconf_entry_free (mateconf_entry);
+ g_object_unref (client);
+
+ return obj;
+}
+
+const gchar *
+mateconf_property_editor_get_key (MateConfPropertyEditor *peditor)
+{
+ return peditor->p->key;
+}
+
+GObject *
+mateconf_property_editor_get_ui_control (MateConfPropertyEditor *peditor)
+{
+ return peditor->p->ui_control;
+}
+
+static void
+peditor_set_mateconf_value (MateConfPropertyEditor *peditor,
+ const gchar *key,
+ MateConfValue *value)
+{
+
+ if (peditor->p->changeset != NULL) {
+ if (value)
+ mateconf_change_set_set (peditor->p->changeset, peditor->p->key, value);
+ else
+ mateconf_change_set_unset (peditor->p->changeset, peditor->p->key);
+ } else {
+ MateConfClient *client = mateconf_client_get_default();
+
+ if (value)
+ mateconf_client_set (client, peditor->p->key, value, NULL);
+ else
+ mateconf_client_unset (client, peditor->p->key, NULL);
+
+ g_object_unref (client);
+ }
+
+}
+
+static void
+peditor_boolean_value_changed (MateConfClient *client,
+ guint cnxn_id,
+ MateConfEntry *entry,
+ MateConfPropertyEditor *peditor)
+{
+ MateConfValue *value, *value_wid;
+
+ if (peditor->p->changeset != NULL)
+ mateconf_change_set_remove (peditor->p->changeset, peditor->p->key);
+
+ if (entry && (value = mateconf_entry_get_value (entry))) {
+ value_wid = peditor->p->conv_to_widget_cb (peditor, value);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (peditor->p->ui_control), mateconf_value_get_bool (value_wid));
+ mateconf_value_free (value_wid);
+ }
+}
+
+static void
+peditor_boolean_widget_changed (MateConfPropertyEditor *peditor,
+ GtkToggleButton *tb)
+{
+ MateConfValue *value, *value_wid;
+
+ if (!peditor->p->inited) return;
+ value_wid = mateconf_value_new (MATECONF_VALUE_BOOL);
+ mateconf_value_set_bool (value_wid, gtk_toggle_button_get_active (tb));
+ value = peditor->p->conv_from_widget_cb (peditor, value_wid);
+ peditor_set_mateconf_value (peditor, peditor->p->key, value);
+ g_signal_emit (peditor, peditor_signals[VALUE_CHANGED], 0, peditor->p->key, value);
+ mateconf_value_free (value_wid);
+ mateconf_value_free (value);
+}
+
+GObject *
+mateconf_peditor_new_boolean (MateConfChangeSet *changeset,
+ const gchar *key,
+ GtkWidget *checkbox,
+ const gchar *first_property_name,
+ ...)
+{
+ GObject *peditor;
+ va_list var_args;
+
+ g_return_val_if_fail (key != NULL, NULL);
+ g_return_val_if_fail (checkbox != NULL, NULL);
+ g_return_val_if_fail (GTK_IS_TOGGLE_BUTTON (checkbox), NULL);
+
+ va_start (var_args, first_property_name);
+
+ peditor = mateconf_peditor_new
+ (key,
+ (MateConfClientNotifyFunc) peditor_boolean_value_changed,
+ changeset,
+ G_OBJECT (checkbox),
+ first_property_name,
+ var_args,
+ NULL);
+
+ va_end (var_args);
+
+ g_signal_connect_swapped (checkbox, "toggled",
+ (GCallback) peditor_boolean_widget_changed, peditor);
+
+ return peditor;
+}
+
+static void
+peditor_integer_value_changed (MateConfClient *client,
+ guint cnxn_id,
+ MateConfEntry *entry,
+ MateConfPropertyEditor *peditor)
+{
+ MateConfValue *value, *value_wid;
+ const char *entry_current_text;
+ int entry_current_integer;
+
+ if (peditor->p->changeset != NULL)
+ mateconf_change_set_remove (peditor->p->changeset, peditor->p->key);
+
+ if (entry && (value = mateconf_entry_get_value (entry))) {
+ value_wid = peditor->p->conv_to_widget_cb (peditor, value);
+ entry_current_text = gtk_entry_get_text (GTK_ENTRY (peditor->p->ui_control));
+ entry_current_integer = strtol (entry_current_text, NULL, 10);
+ if (entry_current_integer != mateconf_value_get_int (value)) {
+ char *buf = g_strdup_printf ("%d", mateconf_value_get_int (value_wid));
+ gtk_entry_set_text (GTK_ENTRY (peditor->p->ui_control), buf);
+ g_free (buf);
+ }
+ mateconf_value_free (value_wid);
+ }
+}
+
+static void
+peditor_integer_widget_changed (MateConfPropertyEditor *peditor,
+ GtkEntry *entry)
+{
+ MateConfValue *value, *value_wid;
+
+ if (!peditor->p->inited) return;
+
+ value_wid = mateconf_value_new (MATECONF_VALUE_INT);
+
+ mateconf_value_set_int (value_wid, strtol (gtk_entry_get_text (entry), NULL, 10));
+ value = peditor->p->conv_from_widget_cb (peditor, value_wid);
+
+ peditor_set_mateconf_value (peditor, peditor->p->key, value);
+
+ g_signal_emit (peditor, peditor_signals[VALUE_CHANGED], 0, peditor->p->key, value);
+ mateconf_value_free (value_wid);
+ mateconf_value_free (value);
+}
+
+static GObject *
+mateconf_peditor_new_integer_valist (MateConfChangeSet *changeset,
+ const gchar *key,
+ GtkWidget *entry,
+ const gchar *first_property_name,
+ va_list var_args)
+{
+ GObject *peditor;
+
+ peditor = mateconf_peditor_new
+ (key,
+ (MateConfClientNotifyFunc) peditor_integer_value_changed,
+ changeset,
+ G_OBJECT (entry),
+ first_property_name,
+ var_args, NULL);
+
+ g_signal_connect_swapped (entry, "changed",
+ (GCallback) peditor_integer_widget_changed, peditor);
+
+ return peditor;
+}
+
+GObject *
+mateconf_peditor_new_integer (MateConfChangeSet *changeset,
+ const gchar *key,
+ GtkWidget *entry,
+ const gchar *first_property_name,
+ ...)
+{
+ GObject *peditor;
+ va_list var_args;
+
+ g_return_val_if_fail (key != NULL, NULL);
+ g_return_val_if_fail (entry != NULL, NULL);
+ g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
+
+ va_start (var_args, first_property_name);
+
+ peditor = mateconf_peditor_new_integer_valist
+ (changeset, key, entry,
+ first_property_name, var_args);
+
+ va_end (var_args);
+
+ return peditor;
+}
+
+static void
+peditor_string_value_changed (MateConfClient *client,
+ guint cnxn_id,
+ MateConfEntry *entry,
+ MateConfPropertyEditor *peditor)
+{
+ MateConfValue *value, *value_wid;
+
+ if (peditor->p->changeset != NULL)
+ mateconf_change_set_remove (peditor->p->changeset, peditor->p->key);
+
+ if (entry && (value = mateconf_entry_get_value (entry))) {
+ const char *entry_current_text;
+ const char *mateconf_text;
+
+ value_wid = peditor->p->conv_to_widget_cb (peditor, value);
+ mateconf_text = mateconf_value_get_string (value_wid);
+ entry_current_text = gtk_entry_get_text (GTK_ENTRY (peditor->p->ui_control));
+
+ if (mateconf_text && strcmp (entry_current_text, mateconf_text) != 0) {
+ gtk_entry_set_text (GTK_ENTRY (peditor->p->ui_control), mateconf_value_get_string (value_wid));
+ }
+ mateconf_value_free (value_wid);
+ }
+}
+
+static void
+peditor_string_widget_changed (MateConfPropertyEditor *peditor,
+ GtkEntry *entry)
+{
+ MateConfValue *value, *value_wid;
+
+ if (!peditor->p->inited) return;
+
+ value_wid = mateconf_value_new (MATECONF_VALUE_STRING);
+
+ mateconf_value_set_string (value_wid, gtk_entry_get_text (entry));
+ value = peditor->p->conv_from_widget_cb (peditor, value_wid);
+
+ peditor_set_mateconf_value (peditor, peditor->p->key, value);
+
+ g_signal_emit (peditor, peditor_signals[VALUE_CHANGED], 0, peditor->p->key, value);
+ mateconf_value_free (value_wid);
+ mateconf_value_free (value);
+}
+
+static GObject *
+mateconf_peditor_new_string_valist (MateConfChangeSet *changeset,
+ const gchar *key,
+ GtkWidget *entry,
+ const gchar *first_property_name,
+ va_list var_args)
+{
+ GObject *peditor;
+
+ peditor = mateconf_peditor_new
+ (key,
+ (MateConfClientNotifyFunc) peditor_string_value_changed,
+ changeset,
+ G_OBJECT (entry),
+ first_property_name,
+ var_args, NULL);
+
+ g_signal_connect_swapped (entry, "changed",
+ (GCallback) peditor_string_widget_changed, peditor);
+
+ return peditor;
+}
+
+GObject *
+mateconf_peditor_new_string (MateConfChangeSet *changeset,
+ const gchar *key,
+ GtkWidget *entry,
+ const gchar *first_property_name,
+ ...)
+{
+ GObject *peditor;
+ va_list var_args;
+
+ g_return_val_if_fail (key != NULL, NULL);
+ g_return_val_if_fail (entry != NULL, NULL);
+ g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
+
+ va_start (var_args, first_property_name);
+
+ peditor = mateconf_peditor_new_string_valist
+ (changeset, key, entry,
+ first_property_name, var_args);
+
+ va_end (var_args);
+
+ return peditor;
+}
+
+static void
+peditor_color_value_changed (MateConfClient *client,
+ guint cnxn_id,
+ MateConfEntry *entry,
+ MateConfPropertyEditor *peditor)
+{
+ MateConfValue *value, *value_wid;
+
+ if (peditor->p->changeset != NULL)
+ mateconf_change_set_remove (peditor->p->changeset, peditor->p->key);
+
+ if (entry && (value = mateconf_entry_get_value (entry))) {
+ const gchar *spec;
+
+ value_wid = peditor->p->conv_to_widget_cb (peditor, value);
+ spec = mateconf_value_get_string (value_wid);
+ if (spec) {
+ GdkColor color;
+ gdk_color_parse (mateconf_value_get_string (value_wid), &color);
+ gtk_color_button_set_color (
+ GTK_COLOR_BUTTON (peditor->p->ui_control), &color);
+ }
+ mateconf_value_free (value_wid);
+ }
+}
+
+static void
+peditor_color_widget_changed (MateConfPropertyEditor *peditor,
+ GtkColorButton *cb)
+{
+ gchar *str;
+ MateConfValue *value, *value_wid;
+ GdkColor color;
+
+ if (!peditor->p->inited) return;
+
+ value_wid = mateconf_value_new (MATECONF_VALUE_STRING);
+ gtk_color_button_get_color (cb, &color);
+ str = g_strdup_printf ("#%02x%02x%02x", color.red >> 8,
+ color.green >> 8, color.blue >> 8);
+ mateconf_value_set_string (value_wid, str);
+ g_free (str);
+
+ value = peditor->p->conv_from_widget_cb (peditor, value_wid);
+
+ peditor_set_mateconf_value (peditor, peditor->p->key, value);
+ g_signal_emit (peditor, peditor_signals[VALUE_CHANGED], 0, peditor->p->key, value);
+
+ mateconf_value_free (value_wid);
+ mateconf_value_free (value);
+}
+
+GObject *
+mateconf_peditor_new_color (MateConfChangeSet *changeset,
+ const gchar *key,
+ GtkWidget *cb,
+ const gchar *first_property_name,
+ ...)
+{
+ GObject *peditor;
+ va_list var_args;
+
+ g_return_val_if_fail (key != NULL, NULL);
+ g_return_val_if_fail (cb != NULL, NULL);
+ g_return_val_if_fail (GTK_IS_COLOR_BUTTON (cb), NULL);
+
+ va_start (var_args, first_property_name);
+
+ peditor = mateconf_peditor_new
+ (key,
+ (MateConfClientNotifyFunc) peditor_color_value_changed,
+ changeset,
+ G_OBJECT (cb),
+ first_property_name,
+ var_args, NULL);
+
+ va_end (var_args);
+
+ g_signal_connect_swapped (cb, "color_set",
+ (GCallback) peditor_color_widget_changed, peditor);
+
+ return peditor;
+}
+
+static int
+peditor_enum_int_from_string (GType type, const gchar *str, gboolean use_nick)
+{
+ GEnumClass *klass;
+ GEnumValue *val;
+ int ret = -1;
+
+ klass = g_type_class_ref (type);
+ if (use_nick)
+ val = g_enum_get_value_by_nick (klass, str);
+ else
+ val = g_enum_get_value_by_name (klass, str);
+
+ g_type_class_unref (klass);
+
+ if (val)
+ ret = val->value;
+
+ return ret;
+}
+
+static gchar*
+peditor_enum_string_from_int (GType type, const int index, gboolean use_nick)
+{
+ GEnumClass *klass;
+ GEnumValue *val;
+ gchar *ret = NULL;
+
+ klass = g_type_class_ref (type);
+ val = g_enum_get_value (klass, index);
+ if (val)
+ {
+ if (val->value_nick && use_nick)
+ ret = g_strdup (val->value_nick);
+ else
+ ret = g_strdup (val->value_name);
+ }
+
+ g_type_class_unref (klass);
+
+ return ret;
+}
+
+static MateConfValue*
+peditor_enum_conv_to_widget (MateConfPropertyEditor *peditor,
+ const MateConfValue *value)
+{
+ MateConfValue *ret;
+ MateConfPropertyEditorEnumData *data = peditor->p->data;
+ int index;
+
+ if (value->type == MATECONF_VALUE_INT)
+ return mateconf_value_copy (value);
+
+ ret = mateconf_value_new (MATECONF_VALUE_INT);
+
+ index = peditor_enum_int_from_string (data->enum_type,
+ mateconf_value_get_string (value),
+ data->use_nick);
+
+ mateconf_value_set_int (ret, index);
+
+ return ret;
+}
+
+static MateConfValue*
+peditor_enum_conv_from_widget (MateConfPropertyEditor *peditor,
+ const MateConfValue *value)
+{
+ MateConfValue *ret;
+ MateConfPropertyEditorEnumData *data = peditor->p->data;
+ gchar *str;
+
+ if (value->type == MATECONF_VALUE_STRING)
+ return mateconf_value_copy (value);
+
+ ret = mateconf_value_new (MATECONF_VALUE_STRING);
+ str = peditor_enum_string_from_int (data->enum_type,
+ mateconf_value_get_int (value),
+ data->use_nick);
+ mateconf_value_set_string (ret, str);
+ g_free (str);
+
+ return ret;
+}
+
+static void
+peditor_combo_box_value_changed (MateConfClient *client,
+ guint cnxn_id,
+ MateConfEntry *entry,
+ MateConfPropertyEditor *peditor)
+{
+ MateConfValue *value, *value_wid;
+
+ if (peditor->p->changeset != NULL)
+ mateconf_change_set_remove (peditor->p->changeset, peditor->p->key);
+
+ if (entry && (value = mateconf_entry_get_value (entry))) {
+ value_wid = peditor->p->conv_to_widget_cb (peditor, value);
+ gtk_combo_box_set_active (GTK_COMBO_BOX (peditor->p->ui_control), mateconf_value_get_int (value_wid));
+ mateconf_value_free (value_wid);
+ }
+}
+
+static void
+peditor_combo_box_widget_changed (MateConfPropertyEditor *peditor,
+ GtkComboBox *combo_box)
+{
+ MateConfValue *value, *value_wid;
+
+ if (!peditor->p->inited) return;
+ value_wid = mateconf_value_new (MATECONF_VALUE_INT);
+ mateconf_value_set_int (value_wid, gtk_combo_box_get_active (combo_box));
+ value = peditor->p->conv_from_widget_cb (peditor, value_wid);
+ peditor_set_mateconf_value (peditor, peditor->p->key, value);
+ g_signal_emit (peditor, peditor_signals[VALUE_CHANGED], 0, peditor->p->key, value);
+ mateconf_value_free (value_wid);
+ if (value)
+ mateconf_value_free (value);
+}
+
+GObject *
+mateconf_peditor_new_combo_box (MateConfChangeSet *changeset,
+ const gchar *key,
+ GtkWidget *combo_box,
+ const gchar *first_property_name,
+ ...)
+{
+ GObject *peditor;
+ va_list var_args;
+
+ g_return_val_if_fail (key != NULL, NULL);
+ g_return_val_if_fail (combo_box != NULL, NULL);
+ g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), NULL);
+
+ va_start (var_args, first_property_name);
+
+ peditor = mateconf_peditor_new
+ (key,
+ (MateConfClientNotifyFunc) peditor_combo_box_value_changed,
+ changeset,
+ G_OBJECT (combo_box),
+ first_property_name,
+ var_args, NULL);
+
+ va_end (var_args);
+
+ g_signal_connect_swapped (combo_box, "changed",
+ (GCallback) peditor_combo_box_widget_changed, peditor);
+
+ return peditor;
+}
+
+GObject *
+mateconf_peditor_new_combo_box_with_enum (MateConfChangeSet *changeset,
+ const gchar *key,
+ GtkWidget *combo_box,
+ GType enum_type,
+ gboolean use_nick,
+ const gchar *first_property_name,
+ ...)
+{
+ GObject *peditor;
+ MateConfPropertyEditorEnumData *data;
+ va_list var_args;
+
+ g_return_val_if_fail (key != NULL, NULL);
+ g_return_val_if_fail (combo_box != NULL, NULL);
+ g_return_val_if_fail (GTK_IS_COMBO_BOX (combo_box), NULL);
+ g_return_val_if_fail (enum_type != G_TYPE_NONE, NULL);
+
+ data = g_new0 (MateConfPropertyEditorEnumData, 1);
+ data->enum_type = enum_type;
+ data->use_nick = use_nick;
+
+ va_start (var_args, first_property_name);
+
+ peditor = mateconf_peditor_new
+ (key,
+ (MateConfClientNotifyFunc) peditor_combo_box_value_changed,
+ changeset,
+ G_OBJECT (combo_box),
+ first_property_name,
+ var_args,
+ "conv-to-widget-cb",
+ peditor_enum_conv_to_widget,
+ "conv-from-widget-cb",
+ peditor_enum_conv_from_widget,
+ "data",
+ data,
+ "data-free-cb",
+ g_free,
+ NULL
+ );
+
+ va_end (var_args);
+
+ g_signal_connect_swapped (combo_box, "changed",
+ (GCallback) peditor_combo_box_widget_changed, peditor);
+
+ return peditor;
+}
+
+static void
+peditor_select_radio_value_changed (MateConfClient *client,
+ guint cnxn_id,
+ MateConfEntry *entry,
+ MateConfPropertyEditor *peditor)
+{
+ GSList *group, *link;
+ MateConfValue *value, *value_wid;
+
+ if (peditor->p->changeset != NULL)
+ mateconf_change_set_remove (peditor->p->changeset, peditor->p->key);
+
+ if (entry && (value = mateconf_entry_get_value (entry))) {
+ value_wid = peditor->p->conv_to_widget_cb (peditor, value);
+ group = g_slist_copy (gtk_radio_button_get_group (GTK_RADIO_BUTTON (peditor->p->ui_control)));
+ group = g_slist_reverse (group);
+ link = g_slist_nth (group, mateconf_value_get_int (value_wid));
+ if (link && link->data)
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (link->data), TRUE);
+ mateconf_value_free (value_wid);
+ g_slist_free (group);
+ }
+}
+
+static void
+peditor_select_radio_widget_changed (MateConfPropertyEditor *peditor,
+ GtkToggleButton *tb)
+{
+ GSList *group;
+ MateConfValue *value, *value_wid;
+
+ if (!peditor->p->inited) return;
+ if (!gtk_toggle_button_get_active (tb)) return;
+
+ value_wid = mateconf_value_new (MATECONF_VALUE_INT);
+ group = g_slist_copy (gtk_radio_button_get_group (GTK_RADIO_BUTTON (peditor->p->ui_control)));
+ group = g_slist_reverse (group);
+
+ mateconf_value_set_int (value_wid, g_slist_index (group, tb));
+ value = peditor->p->conv_from_widget_cb (peditor, value_wid);
+
+ peditor_set_mateconf_value (peditor, peditor->p->key, value);
+ g_signal_emit (peditor, peditor_signals[VALUE_CHANGED], 0, peditor->p->key, value);
+
+ mateconf_value_free (value_wid);
+ mateconf_value_free (value);
+ g_slist_free (group);
+}
+
+GObject *
+mateconf_peditor_new_select_radio (MateConfChangeSet *changeset,
+ const gchar *key,
+ GSList *radio_group,
+ const gchar *first_property_name,
+ ...)
+{
+ GObject *peditor;
+ GtkRadioButton *first_button;
+ GSList *item;
+ va_list var_args;
+
+ g_return_val_if_fail (key != NULL, NULL);
+ g_return_val_if_fail (radio_group != NULL, NULL);
+ g_return_val_if_fail (radio_group->data != NULL, NULL);
+ g_return_val_if_fail (GTK_IS_RADIO_BUTTON (radio_group->data), NULL);
+
+ first_button = GTK_RADIO_BUTTON (radio_group->data);
+
+ va_start (var_args, first_property_name);
+
+ peditor = mateconf_peditor_new
+ (key,
+ (MateConfClientNotifyFunc) peditor_select_radio_value_changed,
+ changeset,
+ G_OBJECT (first_button),
+ first_property_name,
+ var_args, NULL);
+
+ va_end (var_args);
+
+ for (item = radio_group; item != NULL; item = item->next)
+ g_signal_connect_swapped (item->data, "toggled",
+ (GCallback) peditor_select_radio_widget_changed, peditor);
+
+ return peditor;
+}
+
+static void
+peditor_numeric_range_value_changed (MateConfClient *client,
+ guint cnxn_id,
+ MateConfEntry *entry,
+ MateConfPropertyEditor *peditor)
+{
+ MateConfValue *value, *value_wid;
+
+ if (peditor->p->changeset != NULL)
+ mateconf_change_set_remove (peditor->p->changeset, peditor->p->key);
+
+ if (entry && (value = mateconf_entry_get_value (entry))) {
+ value_wid = peditor->p->conv_to_widget_cb (peditor, value);
+
+ switch (value_wid->type) {
+ case MATECONF_VALUE_FLOAT:
+ gtk_adjustment_set_value (GTK_ADJUSTMENT (peditor->p->ui_control), mateconf_value_get_float (value_wid));
+ break;
+ case MATECONF_VALUE_INT:
+ gtk_adjustment_set_value (GTK_ADJUSTMENT (peditor->p->ui_control), mateconf_value_get_int (value_wid));
+ break;
+ default:
+ g_warning ("Unknown type in range peditor: %d\n", value_wid->type);
+ }
+ mateconf_value_free (value_wid);
+ }
+}
+
+static void
+peditor_numeric_range_widget_changed (MateConfPropertyEditor *peditor,
+ GtkAdjustment *adjustment)
+{
+ MateConfValue *value, *value_wid, *default_value;
+ MateConfClient *client;
+
+ if (!peditor->p->inited) return;
+
+ /* We try to get the default type from the schemas. if not, we default
+ * to an int.
+ */
+ client = mateconf_client_get_default();
+
+ default_value = mateconf_client_get_default_from_schema (client,
+ peditor->p->key,
+ NULL);
+ g_object_unref (client);
+
+ if (default_value) {
+ value_wid = mateconf_value_new (default_value->type);
+ mateconf_value_free (default_value);
+ } else {
+ g_warning ("Unable to find a default value for key for %s.\n"
+ "I'll assume it is an integer, but that may break things.\n"
+ "Please be sure that the associated schema is installed",
+ peditor->p->key);
+ value_wid = mateconf_value_new (MATECONF_VALUE_INT);
+ }
+
+ g_assert (value_wid);
+
+ if (value_wid->type == MATECONF_VALUE_INT)
+ mateconf_value_set_int (value_wid, gtk_adjustment_get_value (adjustment));
+ else if (value_wid->type == MATECONF_VALUE_FLOAT)
+ mateconf_value_set_float (value_wid, gtk_adjustment_get_value (adjustment));
+ else {
+ g_warning ("unable to set a mateconf key for %s of type %d",
+ peditor->p->key,
+ value_wid->type);
+ mateconf_value_free (value_wid);
+ return;
+ }
+ value = peditor->p->conv_from_widget_cb (peditor, value_wid);
+ peditor_set_mateconf_value (peditor, peditor->p->key, value);
+ g_signal_emit (peditor, peditor_signals[VALUE_CHANGED], 0, peditor->p->key, value);
+ mateconf_value_free (value_wid);
+ mateconf_value_free (value);
+}
+
+GObject *
+mateconf_peditor_new_numeric_range (MateConfChangeSet *changeset,
+ const gchar *key,
+ GtkWidget *range,
+ const gchar *first_property_name,
+ ...)
+{
+ GObject *peditor;
+ GObject *adjustment = NULL;
+ va_list var_args;
+
+ g_return_val_if_fail (key != NULL, NULL);
+ g_return_val_if_fail (range != NULL, NULL);
+ g_return_val_if_fail (GTK_IS_RANGE (range)||GTK_IS_SPIN_BUTTON (range), NULL);
+
+ if (GTK_IS_RANGE (range))
+ adjustment = G_OBJECT (gtk_range_get_adjustment (GTK_RANGE (range)));
+ else if (GTK_IS_SPIN_BUTTON (range))
+ adjustment = G_OBJECT (gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (range)));
+ else
+ g_assert_not_reached ();
+
+ va_start (var_args, first_property_name);
+
+ peditor = mateconf_peditor_new
+ (key,
+ (MateConfClientNotifyFunc) peditor_numeric_range_value_changed,
+ changeset,
+ adjustment,
+ first_property_name,
+ var_args, NULL);
+
+ va_end (var_args);
+
+ g_signal_connect_swapped (adjustment, "value_changed",
+ (GCallback) peditor_numeric_range_widget_changed, peditor);
+
+ return peditor;
+}
+
+static gboolean
+guard_get_bool (MateConfPropertyEditor *peditor, const MateConfValue *value)
+{
+ if (value->type == MATECONF_VALUE_BOOL)
+ return mateconf_value_get_bool (value);
+ else
+ {
+ MateConfPropertyEditorEnumData *data = peditor->p->data;
+ int index = peditor_enum_int_from_string (data->enum_type, mateconf_value_get_string (value), data->use_nick);
+ return (index != data->enum_val_false);
+ }
+}
+
+static void
+guard_value_changed (MateConfPropertyEditor *peditor,
+ const gchar *key,
+ const MateConfValue *value,
+ GtkWidget *widget)
+{
+ gtk_widget_set_sensitive (widget, guard_get_bool (peditor, value));
+}
+
+void
+mateconf_peditor_widget_set_guard (MateConfPropertyEditor *peditor,
+ GtkWidget *widget)
+{
+ MateConfClient *client;
+ MateConfValue *value;
+
+ g_return_if_fail (peditor != NULL);
+ g_return_if_fail (IS_MATECONF_PROPERTY_EDITOR (peditor));
+ g_return_if_fail (widget != NULL);
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+
+ client = mateconf_client_get_default ();
+ value = mateconf_client_get (client, peditor->p->key, NULL);
+ g_object_unref (client);
+
+ if (value) {
+ gtk_widget_set_sensitive (widget, guard_get_bool (peditor, value));
+ mateconf_value_free (value);
+ } else {
+ g_warning ("NULL MateConf value: %s: possibly incomplete setup", peditor->p->key);
+ }
+
+ g_signal_connect (peditor, "value-changed", (GCallback) guard_value_changed, widget);
+}
+
+MateConfValue *
+mateconf_value_int_to_float (MateConfPropertyEditor *ignored, const MateConfValue *value)
+{
+ MateConfValue *new_value;
+
+ new_value = mateconf_value_new (MATECONF_VALUE_FLOAT);
+ mateconf_value_set_float (new_value, mateconf_value_get_int (value));
+ return new_value;
+}
+
+MateConfValue *
+mateconf_value_float_to_int (MateConfPropertyEditor *ignored, const MateConfValue *value)
+{
+ MateConfValue *new_value;
+
+ new_value = mateconf_value_new (MATECONF_VALUE_INT);
+ mateconf_value_set_int (new_value, mateconf_value_get_float (value));
+ return new_value;
+}
+
+static void
+peditor_font_value_changed (MateConfClient *client,
+ guint cnxn_id,
+ MateConfEntry *entry,
+ MateConfPropertyEditor *peditor)
+{
+ MateConfValue *value, *value_wid;
+
+ if (peditor->p->changeset != NULL)
+ mateconf_change_set_remove (peditor->p->changeset, peditor->p->key);
+
+ if (entry && (value = mateconf_entry_get_value (entry))) {
+ const gchar *font;
+
+ value_wid = peditor->p->conv_to_widget_cb (peditor, value);
+ font = mateconf_value_get_string (value_wid);
+ gtk_font_button_set_font_name (GTK_FONT_BUTTON (peditor->p->ui_control),
+ font);
+ mateconf_value_free (value_wid);
+ }
+}
+
+static void
+peditor_font_widget_changed (MateConfPropertyEditor *peditor,
+ GtkFontButton *font_button)
+{
+ const gchar *font_name;
+ MateConfValue *value, *value_wid = NULL;
+
+ if (!peditor->p->inited)
+ return;
+
+ font_name = gtk_font_button_get_font_name (font_button);
+
+ value_wid = mateconf_value_new (MATECONF_VALUE_STRING);
+ mateconf_value_set_string (value_wid, font_name);
+
+ value = peditor->p->conv_from_widget_cb (peditor, value_wid);
+
+ peditor_set_mateconf_value (peditor, peditor->p->key, value);
+ g_signal_emit (peditor, peditor_signals[VALUE_CHANGED], 0, peditor->p->key, value);
+
+ mateconf_value_free (value_wid);
+ mateconf_value_free (value);
+}
+
+GObject *
+mateconf_peditor_new_font (MateConfChangeSet *changeset,
+ const gchar *key,
+ GtkWidget *font_button,
+ const gchar *first_property_name,
+ ...)
+{
+ GObject *peditor;
+ va_list var_args;
+
+ g_return_val_if_fail (key != NULL, NULL);
+ g_return_val_if_fail (GTK_IS_FONT_BUTTON (font_button), NULL);
+
+ va_start (var_args, first_property_name);
+
+ peditor = mateconf_peditor_new (key,
+ (MateConfClientNotifyFunc) peditor_font_value_changed,
+ changeset,
+ G_OBJECT (font_button),
+ first_property_name,
+ var_args,
+ NULL);
+
+ va_end (var_args);
+
+ g_signal_connect_swapped (font_button, "font_set",
+ (GCallback) peditor_font_widget_changed, peditor);
+
+ return peditor;
+}
+
+static MateConfValue*
+peditor_enum_toggle_conv_to_widget (MateConfPropertyEditor *peditor,
+ const MateConfValue *value)
+{
+ MateConfValue *ret;
+ MateConfPropertyEditorEnumData *data = peditor->p->data;
+ int index;
+
+ if (value->type == MATECONF_VALUE_BOOL)
+ return mateconf_value_copy (value);
+
+ ret = mateconf_value_new (MATECONF_VALUE_BOOL);
+
+ index = peditor_enum_int_from_string (data->enum_type,
+ mateconf_value_get_string (value),
+ data->use_nick);
+ mateconf_value_set_bool (ret, (index != data->enum_val_false));
+
+ return ret;
+}
+
+static MateConfValue*
+peditor_enum_toggle_conv_from_widget (MateConfPropertyEditor *peditor,
+ const MateConfValue *value)
+{
+ MateConfValue *ret;
+ MateConfPropertyEditorEnumData *data = peditor->p->data;
+ gchar *str;
+ int index;
+
+ if (value->type == MATECONF_VALUE_STRING)
+ return mateconf_value_copy (value);
+
+ ret = mateconf_value_new (MATECONF_VALUE_STRING);
+ if (mateconf_value_get_bool (value))
+ index = data->enum_val_true_fn (peditor, data->enum_val_true_fn_data);
+ else
+ index = data->enum_val_false;
+
+ str = peditor_enum_string_from_int (data->enum_type, index, data->use_nick);
+ mateconf_value_set_string (ret, str);
+ g_free (str);
+
+ return ret;
+}
+
+GObject *
+mateconf_peditor_new_enum_toggle (MateConfChangeSet *changeset,
+ const gchar *key,
+ GtkWidget *checkbox,
+ GType enum_type,
+ MateConfPEditorGetValueFn val_true_fn,
+ guint val_false,
+ gboolean use_nick,
+ gpointer data,
+ const gchar *first_property_name,
+ ...)
+{
+ GObject *peditor;
+ MateConfPropertyEditorEnumData *enum_data;
+ va_list var_args;
+
+ g_return_val_if_fail (key != NULL, NULL);
+ g_return_val_if_fail (checkbox != NULL, NULL);
+ g_return_val_if_fail (GTK_IS_TOGGLE_BUTTON (checkbox), NULL);
+
+ enum_data = g_new0 (MateConfPropertyEditorEnumData, 1);
+ enum_data->enum_type = enum_type;
+ enum_data->enum_val_true_fn = val_true_fn;
+ enum_data->enum_val_true_fn_data = data;
+ enum_data->enum_val_false = val_false;
+ enum_data->use_nick = use_nick;
+
+ va_start (var_args, first_property_name);
+
+ peditor = mateconf_peditor_new
+ (key,
+ (MateConfClientNotifyFunc) peditor_boolean_value_changed,
+ changeset,
+ G_OBJECT (checkbox),
+ first_property_name,
+ var_args,
+ "conv-to-widget-cb",
+ peditor_enum_toggle_conv_to_widget,
+ "conv-from-widget-cb",
+ peditor_enum_toggle_conv_from_widget,
+ "data",
+ enum_data,
+ "data-free-cb",
+ g_free,
+ NULL);
+
+ va_end (var_args);
+
+ g_signal_connect_swapped (checkbox, "toggled",
+ (GCallback) peditor_boolean_widget_changed, peditor);
+
+ return peditor;
+}
+
+static gboolean
+peditor_image_set_filename (MateConfPropertyEditor *peditor, const gchar *filename)
+{
+ GdkPixbuf *pixbuf = NULL;
+ GtkImage *image = NULL;
+ const int scale = 100;
+ gchar *message = NULL;
+ GtkWidget *ui_control_child;
+ GList *l;
+
+ /* NULL is not valid, however "" is, but not an error (it's
+ * the default) */
+ g_return_val_if_fail (filename != NULL, FALSE);
+
+
+ if (!g_file_test (filename, G_FILE_TEST_EXISTS))
+ {
+ message = g_strdup_printf (_("Couldn't find the file '%s'.\n\nPlease make "
+ "sure it exists and try again, "
+ "or choose a different background picture."),
+ filename);
+
+ }
+ else if (!(pixbuf = gdk_pixbuf_new_from_file_at_size (filename, scale, scale, NULL)))
+ {
+ message = g_strdup_printf (_("I don't know how to open the file '%s'.\n"
+ "Perhaps it's "
+ "a kind of picture that is not yet supported.\n\n"
+ "Please select a different picture instead."),
+ filename);
+ }
+
+ ui_control_child = gtk_bin_get_child (GTK_BIN (peditor->p->ui_control));
+
+ if (GTK_IS_IMAGE (ui_control_child))
+ image = GTK_IMAGE (ui_control_child);
+ else
+ {
+ for (l = gtk_container_get_children (GTK_CONTAINER (ui_control_child)); l != NULL; l = l->next)
+ {
+ if (GTK_IS_IMAGE (l->data))
+ image = GTK_IMAGE (l->data);
+ else if (GTK_IS_LABEL (l->data) && message == NULL)
+ {
+ gchar *base = g_path_get_basename (filename);
+ gtk_label_set_text (GTK_LABEL (l->data), base);
+ g_free (base);
+ }
+ }
+ }
+
+ if (message)
+ {
+ if (peditor->p->inited)
+ {
+ GtkWidget *box;
+
+ box = gtk_message_dialog_new (NULL,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ "%s",
+ message);
+ gtk_dialog_run (GTK_DIALOG (box));
+ gtk_widget_destroy (box);
+ } else {
+ gtk_image_set_from_stock (image, GTK_STOCK_MISSING_IMAGE,
+ GTK_ICON_SIZE_BUTTON);
+ }
+ g_free (message);
+
+ return FALSE;
+ }
+
+ gtk_image_set_from_pixbuf (image, pixbuf);
+ g_object_unref (pixbuf);
+
+ return TRUE;
+}
+
+static void
+peditor_image_chooser_response_cb (GtkWidget *chooser,
+ gint response,
+ MateConfPropertyEditor *peditor)
+{
+ MateConfValue *value, *value_wid;
+ gchar *filename;
+
+ if (response == GTK_RESPONSE_CANCEL ||
+ response == GTK_RESPONSE_DELETE_EVENT)
+ {
+ gtk_widget_destroy (chooser);
+ return;
+ }
+
+ if (!peditor->p->inited)
+ return;
+
+ filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (chooser));
+ if (!(filename && peditor_image_set_filename (peditor, filename)))
+ {
+ g_free (filename);
+ return;
+ }
+
+ value_wid = mateconf_value_new (MATECONF_VALUE_STRING);
+ mateconf_value_set_string (value_wid, filename);
+ value = peditor->p->conv_from_widget_cb (peditor, value_wid);
+
+ peditor_set_mateconf_value (peditor, peditor->p->key, value);
+ g_signal_emit (peditor, peditor_signals[VALUE_CHANGED], 0, peditor->p->key, value);
+
+ mateconf_value_free (value_wid);
+ mateconf_value_free (value);
+ g_free (filename);
+ gtk_widget_destroy (chooser);
+}
+
+static void
+peditor_image_chooser_update_preview_cb (GtkFileChooser *chooser,
+ GtkImage *preview)
+{
+ char *filename;
+ GdkPixbuf *pixbuf = NULL;
+ const int scale = 100;
+
+ filename = gtk_file_chooser_get_preview_filename (chooser);
+
+ if (filename != NULL && g_file_test (filename, G_FILE_TEST_IS_REGULAR))
+ pixbuf = gdk_pixbuf_new_from_file_at_size (filename, scale, scale, NULL);
+
+ gtk_image_set_from_pixbuf (preview, pixbuf);
+
+ g_free (filename);
+
+ if (pixbuf != NULL)
+ g_object_unref (pixbuf);
+}
+
+static void
+peditor_image_clicked_cb (MateConfPropertyEditor *peditor, GtkButton *button)
+{
+ MateConfValue *value = NULL, *value_wid;
+ const gchar *filename;
+ GtkWidget *chooser, *toplevel, *preview, *preview_box;
+
+ toplevel = gtk_widget_get_toplevel (GTK_WIDGET (button));
+ chooser = gtk_file_chooser_dialog_new (_("Please select an image."),
+ GTK_IS_WINDOW (toplevel) ? GTK_WINDOW (toplevel)
+ : NULL,
+ GTK_FILE_CHOOSER_ACTION_OPEN,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ _("_Select"), GTK_RESPONSE_OK,
+ NULL);
+
+ preview = gtk_image_new ();
+
+ preview_box = gtk_hbox_new (FALSE, 6);
+ gtk_box_pack_start (GTK_BOX (preview_box), preview, FALSE, TRUE, 0);
+ gtk_container_set_border_width (GTK_CONTAINER (preview_box), 6);
+
+ gtk_widget_show_all (preview_box);
+ gtk_file_chooser_set_preview_widget (GTK_FILE_CHOOSER (chooser),
+ preview_box);
+ gtk_file_chooser_set_preview_widget_active (GTK_FILE_CHOOSER (chooser),
+ TRUE);
+
+ gtk_dialog_set_default_response (GTK_DIALOG (chooser), GTK_RESPONSE_OK);
+ gtk_window_set_destroy_with_parent (GTK_WINDOW (chooser), TRUE);
+ gtk_window_set_modal (GTK_WINDOW (chooser), TRUE);
+
+ /* need the current filename */
+ if (peditor->p->changeset)
+ mateconf_change_set_check_value (peditor->p->changeset, peditor->p->key, &value);
+
+ if (value)
+ {
+ /* the one we got is not a copy */
+ value = mateconf_value_copy (value);
+ }
+ else
+ {
+ MateConfClient *client = mateconf_client_get_default ();
+ value = mateconf_client_get (client, peditor->p->key, NULL);
+ g_object_unref (client);
+ }
+
+ value_wid = peditor->p->conv_to_widget_cb (peditor, value);
+ filename = mateconf_value_get_string (value_wid);
+
+ if (filename && strcmp (filename, ""))
+ gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (chooser), filename);
+
+ g_signal_connect (chooser, "update-preview",
+ G_CALLBACK (peditor_image_chooser_update_preview_cb),
+ preview);
+ g_signal_connect (chooser, "response",
+ G_CALLBACK (peditor_image_chooser_response_cb),
+ peditor);
+
+ if (gtk_grab_get_current ())
+ gtk_grab_add (chooser);
+
+ gtk_widget_show (chooser);
+
+ mateconf_value_free (value);
+ mateconf_value_free (value_wid);
+}
+
+static void
+peditor_image_value_changed (MateConfClient *client,
+ guint cnxn_id,
+ MateConfEntry *entry,
+ MateConfPropertyEditor *peditor)
+{
+ MateConfValue *value, *value_wid;
+
+ if (peditor->p->changeset != NULL)
+ mateconf_change_set_remove (peditor->p->changeset, peditor->p->key);
+
+ if (entry && (value = mateconf_entry_get_value (entry))) {
+ const gchar *filename;
+
+ value_wid = peditor->p->conv_to_widget_cb (peditor, value);
+ filename = mateconf_value_get_string (value_wid);
+ peditor_image_set_filename (peditor, filename);
+ mateconf_value_free (value_wid);
+ }
+}
+
+GObject *
+mateconf_peditor_new_image (MateConfChangeSet *changeset,
+ const gchar *key,
+ GtkWidget *button,
+ const gchar *first_property_name,
+ ...)
+{
+ GObject *peditor;
+ va_list var_args;
+
+ g_return_val_if_fail (key != NULL, NULL);
+ g_return_val_if_fail (button != NULL, NULL);
+ g_return_val_if_fail (GTK_IS_BUTTON (button), NULL);
+
+ va_start (var_args, first_property_name);
+
+ peditor = mateconf_peditor_new
+ (key,
+ (MateConfClientNotifyFunc) peditor_image_value_changed,
+ changeset,
+ G_OBJECT (button),
+ first_property_name,
+ var_args, NULL);
+
+ va_end (var_args);
+
+ g_signal_connect_swapped (button, "clicked",
+ (GCallback) peditor_image_clicked_cb, peditor);
+
+ return peditor;
+}
+
+GObject *
+mateconf_peditor_new_select_radio_with_enum (MateConfChangeSet *changeset,
+ const gchar *key,
+ GSList *radio_group,
+ GType enum_type,
+ gboolean use_nick,
+ const gchar *first_property_name,
+ ...)
+{
+ GObject *peditor;
+ MateConfPropertyEditorEnumData *enum_data;
+ GtkRadioButton *first_button;
+ GSList *item;
+ va_list var_args;
+
+ g_return_val_if_fail (key != NULL, NULL);
+ g_return_val_if_fail (radio_group != NULL, NULL);
+ g_return_val_if_fail (radio_group->data != NULL, NULL);
+ g_return_val_if_fail (GTK_IS_RADIO_BUTTON (radio_group->data), NULL);
+
+ enum_data = g_new0 (MateConfPropertyEditorEnumData, 1);
+ enum_data->enum_type = enum_type;
+ enum_data->use_nick = use_nick;
+
+ first_button = GTK_RADIO_BUTTON (radio_group->data);
+
+ va_start (var_args, first_property_name);
+
+ peditor = mateconf_peditor_new
+ (key,
+ (MateConfClientNotifyFunc) peditor_select_radio_value_changed,
+ changeset,
+ G_OBJECT (first_button),
+ first_property_name,
+ var_args,
+ "conv-to-widget-cb",
+ peditor_enum_conv_to_widget,
+ "conv-from-widget-cb",
+ peditor_enum_conv_from_widget,
+ "data",
+ enum_data,
+ "data-free-cb",
+ g_free,
+ NULL);
+
+ va_end (var_args);
+
+ for (item = radio_group; item != NULL; item = item->next)
+ g_signal_connect_swapped (item->data, "toggled",
+ (GCallback) peditor_select_radio_widget_changed, peditor);
+
+ return peditor;
+}
+
+static void
+peditor_tree_view_value_changed (MateConfClient *client,
+ guint cnxn_id,
+ MateConfEntry *entry,
+ MateConfPropertyEditor *peditor)
+{
+ MateConfValue *value;
+
+ if (peditor->p->changeset != NULL)
+ mateconf_change_set_remove (peditor->p->changeset, peditor->p->key);
+
+ if (entry && (value = mateconf_entry_get_value (entry))) {
+ GtkTreeView *treeview;
+ GtkTreeSelection *selection;
+ MateConfValue *value_wid;
+
+ treeview = GTK_TREE_VIEW (peditor->p->ui_control);
+ selection = gtk_tree_view_get_selection (treeview);
+
+ value_wid = peditor->p->conv_to_widget_cb (peditor, value);
+
+ if (value_wid != NULL) {
+ GtkTreePath *path = gtk_tree_path_new_from_string (
+ mateconf_value_get_string (value_wid));
+ gtk_tree_selection_select_path (selection, path);
+ gtk_tree_view_scroll_to_cell (treeview, path, NULL, FALSE, 0, 0);
+ gtk_tree_path_free (path);
+ mateconf_value_free (value_wid);
+ } else {
+ gtk_tree_selection_unselect_all (selection);
+ }
+ }
+}
+
+static void
+peditor_tree_view_widget_changed (MateConfPropertyEditor *peditor,
+ GtkTreeSelection *selection)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ MateConfValue *value, *value_wid;
+
+ if (!peditor->p->inited) return;
+
+ /* we don't support GTK_SELECTION_MULTIPLE */
+ if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
+ gchar *path;
+
+ path = gtk_tree_model_get_string_from_iter (model, &iter);
+ value_wid = mateconf_value_new (MATECONF_VALUE_STRING);
+ mateconf_value_set_string (value_wid, path);
+ g_free (path);
+ } else
+ value_wid = NULL;
+
+ value = peditor->p->conv_from_widget_cb (peditor, value_wid);
+ peditor_set_mateconf_value (peditor, peditor->p->key, value);
+ g_signal_emit (peditor, peditor_signals[VALUE_CHANGED], 0, peditor->p->key, value);
+
+ if (value_wid)
+ mateconf_value_free (value_wid);
+ if (value)
+ mateconf_value_free (value);
+}
+
+GObject *
+mateconf_peditor_new_tree_view (MateConfChangeSet *changeset,
+ const gchar *key,
+ GtkWidget *tree_view,
+ const gchar *first_property_name,
+ ...)
+{
+ GObject *peditor;
+ va_list var_args;
+
+ g_return_val_if_fail (key != NULL, NULL);
+ g_return_val_if_fail (tree_view != NULL, NULL);
+ g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
+
+ va_start (var_args, first_property_name);
+
+ peditor = mateconf_peditor_new
+ (key,
+ (MateConfClientNotifyFunc) peditor_tree_view_value_changed,
+ changeset,
+ G_OBJECT (tree_view),
+ first_property_name,
+ var_args, NULL);
+
+ va_end (var_args);
+
+ g_signal_connect_swapped (gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view)),
+ "changed",
+ (GCallback) peditor_tree_view_widget_changed, peditor);
+
+ return peditor;
+}
diff --git a/capplets/common/mateconf-property-editor.h b/capplets/common/mateconf-property-editor.h
new file mode 100644
index 00000000..1f15b9fd
--- /dev/null
+++ b/capplets/common/mateconf-property-editor.h
@@ -0,0 +1,162 @@
+/* -*- mode: c; style: linux -*- */
+
+/* mateconf-property-editor.h
+ * Copyright (C) 2001 Ximian, Inc.
+ *
+ * Written by Bradford Hovinen <[email protected]>
+ *
+ * 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, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef __MATECONF_PROPERTY_EDITOR_H
+#define __MATECONF_PROPERTY_EDITOR_H
+
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+#include <mateconf/mateconf-client.h>
+#include <mateconf/mateconf-changeset.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MATECONF_PROPERTY_EDITOR(obj) G_TYPE_CHECK_INSTANCE_CAST (obj, mateconf_property_editor_get_type (), MateConfPropertyEditor)
+#define MATECONF_PROPERTY_EDITOR_CLASS(klass) G_TYPE_CHECK_CLASS_CAST (klass, mateconf_property_editor_get_type (), MateConfPropertyEditorClass)
+#define IS_MATECONF_PROPERTY_EDITOR(obj) G_TYPE_CHECK_INSTANCE_TYPE (obj, mateconf_property_editor_get_type ())
+
+typedef struct _MateConfPropertyEditor MateConfPropertyEditor;
+typedef struct _MateConfPropertyEditorClass MateConfPropertyEditorClass;
+typedef struct _MateConfPropertyEditorPrivate MateConfPropertyEditorPrivate;
+
+typedef MateConfValue *(*MateConfPEditorValueConvFn) (MateConfPropertyEditor *peditor, const MateConfValue *);
+typedef int (*MateConfPEditorGetValueFn) (MateConfPropertyEditor *peditor, gpointer data);
+
+struct _MateConfPropertyEditor
+{
+ GObject parent;
+
+ MateConfPropertyEditorPrivate *p;
+};
+
+struct _MateConfPropertyEditorClass
+{
+ GObjectClass g_object_class;
+
+ void (*value_changed) (MateConfPropertyEditor *peditor, gchar *key, const MateConfValue *value);
+};
+
+GType mateconf_property_editor_get_type (void);
+
+const gchar *mateconf_property_editor_get_key (MateConfPropertyEditor *peditor);
+GObject *mateconf_property_editor_get_ui_control (MateConfPropertyEditor *peditor);
+
+GObject *mateconf_peditor_new_boolean (MateConfChangeSet *changeset,
+ const gchar *key,
+ GtkWidget *checkbox,
+ const gchar *first_property_name,
+ ...);
+
+GObject *mateconf_peditor_new_enum_toggle (MateConfChangeSet *changeset,
+ const gchar *key,
+ GtkWidget *checkbox,
+ GType enum_type,
+ MateConfPEditorGetValueFn val_true_fn,
+ guint val_false,
+ gboolean use_nick,
+ gpointer data,
+ const gchar *first_property_name,
+ ...);
+
+GObject *mateconf_peditor_new_integer (MateConfChangeSet *changeset,
+ const gchar *key,
+ GtkWidget *entry,
+ const gchar *first_property_name,
+ ...);
+GObject *mateconf_peditor_new_string (MateConfChangeSet *changeset,
+ const gchar *key,
+ GtkWidget *entry,
+ const gchar *first_property_name,
+ ...);
+GObject *mateconf_peditor_new_color (MateConfChangeSet *changeset,
+ const gchar *key,
+ GtkWidget *color_entry,
+ const gchar *first_property_name,
+ ...);
+
+GObject *mateconf_peditor_new_combo_box (MateConfChangeSet *changeset,
+ const gchar *key,
+ GtkWidget *combo_box,
+ const gchar *first_property_name,
+ ...);
+
+GObject *mateconf_peditor_new_combo_box_with_enum (MateConfChangeSet *changeset,
+ const gchar *key,
+ GtkWidget *combo_box,
+ GType enum_type,
+ gboolean use_nick,
+ const gchar *first_property_name,
+ ...);
+
+GObject *mateconf_peditor_new_select_radio (MateConfChangeSet *changeset,
+ const gchar *key,
+ GSList *radio_group,
+ const gchar *first_property_name,
+ ...);
+
+GObject *mateconf_peditor_new_select_radio_with_enum (MateConfChangeSet *changeset,
+ const gchar *key,
+ GSList *radio_group,
+ GType enum_type,
+ gboolean use_nick,
+ const gchar *first_property_name,
+ ...);
+
+GObject *mateconf_peditor_new_numeric_range (MateConfChangeSet *changeset,
+ const gchar *key,
+ GtkWidget *range,
+ const gchar *first_property_name,
+ ...);
+
+GObject *mateconf_peditor_new_font (MateConfChangeSet *changeset,
+ const gchar *key,
+ GtkWidget *font_button,
+ const gchar *first_property_name,
+ ...);
+
+GObject *mateconf_peditor_new_image (MateConfChangeSet *changeset,
+ const gchar *key,
+ GtkWidget *button,
+ const gchar *first_property,
+ ...);
+
+GObject *mateconf_peditor_new_tree_view (MateConfChangeSet *changeset,
+ const gchar *key,
+ GtkWidget *tree_view,
+ const gchar *first_property_name,
+ ...);
+
+void mateconf_peditor_widget_set_guard (MateConfPropertyEditor *peditor,
+ GtkWidget *widget);
+
+/* some convenience callbacks to map int <-> float */
+MateConfValue *mateconf_value_int_to_float (MateConfPropertyEditor *ignored, MateConfValue const *value);
+MateConfValue *mateconf_value_float_to_int (MateConfPropertyEditor *ignored, MateConfValue const *value);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MATECONF_PROPERTY_EDITOR_H */
diff --git a/capplets/common/theme-thumbnail.c b/capplets/common/theme-thumbnail.c
new file mode 100644
index 00000000..4afa4454
--- /dev/null
+++ b/capplets/common/theme-thumbnail.c
@@ -0,0 +1,1144 @@
+#include <config.h>
+#include <unistd.h>
+#include <string.h>
+#include <marco-private/util.h>
+#include <marco-private/theme.h>
+#include <marco-private/theme-parser.h>
+#include <marco-private/preview-widget.h>
+#include <signal.h>
+#include <errno.h>
+#include <math.h>
+
+/* We have to #undef this as marco #defines these. */
+#undef _
+#undef N_
+
+#include <glib.h>
+
+#include "theme-thumbnail.h"
+#include "gtkrc-utils.h"
+#include "capplet-util.h"
+
+typedef struct {
+ gboolean set;
+ gint thumbnail_width;
+ gint thumbnail_height;
+ GByteArray* data;
+ gchar* theme_name;
+ ThemeThumbnailFunc func;
+ gpointer user_data;
+ GDestroyNotify destroy;
+ GIOChannel* channel;
+ guint watch_id;
+} ThemeThumbnailAsyncData;
+
+
+static ThemeThumbnailAsyncData async_data;
+
+/* Protocol */
+
+/* Our protocol is pretty simple. The parent process will write several strings
+ * (separated by a '\000'). They are the widget theme, the wm theme, the icon
+ * theme, etc. Then, it will wait for the child to write back the data. The
+ * parent expects ICON_SIZE_WIDTH * ICON_SIZE_HEIGHT * 4 bytes of information.
+ * After that, the child is ready for the next theme to render.
+ */
+
+enum {
+ READY_FOR_THEME,
+ READING_TYPE,
+ READING_CONTROL_THEME_NAME,
+ READING_GTK_COLOR_SCHEME,
+ READING_WM_THEME_NAME,
+ READING_ICON_THEME_NAME,
+ READING_APPLICATION_FONT,
+ WRITING_PIXBUF_DATA
+};
+
+typedef struct {
+ gint status;
+ GByteArray* type;
+ GByteArray* control_theme_name;
+ GByteArray* gtk_color_scheme;
+ GByteArray* wm_theme_name;
+ GByteArray* icon_theme_name;
+ GByteArray* application_font;
+} ThemeThumbnailData;
+
+typedef struct {
+ gchar* thumbnail_type;
+ gpointer theme_info;
+ ThemeThumbnailFunc func;
+ gpointer user_data;
+ GDestroyNotify destroy;
+} ThemeQueueItem;
+
+static GList* theme_queue = NULL;
+
+static int pipe_to_factory_fd[2];
+static int pipe_from_factory_fd[2];
+
+#define THUMBNAIL_TYPE_META "meta"
+#define THUMBNAIL_TYPE_GTK "gtk"
+#define THUMBNAIL_TYPE_MARCO "marco"
+#define THUMBNAIL_TYPE_ICON "icon"
+
+#define META_THUMBNAIL_SIZE 128
+#define GTK_THUMBNAIL_SIZE 96
+#define MARCO_THUMBNAIL_WIDTH 120
+#define MARCO_THUMBNAIL_HEIGHT 60
+
+/* This draw the thumbnail of gtk
+ */
+static GdkPixmap* draw_window_on_pixbuf(GtkWidget* widget)
+{
+ GdkVisual* visual;
+ GdkPixmap* pixmap;
+ GtkStyle* style;
+ GdkScreen* screen = gdk_screen_get_default();
+ GdkWindow* window;
+ gint width, height;
+
+ gtk_widget_ensure_style(widget);
+
+ style = gtk_widget_get_style(widget);
+
+ g_assert(style);
+ g_assert(style->font_desc);
+
+ gtk_window_get_size(GTK_WINDOW(widget), &width, &height);
+
+ visual = gtk_widget_get_visual(widget);
+ pixmap = gdk_pixmap_new(NULL, width, height, visual->depth);
+ gdk_drawable_set_colormap(GDK_DRAWABLE(pixmap), gtk_widget_get_colormap(widget));
+
+ window = gtk_widget_get_window(widget);
+
+ /* This is a hack for the default resize grip on Ubuntu.
+ * Once again, thank you Ubuntu.
+ *
+ * We need to add a --enable-ubuntu for this.
+ */
+ #ifdef UBUNTU
+ gtk_window_set_has_resize_grip(GTK_WINDOW(widget), FALSE);
+ #endif
+
+ gdk_window_redirect_to_drawable(window, pixmap, 0, 0, 0, 0, width, height);
+ gdk_window_set_override_redirect(window, TRUE);
+ gtk_window_move(GTK_WINDOW(widget), gdk_screen_get_width(screen), gdk_screen_get_height(screen));
+ gtk_widget_show(widget);
+
+ gdk_window_process_updates(window, TRUE);
+ gtk_widget_hide(widget);
+
+ return pixmap;
+}
+
+static void pixbuf_apply_mask_region(GdkPixbuf* pixbuf, GdkRegion* region)
+{
+ gint nchannels, rowstride, w, h;
+ guchar *pixels, *p;
+
+ g_return_if_fail (pixbuf);
+ g_return_if_fail (region);
+
+ nchannels = gdk_pixbuf_get_n_channels (pixbuf);
+ rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+ pixels = gdk_pixbuf_get_pixels (pixbuf);
+
+
+ /* we need an alpha channel ... */
+ if (!gdk_pixbuf_get_has_alpha (pixbuf) || nchannels != 4)
+ return;
+
+ for (w = 0; w < gdk_pixbuf_get_width (pixbuf); ++w)
+ for (h = 0; h < gdk_pixbuf_get_height (pixbuf); ++h)
+ {
+ if (!gdk_region_point_in (region, w, h))
+ {
+ p = pixels + h * rowstride + w * nchannels;
+ if (G_BYTE_ORDER == G_BIG_ENDIAN)
+ p[0] = 0x0;
+ else
+ p[3] = 0x0;
+ }
+ }
+
+}
+
+static GdkPixbuf *
+create_folder_icon (char *icon_theme_name)
+{
+ GtkIconTheme *icon_theme;
+ GdkPixbuf *folder_icon = NULL;
+ GtkIconInfo *folder_icon_info;
+ gchar *example_icon_name;
+ const gchar *icon_names[5];
+ gint i;
+
+ icon_theme = gtk_icon_theme_new ();
+ gtk_icon_theme_set_custom_theme (icon_theme, icon_theme_name);
+
+ i = 0;
+ /* Get the Example icon name in the theme if specified */
+ example_icon_name = gtk_icon_theme_get_example_icon_name (icon_theme);
+ if (example_icon_name != NULL)
+ icon_names[i++] = example_icon_name;
+ icon_names[i++] = "x-directory-normal";
+ icon_names[i++] = "mate-fs-directory";
+ icon_names[i++] = "folder";
+ icon_names[i++] = NULL;
+
+ folder_icon_info = gtk_icon_theme_choose_icon (icon_theme, icon_names, 48, GTK_ICON_LOOKUP_FORCE_SIZE);
+ if (folder_icon_info != NULL)
+ {
+ folder_icon = gtk_icon_info_load_icon (folder_icon_info, NULL);
+ gtk_icon_info_free (folder_icon_info);
+ }
+
+ g_object_unref (icon_theme);
+ g_free (example_icon_name);
+
+ /* render the icon to the thumbnail */
+ if (folder_icon == NULL)
+ {
+ GtkWidget *dummy;
+ dummy = gtk_label_new ("");
+
+ folder_icon = gtk_widget_render_icon (dummy,
+ GTK_STOCK_MISSING_IMAGE,
+ GTK_ICON_SIZE_DIALOG,
+ NULL);
+
+ gtk_widget_destroy (dummy);
+ }
+
+ return folder_icon;
+}
+
+static GdkPixbuf *
+create_meta_theme_pixbuf (ThemeThumbnailData *theme_thumbnail_data)
+{
+ GtkWidget *window;
+ GtkWidget *preview;
+ GtkWidget *vbox;
+ GtkWidget *align;
+ GtkWidget *box;
+ GtkWidget *stock_button;
+ GtkWidget *checkbox;
+ GtkWidget *radio;
+
+ GtkRequisition requisition;
+ GtkAllocation allocation;
+ GtkAllocation vbox_allocation;
+ GdkPixmap *pixmap;
+ MetaFrameFlags flags;
+ MetaTheme *theme;
+ GdkPixbuf *pixbuf, *icon;
+ int icon_width, icon_height;
+ GdkRegion *region;
+
+ g_object_set (gtk_settings_get_default (),
+ "gtk-theme-name", (char *) theme_thumbnail_data->control_theme_name->data,
+ "gtk-font-name", (char *) theme_thumbnail_data->application_font->data,
+ "gtk-icon-theme-name", (char *) theme_thumbnail_data->icon_theme_name->data,
+ "gtk-color-scheme", (char *) theme_thumbnail_data->gtk_color_scheme->data,
+ NULL);
+
+ theme = meta_theme_load ((char *) theme_thumbnail_data->wm_theme_name->data, NULL);
+ if (theme == NULL)
+ return NULL;
+
+ /* Represent the icon theme */
+ icon = create_folder_icon ((char *) theme_thumbnail_data->icon_theme_name->data);
+ icon_width = gdk_pixbuf_get_width (icon);
+ icon_height = gdk_pixbuf_get_height (icon);
+
+ /* Create a fake window */
+ flags = META_FRAME_ALLOWS_DELETE |
+ META_FRAME_ALLOWS_MENU |
+ META_FRAME_ALLOWS_MINIMIZE |
+ META_FRAME_ALLOWS_MAXIMIZE |
+ META_FRAME_ALLOWS_VERTICAL_RESIZE |
+ META_FRAME_ALLOWS_HORIZONTAL_RESIZE |
+ META_FRAME_HAS_FOCUS |
+ META_FRAME_ALLOWS_SHADE |
+ META_FRAME_ALLOWS_MOVE;
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ preview = meta_preview_new ();
+ gtk_container_add (GTK_CONTAINER (window), preview);
+ gtk_widget_realize (window);
+ gtk_widget_realize (preview);
+ vbox = gtk_vbox_new (FALSE, 6);
+ gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
+ gtk_container_add (GTK_CONTAINER (preview), vbox);
+ align = gtk_alignment_new (0, 0, 0.0, 0.0);
+ gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 0);
+ stock_button = gtk_button_new_from_stock (GTK_STOCK_OPEN);
+ gtk_container_add (GTK_CONTAINER (align), stock_button);
+ box = gtk_hbox_new (FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (vbox), box, FALSE, FALSE, 0);
+ checkbox = gtk_check_button_new ();
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbox), TRUE);
+ gtk_box_pack_start (GTK_BOX (box), checkbox, FALSE, FALSE, 0);
+ radio = gtk_radio_button_new (NULL);
+ gtk_box_pack_start (GTK_BOX (box), radio, FALSE, FALSE, 0);
+
+ gtk_widget_show_all (preview);
+
+ meta_preview_set_frame_flags (META_PREVIEW (preview), flags);
+ meta_preview_set_theme (META_PREVIEW (preview), theme);
+ meta_preview_set_title (META_PREVIEW (preview), "");
+
+ gtk_window_set_default_size (GTK_WINDOW (window), META_THUMBNAIL_SIZE, META_THUMBNAIL_SIZE);
+
+ gtk_widget_size_request (window, &requisition);
+ allocation.x = 0;
+ allocation.y = 0;
+ allocation.width = META_THUMBNAIL_SIZE;
+ allocation.height = META_THUMBNAIL_SIZE;
+ gtk_widget_size_allocate (window, &allocation);
+ gtk_widget_size_request (window, &requisition);
+
+ pixmap = draw_window_on_pixbuf (window);
+
+ pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, META_THUMBNAIL_SIZE, META_THUMBNAIL_SIZE);
+ gdk_pixbuf_get_from_drawable (pixbuf, pixmap, NULL, 0, 0, 0, 0, META_THUMBNAIL_SIZE, META_THUMBNAIL_SIZE);
+
+ gtk_widget_get_allocation (vbox, &vbox_allocation);
+
+ /* Add the icon theme to the pixbuf */
+ gdk_pixbuf_composite (icon, pixbuf,
+ vbox_allocation.x + vbox_allocation.width - icon_width - 5,
+ vbox_allocation.y + vbox_allocation.height - icon_height - 5,
+ icon_width, icon_height,
+ vbox_allocation.x + vbox_allocation.width - icon_width - 5,
+ vbox_allocation.y + vbox_allocation.height - icon_height - 5,
+ 1.0, 1.0, GDK_INTERP_BILINEAR, 255);
+ region = meta_preview_get_clip_region (META_PREVIEW (preview),
+ META_THUMBNAIL_SIZE, META_THUMBNAIL_SIZE);
+ pixbuf_apply_mask_region (pixbuf, region);
+ gdk_region_destroy (region);
+
+ g_object_unref (icon);
+ gtk_widget_destroy (window);
+ meta_theme_free (theme);
+ g_object_unref (pixmap);
+
+ return pixbuf;
+}
+
+static GdkPixbuf *
+create_gtk_theme_pixbuf (ThemeThumbnailData *theme_thumbnail_data)
+{
+ GtkSettings *settings;
+ GtkWidget *window, *vbox, *box, *stock_button, *checkbox, *radio;
+ GtkRequisition requisition;
+ GtkAllocation allocation;
+ GdkPixmap *pixmap;
+ GdkPixbuf *pixbuf, *retval;
+ gint width, height;
+
+ settings = gtk_settings_get_default ();
+ g_object_set (settings, "gtk-theme-name", (char *) theme_thumbnail_data->control_theme_name->data,
+ "gtk-color-scheme", (char *) theme_thumbnail_data->gtk_color_scheme->data,
+ NULL);
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+ vbox = gtk_vbox_new (FALSE, 0);
+ gtk_container_add (GTK_CONTAINER (window), vbox);
+ box = gtk_hbox_new (FALSE, 6);
+ gtk_container_set_border_width (GTK_CONTAINER (box), 6);
+ gtk_box_pack_start (GTK_BOX (vbox), box, FALSE, FALSE, 0);
+ stock_button = gtk_button_new_from_stock (GTK_STOCK_OPEN);
+ gtk_box_pack_start (GTK_BOX (box), stock_button, FALSE, FALSE, 0);
+ checkbox = gtk_check_button_new ();
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbox), TRUE);
+ gtk_box_pack_start (GTK_BOX (box), checkbox, FALSE, FALSE, 0);
+ radio = gtk_radio_button_new_from_widget (NULL);
+ gtk_box_pack_start (GTK_BOX (box), radio, FALSE, FALSE, 0);
+
+ gtk_widget_show_all (vbox);
+ gtk_widget_realize (stock_button);
+ gtk_widget_realize (gtk_bin_get_child (GTK_BIN (stock_button)));
+ gtk_widget_realize (checkbox);
+ gtk_widget_realize (radio);
+ gtk_widget_map (stock_button);
+ gtk_widget_map (gtk_bin_get_child (GTK_BIN (stock_button)));
+ gtk_widget_map (checkbox);
+ gtk_widget_map (radio);
+
+ gtk_widget_size_request (window, &requisition);
+ allocation.x = 0;
+ allocation.y = 0;
+ allocation.width = requisition.width;
+ allocation.height = requisition.height;
+ gtk_widget_size_allocate (window, &allocation);
+ gtk_widget_size_request (window, &requisition);
+
+ gtk_window_get_size (GTK_WINDOW (window), &width, &height);
+
+ pixmap = draw_window_on_pixbuf (window);
+
+ pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, width, height);
+ gdk_pixbuf_get_from_drawable (pixbuf, pixmap, NULL, 0, 0, 0, 0, width, height);
+
+ retval = gdk_pixbuf_scale_simple (pixbuf,
+ GTK_THUMBNAIL_SIZE,
+ (int) GTK_THUMBNAIL_SIZE * (((double) height) / ((double) width)),
+ GDK_INTERP_BILINEAR);
+ g_object_unref (pixbuf);
+ gtk_widget_destroy (window);
+ g_object_unref (pixmap);
+
+ return retval;
+}
+
+static GdkPixbuf *
+create_marco_theme_pixbuf (ThemeThumbnailData *theme_thumbnail_data)
+{
+ GtkWidget *window, *preview, *dummy;
+ MetaFrameFlags flags;
+ MetaTheme *theme;
+ GtkRequisition requisition;
+ GtkAllocation allocation;
+ GdkPixmap *pixmap;
+ GdkPixbuf *pixbuf, *retval;
+ GdkRegion *region;
+
+ theme = meta_theme_load ((char *) theme_thumbnail_data->wm_theme_name->data, NULL);
+ if (theme == NULL)
+ return NULL;
+
+ flags = META_FRAME_ALLOWS_DELETE |
+ META_FRAME_ALLOWS_MENU |
+ META_FRAME_ALLOWS_MINIMIZE |
+ META_FRAME_ALLOWS_MAXIMIZE |
+ META_FRAME_ALLOWS_VERTICAL_RESIZE |
+ META_FRAME_ALLOWS_HORIZONTAL_RESIZE |
+ META_FRAME_HAS_FOCUS |
+ META_FRAME_ALLOWS_SHADE |
+ META_FRAME_ALLOWS_MOVE;
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_default_size (GTK_WINDOW (window), (int) MARCO_THUMBNAIL_WIDTH * 1.2, (int) MARCO_THUMBNAIL_HEIGHT * 1.2);
+
+ preview = meta_preview_new ();
+ meta_preview_set_frame_flags (META_PREVIEW (preview), flags);
+ meta_preview_set_theme (META_PREVIEW (preview), theme);
+ meta_preview_set_title (META_PREVIEW (preview), "");
+ gtk_container_add (GTK_CONTAINER (window), preview);
+
+ dummy = gtk_label_new ("");
+ gtk_container_add (GTK_CONTAINER (preview), dummy);
+
+ gtk_widget_realize (window);
+ gtk_widget_realize (preview);
+ gtk_widget_realize (dummy);
+ gtk_widget_show_all (preview);
+ gtk_widget_map (dummy);
+
+ gtk_widget_size_request (window, &requisition);
+ allocation.x = 0;
+ allocation.y = 0;
+ allocation.width = (int) MARCO_THUMBNAIL_WIDTH * 1.2;
+ allocation.height = (int) MARCO_THUMBNAIL_HEIGHT * 1.2;
+ gtk_widget_size_allocate (window, &allocation);
+ gtk_widget_size_request (window, &requisition);
+
+ pixmap = draw_window_on_pixbuf (window);
+
+ pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, (int) MARCO_THUMBNAIL_WIDTH * 1.2, (int) MARCO_THUMBNAIL_HEIGHT * 1.2);
+ gdk_pixbuf_get_from_drawable (pixbuf, pixmap, NULL, 0, 0, 0, 0, (int) MARCO_THUMBNAIL_WIDTH * 1.2, (int) MARCO_THUMBNAIL_HEIGHT * 1.2);
+
+ region = meta_preview_get_clip_region (META_PREVIEW (preview),
+ MARCO_THUMBNAIL_WIDTH * 1.2, MARCO_THUMBNAIL_HEIGHT * 1.2);
+ pixbuf_apply_mask_region (pixbuf, region);
+ gdk_region_destroy (region);
+
+
+ retval = gdk_pixbuf_scale_simple (pixbuf,
+ MARCO_THUMBNAIL_WIDTH,
+ MARCO_THUMBNAIL_HEIGHT,
+ GDK_INTERP_BILINEAR);
+ g_object_unref (pixbuf);
+
+ gtk_widget_destroy (window);
+ meta_theme_free (theme);
+ g_object_unref (pixmap);
+
+ return retval;
+}
+
+static GdkPixbuf *
+create_icon_theme_pixbuf (ThemeThumbnailData *theme_thumbnail_data)
+{
+ return create_folder_icon ((char *) theme_thumbnail_data->icon_theme_name->data);
+}
+
+
+static void
+handle_bytes (const gchar *buffer,
+ gint bytes_read,
+ ThemeThumbnailData *theme_thumbnail_data)
+{
+ const gchar *ptr;
+ ptr = buffer;
+
+ while (bytes_read > 0)
+ {
+ char *nil;
+
+ switch (theme_thumbnail_data->status)
+ {
+ case READY_FOR_THEME:
+ theme_thumbnail_data->status = READING_TYPE;
+ /* fall through */
+ case READING_TYPE:
+ nil = memchr (ptr, '\000', bytes_read);
+ if (nil == NULL)
+ {
+ g_byte_array_append (theme_thumbnail_data->type, ptr, bytes_read);
+ bytes_read = 0;
+ }
+ else
+ {
+ g_byte_array_append (theme_thumbnail_data->type, ptr, nil - ptr + 1);
+ bytes_read -= (nil - ptr + 1);
+ ptr = nil + 1;
+ theme_thumbnail_data->status = READING_CONTROL_THEME_NAME;
+ }
+ break;
+
+ case READING_CONTROL_THEME_NAME:
+ nil = memchr (ptr, '\000', bytes_read);
+ if (nil == NULL)
+ {
+ g_byte_array_append (theme_thumbnail_data->control_theme_name, ptr, bytes_read);
+ bytes_read = 0;
+ }
+ else
+ {
+ g_byte_array_append (theme_thumbnail_data->control_theme_name, ptr, nil - ptr + 1);
+ bytes_read -= (nil - ptr + 1);
+ ptr = nil + 1;
+ theme_thumbnail_data->status = READING_GTK_COLOR_SCHEME;
+ }
+ break;
+
+ case READING_GTK_COLOR_SCHEME:
+ nil = memchr (ptr, '\000', bytes_read);
+ if (nil == NULL)
+ {
+ g_byte_array_append (theme_thumbnail_data->gtk_color_scheme, ptr, bytes_read);
+ bytes_read = 0;
+ }
+ else
+ {
+ g_byte_array_append (theme_thumbnail_data->gtk_color_scheme, ptr, nil - ptr + 1);
+ bytes_read -= (nil - ptr + 1);
+ ptr = nil + 1;
+ theme_thumbnail_data->status = READING_WM_THEME_NAME;
+ }
+ break;
+
+ case READING_WM_THEME_NAME:
+ nil = memchr (ptr, '\000', bytes_read);
+ if (nil == NULL)
+ {
+ g_byte_array_append (theme_thumbnail_data->wm_theme_name, ptr, bytes_read);
+ bytes_read = 0;
+ }
+ else
+ {
+ g_byte_array_append (theme_thumbnail_data->wm_theme_name, ptr, nil - ptr + 1);
+ bytes_read -= (nil - ptr + 1);
+ ptr = nil + 1;
+ theme_thumbnail_data->status = READING_ICON_THEME_NAME;
+ }
+ break;
+
+ case READING_ICON_THEME_NAME:
+ nil = memchr (ptr, '\000', bytes_read);
+ if (nil == NULL)
+ {
+ g_byte_array_append (theme_thumbnail_data->icon_theme_name, ptr, bytes_read);
+ bytes_read = 0;
+ }
+ else
+ {
+ g_byte_array_append (theme_thumbnail_data->icon_theme_name, ptr, nil - ptr + 1);
+ bytes_read -= (nil - ptr + 1);
+ ptr = nil + 1;
+ theme_thumbnail_data->status = READING_APPLICATION_FONT;
+ }
+ break;
+
+ case READING_APPLICATION_FONT:
+ nil = memchr (ptr, '\000', bytes_read);
+ if (nil == NULL)
+ {
+ g_byte_array_append (theme_thumbnail_data->application_font, ptr, bytes_read);
+ bytes_read = 0;
+ }
+ else
+ {
+ g_byte_array_append (theme_thumbnail_data->application_font, ptr, nil - ptr + 1);
+ bytes_read -= (nil - ptr + 1);
+ ptr = nil + 1;
+ theme_thumbnail_data->status = WRITING_PIXBUF_DATA;
+ }
+ break;
+
+ default:
+ g_assert_not_reached ();
+ }
+ }
+}
+
+static gboolean
+message_from_capplet (GIOChannel *source,
+ GIOCondition condition,
+ gpointer data)
+{
+ gchar buffer[1024];
+ GIOStatus status;
+ gsize bytes_read;
+ ThemeThumbnailData *theme_thumbnail_data;
+
+ theme_thumbnail_data = (ThemeThumbnailData *) data;
+ status = g_io_channel_read_chars (source,
+ buffer,
+ 1024,
+ &bytes_read,
+ NULL);
+
+ switch (status)
+ {
+ case G_IO_STATUS_NORMAL:
+ handle_bytes (buffer, bytes_read, theme_thumbnail_data);
+
+ if (theme_thumbnail_data->status == WRITING_PIXBUF_DATA)
+ {
+ GdkPixbuf *pixbuf = NULL;
+ gint i, rowstride;
+ guchar *pixels;
+ gint width, height;
+ const gchar *type = (const gchar *) theme_thumbnail_data->type->data;
+
+ if (!strcmp (type, THUMBNAIL_TYPE_META))
+ pixbuf = create_meta_theme_pixbuf (theme_thumbnail_data);
+ else if (!strcmp (type, THUMBNAIL_TYPE_GTK))
+ pixbuf = create_gtk_theme_pixbuf (theme_thumbnail_data);
+ else if (!strcmp (type, THUMBNAIL_TYPE_MARCO))
+ pixbuf = create_marco_theme_pixbuf (theme_thumbnail_data);
+ else if (!strcmp (type, THUMBNAIL_TYPE_ICON))
+ pixbuf = create_icon_theme_pixbuf (theme_thumbnail_data);
+ else
+ g_assert_not_reached ();
+
+ if (pixbuf == NULL) {
+ width = height = rowstride = 0;
+ pixels = NULL;
+ } else {
+ width = gdk_pixbuf_get_width (pixbuf);
+ height = gdk_pixbuf_get_height (pixbuf);
+ rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+ pixels = gdk_pixbuf_get_pixels (pixbuf);
+ }
+
+ /* Write the pixbuf's size */
+ write (pipe_from_factory_fd[1], &width, sizeof (width));
+ write (pipe_from_factory_fd[1], &height, sizeof (height));
+
+ for (i = 0; i < height; i++)
+ {
+ write (pipe_from_factory_fd[1], pixels + rowstride * i, width * gdk_pixbuf_get_n_channels (pixbuf));
+ }
+
+ if (pixbuf)
+ g_object_unref (pixbuf);
+ g_byte_array_set_size (theme_thumbnail_data->type, 0);
+ g_byte_array_set_size (theme_thumbnail_data->control_theme_name, 0);
+ g_byte_array_set_size (theme_thumbnail_data->gtk_color_scheme, 0);
+ g_byte_array_set_size (theme_thumbnail_data->wm_theme_name, 0);
+ g_byte_array_set_size (theme_thumbnail_data->icon_theme_name, 0);
+ g_byte_array_set_size (theme_thumbnail_data->application_font, 0);
+ theme_thumbnail_data->status = READY_FOR_THEME;
+ }
+ return TRUE;
+
+ case G_IO_STATUS_AGAIN:
+ return TRUE;
+
+ case G_IO_STATUS_EOF:
+ case G_IO_STATUS_ERROR:
+ _exit (0);
+
+ default:
+ g_assert_not_reached ();
+ }
+
+ return TRUE;
+}
+
+static void
+generate_next_in_queue (void)
+{
+ ThemeQueueItem *item;
+
+ if (theme_queue == NULL)
+ return;
+
+ item = theme_queue->data;
+ theme_queue = g_list_delete_link (theme_queue, g_list_first (theme_queue));
+
+ if (!strcmp (item->thumbnail_type, THUMBNAIL_TYPE_META))
+ generate_meta_theme_thumbnail_async ((MateThemeMetaInfo *) item->theme_info,
+ item->func,
+ item->user_data,
+ item->destroy);
+ else if (!strcmp (item->thumbnail_type, THUMBNAIL_TYPE_GTK))
+ generate_gtk_theme_thumbnail_async ((MateThemeInfo *) item->theme_info,
+ item->func,
+ item->user_data,
+ item->destroy);
+ else if (!strcmp (item->thumbnail_type, THUMBNAIL_TYPE_MARCO))
+ generate_marco_theme_thumbnail_async ((MateThemeInfo *) item->theme_info,
+ item->func,
+ item->user_data,
+ item->destroy);
+ else if (!strcmp (item->thumbnail_type, THUMBNAIL_TYPE_ICON))
+ generate_icon_theme_thumbnail_async ((MateThemeIconInfo *) item->theme_info,
+ item->func,
+ item->user_data,
+ item->destroy);
+
+ g_free (item);
+}
+
+static gboolean
+message_from_child (GIOChannel *source,
+ GIOCondition condition,
+ gpointer data)
+{
+ gchar buffer[1024];
+ GIOStatus status;
+ gsize bytes_read;
+
+ if (async_data.set == FALSE)
+ return TRUE;
+
+ if (condition == G_IO_HUP)
+ return FALSE;
+
+ status = g_io_channel_read_chars (source,
+ buffer,
+ 1024,
+ &bytes_read,
+ NULL);
+ switch (status)
+ {
+ case G_IO_STATUS_NORMAL:
+ g_byte_array_append (async_data.data, (guchar *) buffer, bytes_read);
+
+ if (async_data.thumbnail_width == -1 && async_data.data->len >= 2 * sizeof (gint))
+ {
+ async_data.thumbnail_width = *((gint *) async_data.data->data);
+ async_data.thumbnail_height = *(((gint *) async_data.data->data) + 1);
+ g_byte_array_remove_range (async_data.data, 0, 2 * sizeof (gint));
+ }
+
+ if (async_data.thumbnail_width >= 0 && async_data.data->len == async_data.thumbnail_width * async_data.thumbnail_height * 4)
+ {
+ GdkPixbuf *pixbuf = NULL;
+
+ if (async_data.thumbnail_width > 0) {
+ gchar *pixels;
+ gint i, rowstride;
+
+ pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, async_data.thumbnail_width, async_data.thumbnail_height);
+ pixels = (gchar *) gdk_pixbuf_get_pixels (pixbuf);
+ rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+
+ for (i = 0; i < async_data.thumbnail_height; ++i)
+ memcpy (pixels + rowstride * i, async_data.data->data + 4 * async_data.thumbnail_width * i, async_data.thumbnail_width * 4);
+ }
+
+ /* callback function needs to ref the pixbuf if it wants to keep it */
+ (* async_data.func) (pixbuf, async_data.theme_name, async_data.user_data);
+
+ if (async_data.destroy)
+ (* async_data.destroy) (async_data.user_data);
+
+ if (pixbuf)
+ g_object_unref (pixbuf);
+
+ /* Clean up async_data */
+ g_free (async_data.theme_name);
+ g_source_remove (async_data.watch_id);
+ g_io_channel_unref (async_data.channel);
+
+ /* reset async_data */
+ async_data.thumbnail_width = -1;
+ async_data.thumbnail_height = -1;
+ async_data.theme_name = NULL;
+ async_data.channel = NULL;
+ async_data.func = NULL;
+ async_data.user_data = NULL;
+ async_data.destroy = NULL;
+ async_data.set = FALSE;
+ g_byte_array_set_size (async_data.data, 0);
+
+ generate_next_in_queue ();
+ }
+ return TRUE;
+
+ case G_IO_STATUS_AGAIN:
+ return TRUE;
+
+ case G_IO_STATUS_EOF:
+ case G_IO_STATUS_ERROR:
+ return FALSE;
+
+ default:
+ g_assert_not_reached ();
+ }
+
+ return TRUE;
+}
+
+static void
+send_thumbnail_request (gchar *thumbnail_type,
+ gchar *gtk_theme_name,
+ gchar *gtk_color_scheme,
+ gchar *marco_theme_name,
+ gchar *icon_theme_name,
+ gchar *application_font)
+{
+ write (pipe_to_factory_fd[1], thumbnail_type, strlen (thumbnail_type) + 1);
+
+ if (gtk_theme_name)
+ write (pipe_to_factory_fd[1], gtk_theme_name, strlen (gtk_theme_name) + 1);
+ else
+ write (pipe_to_factory_fd[1], "", 1);
+
+ if (gtk_color_scheme)
+ write (pipe_to_factory_fd[1], gtk_color_scheme, strlen (gtk_color_scheme) + 1);
+ else
+ write (pipe_to_factory_fd[1], "", 1);
+
+ if (marco_theme_name)
+ write (pipe_to_factory_fd[1], marco_theme_name, strlen (marco_theme_name) + 1);
+ else
+ write (pipe_to_factory_fd[1], "", 1);
+
+ if (icon_theme_name)
+ write (pipe_to_factory_fd[1], icon_theme_name, strlen (icon_theme_name) + 1);
+ else
+ write (pipe_to_factory_fd[1], "", 1);
+
+ if (application_font)
+ write (pipe_to_factory_fd[1], application_font, strlen (application_font) + 1);
+ else
+ write (pipe_to_factory_fd[1], "Sans 10", strlen ("Sans 10") + 1);
+
+}
+
+static GdkPixbuf *
+read_pixbuf (void)
+{
+ gint bytes_read, i, j = 0;
+ gint size[2];
+ GdkPixbuf *pixbuf;
+ gint rowstride;
+ guchar *pixels;
+
+ do
+ {
+ bytes_read = read (pipe_from_factory_fd[0], ((guint8*) size) + j, 2 * sizeof (gint));
+ if (bytes_read == 0)
+ goto eof;
+ j += bytes_read;
+ }
+ while (j < 2 * sizeof (gint));
+
+ if (size[0] <= 0 || size[1] <= 0)
+ return NULL;
+
+ pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, size[0], size[1]);
+ rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+ pixels = gdk_pixbuf_get_pixels (pixbuf);
+
+ for (i = 0; i < size[1]; i++)
+ {
+ j = 0;
+
+ do
+ {
+ bytes_read = read (pipe_from_factory_fd[0], pixels + rowstride * i + j, size[0] * gdk_pixbuf_get_n_channels (pixbuf) - j);
+
+ if (bytes_read > 0)
+ j += bytes_read;
+ else if (bytes_read == 0)
+ {
+ g_object_unref (pixbuf);
+ goto eof;
+ }
+ }
+ while (j < size[0] * gdk_pixbuf_get_n_channels (pixbuf));
+ }
+
+ return pixbuf;
+
+eof:
+ g_warning ("Received EOF while reading thumbnail");
+ close (pipe_to_factory_fd[1]);
+ pipe_to_factory_fd[1] = 0;
+ close (pipe_from_factory_fd[0]);
+ pipe_from_factory_fd[0] = 0;
+ return NULL;
+}
+
+static GdkPixbuf *
+generate_theme_thumbnail (gchar *thumbnail_type,
+ gchar *gtk_theme_name,
+ gchar *gtk_color_scheme,
+ gchar *marco_theme_name,
+ gchar *icon_theme_name,
+ gchar *application_font)
+{
+ if (async_data.set || !pipe_to_factory_fd[1] || !pipe_from_factory_fd[0])
+ return NULL;
+
+ send_thumbnail_request (thumbnail_type,
+ gtk_theme_name,
+ gtk_color_scheme,
+ marco_theme_name,
+ icon_theme_name,
+ application_font);
+
+ return read_pixbuf ();
+}
+
+GdkPixbuf *
+generate_meta_theme_thumbnail (MateThemeMetaInfo *theme_info)
+{
+ return generate_theme_thumbnail (THUMBNAIL_TYPE_META,
+ theme_info->gtk_theme_name,
+ theme_info->gtk_color_scheme,
+ theme_info->marco_theme_name,
+ theme_info->icon_theme_name,
+ theme_info->application_font);
+}
+
+GdkPixbuf *
+generate_gtk_theme_thumbnail (MateThemeInfo *theme_info)
+{
+ gchar *scheme;
+
+ scheme = gtkrc_get_color_scheme_for_theme (theme_info->name);
+
+ return generate_theme_thumbnail (THUMBNAIL_TYPE_GTK,
+ theme_info->name,
+ scheme,
+ NULL,
+ NULL,
+ NULL);
+ g_free (scheme);
+}
+
+GdkPixbuf *
+generate_marco_theme_thumbnail (MateThemeInfo *theme_info)
+{
+ return generate_theme_thumbnail (THUMBNAIL_TYPE_MARCO,
+ NULL,
+ NULL,
+ theme_info->name,
+ NULL,
+ NULL);
+}
+
+GdkPixbuf *
+generate_icon_theme_thumbnail (MateThemeIconInfo *theme_info)
+{
+ return generate_theme_thumbnail (THUMBNAIL_TYPE_ICON,
+ NULL,
+ NULL,
+ NULL,
+ theme_info->name,
+ NULL);
+}
+
+static void generate_theme_thumbnail_async(gpointer theme_info, gchar* theme_name, gchar* thumbnail_type, gchar* gtk_theme_name, gchar* gtk_color_scheme, gchar* marco_theme_name, gchar* icon_theme_name, gchar* application_font, ThemeThumbnailFunc func, gpointer user_data, GDestroyNotify destroy)
+{
+ if (async_data.set)
+ {
+ ThemeQueueItem* item = g_new0 (ThemeQueueItem, 1);
+
+ item->thumbnail_type = thumbnail_type;
+ item->theme_info = theme_info;
+ item->func = func;
+ item->user_data = user_data;
+ item->destroy = destroy;
+
+ theme_queue = g_list_append(theme_queue, item);
+
+ return;
+ }
+
+ if (!pipe_to_factory_fd[1] || !pipe_from_factory_fd[0])
+ {
+ (*func)(NULL, theme_name, user_data);
+
+ if (destroy)
+ {
+ (*destroy)(user_data);
+ }
+
+ return;
+ }
+
+ if (async_data.channel == NULL)
+ {
+ async_data.channel = g_io_channel_unix_new(pipe_from_factory_fd[0]);
+
+ g_io_channel_set_flags(async_data.channel, g_io_channel_get_flags (async_data.channel) | G_IO_FLAG_NONBLOCK, NULL);
+ g_io_channel_set_encoding(async_data.channel, NULL, NULL);
+
+ async_data.watch_id = g_io_add_watch(async_data.channel, G_IO_IN | G_IO_HUP, message_from_child, NULL);
+ }
+
+ async_data.set = TRUE;
+ async_data.thumbnail_width = -1;
+ async_data.thumbnail_height = -1;
+ async_data.theme_name = g_strdup(theme_name);
+ async_data.func = func;
+ async_data.user_data = user_data;
+ async_data.destroy = destroy;
+
+ send_thumbnail_request(thumbnail_type, gtk_theme_name, gtk_color_scheme, marco_theme_name, icon_theme_name, application_font);
+}
+
+void
+generate_meta_theme_thumbnail_async (MateThemeMetaInfo *theme_info,
+ ThemeThumbnailFunc func,
+ gpointer user_data,
+ GDestroyNotify destroy)
+{
+ generate_theme_thumbnail_async (theme_info,
+ theme_info->name,
+ THUMBNAIL_TYPE_META,
+ theme_info->gtk_theme_name,
+ theme_info->gtk_color_scheme,
+ theme_info->marco_theme_name,
+ theme_info->icon_theme_name,
+ theme_info->application_font,
+ func, user_data, destroy);
+}
+
+void generate_gtk_theme_thumbnail_async (MateThemeInfo* theme_info, ThemeThumbnailFunc func, gpointer user_data, GDestroyNotify destroy)
+{
+ gchar* scheme = gtkrc_get_color_scheme_for_theme(theme_info->name);
+
+ generate_theme_thumbnail_async(theme_info, theme_info->name, THUMBNAIL_TYPE_GTK, theme_info->name, scheme, NULL, NULL, NULL, func, user_data, destroy);
+
+ g_free(scheme);
+}
+
+void
+generate_marco_theme_thumbnail_async (MateThemeInfo *theme_info,
+ ThemeThumbnailFunc func,
+ gpointer user_data,
+ GDestroyNotify destroy)
+{
+ generate_theme_thumbnail_async (theme_info,
+ theme_info->name,
+ THUMBNAIL_TYPE_MARCO,
+ NULL,
+ NULL,
+ theme_info->name,
+ NULL,
+ NULL,
+ func, user_data, destroy);
+}
+
+void
+generate_icon_theme_thumbnail_async (MateThemeIconInfo *theme_info,
+ ThemeThumbnailFunc func,
+ gpointer user_data,
+ GDestroyNotify destroy)
+{
+ generate_theme_thumbnail_async (theme_info,
+ theme_info->name,
+ THUMBNAIL_TYPE_ICON,
+ NULL,
+ NULL,
+ NULL,
+ theme_info->name,
+ NULL,
+ func, user_data, destroy);
+}
+
+void
+theme_thumbnail_factory_init (int argc, char *argv[])
+{
+#ifndef __APPLE__
+ gint child_pid;
+#endif
+
+ pipe (pipe_to_factory_fd);
+ pipe (pipe_from_factory_fd);
+
+/* Apple's CoreFoundation classes must not be used from forked
+ * processes. Since freetype (and thus GTK) uses them, we simply
+ * disable the thumbnailer on MacOS for now. That means no thumbs
+ * until the thumbnailing process is rewritten, but at least we won't
+ * make apps crash. */
+#ifndef __APPLE__
+ child_pid = fork ();
+ if (child_pid == 0)
+ {
+ ThemeThumbnailData data;
+ GIOChannel *channel;
+
+ /* Child */
+ gtk_init (&argc, &argv);
+
+ close (pipe_to_factory_fd[1]);
+ pipe_to_factory_fd[1] = 0;
+ close (pipe_from_factory_fd[0]);
+ pipe_from_factory_fd[0] = 0;
+
+ data.status = READY_FOR_THEME;
+ data.type = g_byte_array_new ();
+ data.control_theme_name = g_byte_array_new ();
+ data.gtk_color_scheme = g_byte_array_new ();
+ data.wm_theme_name = g_byte_array_new ();
+ data.icon_theme_name = g_byte_array_new ();
+ data.application_font = g_byte_array_new ();
+
+ channel = g_io_channel_unix_new (pipe_to_factory_fd[0]);
+ g_io_channel_set_flags (channel, g_io_channel_get_flags (channel) |
+ G_IO_FLAG_NONBLOCK, NULL);
+ g_io_channel_set_encoding (channel, NULL, NULL);
+ g_io_add_watch (channel, G_IO_IN | G_IO_HUP, message_from_capplet, &data);
+ g_io_channel_unref (channel);
+
+ gtk_main ();
+ _exit (0);
+ }
+
+ g_assert (child_pid > 0);
+
+ /* Parent */
+ close (pipe_to_factory_fd[0]);
+ close (pipe_from_factory_fd[1]);
+#endif /* __APPLE__ */
+
+ async_data.set = FALSE;
+ async_data.theme_name = NULL;
+ async_data.data = g_byte_array_new ();
+}
diff --git a/capplets/common/theme-thumbnail.h b/capplets/common/theme-thumbnail.h
new file mode 100644
index 00000000..fe25f706
--- /dev/null
+++ b/capplets/common/theme-thumbnail.h
@@ -0,0 +1,37 @@
+#ifndef __THEME_THUMBNAIL_H__
+#define __THEME_THUMBNAIL_H__
+
+
+#include <gtk/gtk.h>
+#include "mate-theme-info.h"
+
+typedef void (* ThemeThumbnailFunc) (GdkPixbuf *pixbuf,
+ gchar *theme_name,
+ gpointer data);
+
+GdkPixbuf *generate_meta_theme_thumbnail (MateThemeMetaInfo *theme_info);
+GdkPixbuf *generate_gtk_theme_thumbnail (MateThemeInfo *theme_info);
+GdkPixbuf *generate_marco_theme_thumbnail (MateThemeInfo *theme_info);
+GdkPixbuf *generate_icon_theme_thumbnail (MateThemeIconInfo *theme_info);
+
+void generate_meta_theme_thumbnail_async (MateThemeMetaInfo *theme_info,
+ ThemeThumbnailFunc func,
+ gpointer data,
+ GDestroyNotify destroy);
+void generate_gtk_theme_thumbnail_async (MateThemeInfo *theme_info,
+ ThemeThumbnailFunc func,
+ gpointer data,
+ GDestroyNotify destroy);
+void generate_marco_theme_thumbnail_async (MateThemeInfo *theme_info,
+ ThemeThumbnailFunc func,
+ gpointer data,
+ GDestroyNotify destroy);
+void generate_icon_theme_thumbnail_async (MateThemeIconInfo *theme_info,
+ ThemeThumbnailFunc func,
+ gpointer data,
+ GDestroyNotify destroy);
+
+void theme_thumbnail_factory_init (int argc,
+ char *argv[]);
+
+#endif /* __THEME_THUMBNAIL_H__ */
diff --git a/capplets/common/wm-common.c b/capplets/common/wm-common.c
new file mode 100644
index 00000000..31cd503d
--- /dev/null
+++ b/capplets/common/wm-common.c
@@ -0,0 +1,184 @@
+#include <X11/Xatom.h>
+#include <gdk/gdkx.h>
+#include <gdk/gdk.h>
+#include <string.h>
+#include <glib.h>
+#include <glib-object.h>
+#include "wm-common.h"
+
+typedef struct _WMCallbackData
+{
+ GFunc func;
+ gpointer data;
+} WMCallbackData;
+
+/* Our WM Window */
+static Window wm_window = None;
+
+static char *
+wm_common_get_window_manager_property (Atom atom)
+{
+ Atom utf8_string, type;
+ int result;
+ char *retval;
+ int format;
+ gulong nitems;
+ gulong bytes_after;
+ gchar *val;
+
+ if (wm_window == None)
+ return NULL;
+
+ utf8_string = XInternAtom (GDK_DISPLAY (), "UTF8_STRING", False);
+
+ gdk_error_trap_push ();
+
+ val = NULL;
+ result = XGetWindowProperty (GDK_DISPLAY (),
+ wm_window,
+ atom,
+ 0, G_MAXLONG,
+ False, utf8_string,
+ &type, &format, &nitems,
+ &bytes_after, (guchar **) &val);
+
+ if (gdk_error_trap_pop () || result != Success ||
+ type != utf8_string || format != 8 || nitems == 0 ||
+ !g_utf8_validate (val, nitems, NULL))
+ {
+ retval = NULL;
+ }
+ else
+ {
+ retval = g_strndup (val, nitems);
+ }
+
+ if (val)
+ XFree (val);
+
+ return retval;
+}
+
+char*
+wm_common_get_current_window_manager (void)
+{
+ Atom atom = XInternAtom (GDK_DISPLAY (), "_NET_WM_NAME", False);
+ char *result;
+
+ result = wm_common_get_window_manager_property (atom);
+ if (result)
+ return result;
+ else
+ return g_strdup (WM_COMMON_UNKNOWN);
+}
+
+char**
+wm_common_get_current_keybindings (void)
+{
+ Atom keybindings_atom = XInternAtom (GDK_DISPLAY (), "_MATE_WM_KEYBINDINGS", False);
+ char *keybindings = wm_common_get_window_manager_property (keybindings_atom);
+ char **results;
+
+ if (keybindings)
+ {
+ char **p;
+ results = g_strsplit(keybindings, ",", -1);
+ for (p = results; *p; p++)
+ g_strstrip (*p);
+ g_free (keybindings);
+ }
+ else
+ {
+ Atom wm_atom = XInternAtom (GDK_DISPLAY (), "_NET_WM_NAME", False);
+ char *wm_name = wm_common_get_window_manager_property (wm_atom);
+ char *to_copy[] = { NULL, NULL };
+
+ to_copy[0] = wm_name ? wm_name : WM_COMMON_UNKNOWN;
+
+ results = g_strdupv (to_copy);
+ g_free (wm_name);
+ }
+
+ return results;
+}
+
+static void
+update_wm_window (void)
+{
+ Window *xwindow;
+ Atom type;
+ gint format;
+ gulong nitems;
+ gulong bytes_after;
+
+ XGetWindowProperty (GDK_DISPLAY (), GDK_ROOT_WINDOW (),
+ XInternAtom (GDK_DISPLAY (), "_NET_SUPPORTING_WM_CHECK", False),
+ 0, G_MAXLONG, False, XA_WINDOW, &type, &format,
+ &nitems, &bytes_after, (guchar **) &xwindow);
+
+ if (type != XA_WINDOW)
+ {
+ wm_window = None;
+ return;
+ }
+
+ gdk_error_trap_push ();
+ XSelectInput (GDK_DISPLAY (), *xwindow, StructureNotifyMask | PropertyChangeMask);
+ XSync (GDK_DISPLAY (), False);
+
+ if (gdk_error_trap_pop ())
+ {
+ XFree (xwindow);
+ wm_window = None;
+ return;
+ }
+
+ wm_window = *xwindow;
+ XFree (xwindow);
+}
+
+static GdkFilterReturn
+wm_window_event_filter (GdkXEvent *xev,
+ GdkEvent *event,
+ gpointer data)
+{
+ WMCallbackData *ncb_data = (WMCallbackData*) data;
+ XEvent *xevent = (XEvent *)xev;
+
+ if ((xevent->type == DestroyNotify &&
+ wm_window != None && xevent->xany.window == wm_window) ||
+ (xevent->type == PropertyNotify &&
+ xevent->xany.window == GDK_ROOT_WINDOW () &&
+ xevent->xproperty.atom == (XInternAtom (GDK_DISPLAY (), "_NET_SUPPORTING_WM_CHECK", False))) ||
+ (xevent->type == PropertyNotify &&
+ wm_window != None && xevent->xany.window == wm_window &&
+ xevent->xproperty.atom == (XInternAtom (GDK_DISPLAY (), "_NET_WM_NAME", False))))
+ {
+ update_wm_window ();
+ (* ncb_data->func) ((gpointer)wm_common_get_current_window_manager(),
+ ncb_data->data);
+ }
+
+ return GDK_FILTER_CONTINUE;
+}
+
+void
+wm_common_register_window_manager_change (GFunc func,
+ gpointer data)
+{
+ WMCallbackData *ncb_data;
+
+ ncb_data = g_new0 (WMCallbackData, 1);
+
+ ncb_data->func = func;
+ ncb_data->data = data;
+
+ gdk_window_add_filter (NULL, wm_window_event_filter, ncb_data);
+
+ update_wm_window ();
+
+ XSelectInput (GDK_DISPLAY (), GDK_ROOT_WINDOW (), PropertyChangeMask);
+ XSync (GDK_DISPLAY (), False);
+}
+
+
diff --git a/capplets/common/wm-common.h b/capplets/common/wm-common.h
new file mode 100644
index 00000000..564c6b9e
--- /dev/null
+++ b/capplets/common/wm-common.h
@@ -0,0 +1,17 @@
+#ifndef WM_COMMON_H
+#define WM_COMMON_H
+
+#define WM_COMMON_MARCO "Marco"
+#define WM_COMMON_SAWFISH "Sawfish"
+#define WM_COMMON_UNKNOWN "Unknown"
+
+gchar *wm_common_get_current_window_manager (void);
+/* Returns a strv of keybinding names for the window manager;
+ * using _MATE_WM_KEYBINDINGS if available, _NET_WM_NAME otherwise. */
+char **wm_common_get_current_keybindings (void);
+
+void wm_common_register_window_manager_change (GFunc func,
+ gpointer data);
+
+#endif /* WM_COMMON_H */
+
diff --git a/capplets/default-applications/Makefile.am b/capplets/default-applications/Makefile.am
new file mode 100644
index 00000000..b6487ec7
--- /dev/null
+++ b/capplets/default-applications/Makefile.am
@@ -0,0 +1,75 @@
+# This is used in MATECC_CAPPLETS_CFLAGS
+cappletname = default-applications
+
+bin_PROGRAMS = mate-default-applications-properties
+
+bin_SCRIPTS = mate-at-visual mate-at-mobility
+
+mate_default_applications_properties_LDADD = $(MATECC_CAPPLETS_LIBS)
+mate_default_applications_properties_SOURCES = \
+ mate-da-capplet.c mate-da-capplet.h \
+ mate-da-xml.c mate-da-xml.h \
+ mate-da-item.c mate-da-item.h
+
+@INTLTOOL_DESKTOP_RULE@
+
+uidir = $(pkgdatadir)/ui
+dist_ui_DATA = mate-default-applications-properties.ui
+
+mate-at-visual: mate-at-commandline.in
+ cp $< $@
+
+mate-at-mobility: mate-at-commandline.in
+ cp $< $@
+
+desktopdir = $(datadir)/applications
+Desktop_in_files = default-applications.desktop.in
+desktop_DATA = $(Desktop_in_files:.desktop.in=.desktop)
+
+pkgconfigdir = $(datadir)/pkgconfig
+pkgconfig_DATA = mate-default-applications.pc
+
+autostartdir = $(sysconfdir)/xdg/autostart
+autostart_in_files = mate-at-session.desktop.in
+autostart_DATA = $(autostart_in_files:.desktop.in=.desktop)
+
+xmldata_in_files = mate-default-applications.xml.in
+xmldatadir = $(pkgdatadir)/default-apps
+xmldata_DATA = $(xmldata_in_files:.xml.in=.xml)
+@INTLTOOL_XML_RULE@
+
+INCLUDES = \
+ $(MATECC_CAPPLETS_CFLAGS) \
+ $(DEFAULT_APPLICATIONS_CAPPLET_CFLAGS) \
+ -DMATELOCALEDIR=\""$(datadir)/locale"\"\
+ -DMATECC_UI_DIR=\""$(uidir)"\" \
+ -DMATECC_APPS_DIR=\""$(xmldatadir)"\"
+
+icons16dir = $(datadir)/icons/mate/16x16/apps
+dist_icons16_DATA = icons/16x16/preferences-desktop-default-applications.png
+icons22dir = $(datadir)/icons/mate/22x22/apps
+dist_icons22_DATA = icons/22x22/preferences-desktop-default-applications.png
+icons24dir = $(datadir)/icons/mate/24x24/apps
+dist_icons24_DATA = icons/24x24/preferences-desktop-default-applications.png
+icons32dir = $(datadir)/icons/mate/32x32/apps
+dist_icons32_DATA = icons/32x32/preferences-desktop-default-applications.png
+icons48dir = $(datadir)/icons/mate/48x48/apps
+dist_icons48_DATA = icons/48x48/preferences-desktop-default-applications.png
+
+gtk_update_icon_cache = gtk-update-icon-cache -f -t $(datadir)/icons/hicolor
+uninstall-hook: update-icon-cache
+install-data-hook: update-icon-cache
+update-icon-cache:
+ @-if test -z "$(DESTDIR)"; then \
+ echo "Updating Gtk icon cache."; \
+ $(gtk_update_icon_cache); \
+ else \
+ echo "*** Icon cache not updated. After install, run this:"; \
+ echo "*** $(gtk_update_icon_cache)"; \
+ fi
+
+
+CLEANFILES = $(MATECC_CAPPLETS_CLEANFILES) $(Desktop_in_files) $(desktop_DATA) $(xmldata_DATA) $(autostart_DATA) $(bin_SCRIPTS)
+EXTRA_DIST = $(xmldata_in_files) mate-default-applications.pc.in
+
+-include $(top_srcdir)/git.mk
diff --git a/capplets/default-applications/default-applications.desktop.in.in b/capplets/default-applications/default-applications.desktop.in.in
new file mode 100644
index 00000000..9b25b759
--- /dev/null
+++ b/capplets/default-applications/default-applications.desktop.in.in
@@ -0,0 +1,14 @@
+[Desktop Entry]
+_Name=Preferred Applications
+_Comment=Select your default applications
+Exec=mate-default-applications-properties
+Icon=preferences-desktop-default-applications
+Terminal=false
+Type=Application
+StartupNotify=true
+Categories=MATE;GTK;Settings;X-MATE-PersonalSettings;
+OnlyShowIn=MATE;
+X-MATE-Bugzilla-Bugzilla=MATE
+X-MATE-Bugzilla-Product=mate-control-center
+X-MATE-Bugzilla-Component=Preferred applications
+X-MATE-Bugzilla-Version=@VERSION@
diff --git a/capplets/default-applications/icons/16x16/preferences-desktop-default-applications.png b/capplets/default-applications/icons/16x16/preferences-desktop-default-applications.png
new file mode 100644
index 00000000..41a765aa
--- /dev/null
+++ b/capplets/default-applications/icons/16x16/preferences-desktop-default-applications.png
Binary files differ
diff --git a/capplets/default-applications/icons/22x22/preferences-desktop-default-applications.png b/capplets/default-applications/icons/22x22/preferences-desktop-default-applications.png
new file mode 100644
index 00000000..83b6826c
--- /dev/null
+++ b/capplets/default-applications/icons/22x22/preferences-desktop-default-applications.png
Binary files differ
diff --git a/capplets/default-applications/icons/24x24/preferences-desktop-default-applications.png b/capplets/default-applications/icons/24x24/preferences-desktop-default-applications.png
new file mode 100644
index 00000000..630ea040
--- /dev/null
+++ b/capplets/default-applications/icons/24x24/preferences-desktop-default-applications.png
Binary files differ
diff --git a/capplets/default-applications/icons/32x32/preferences-desktop-default-applications.png b/capplets/default-applications/icons/32x32/preferences-desktop-default-applications.png
new file mode 100644
index 00000000..23718f78
--- /dev/null
+++ b/capplets/default-applications/icons/32x32/preferences-desktop-default-applications.png
Binary files differ
diff --git a/capplets/default-applications/icons/48x48/preferences-desktop-default-applications.png b/capplets/default-applications/icons/48x48/preferences-desktop-default-applications.png
new file mode 100644
index 00000000..ac25569d
--- /dev/null
+++ b/capplets/default-applications/icons/48x48/preferences-desktop-default-applications.png
Binary files differ
diff --git a/capplets/default-applications/mate-at-commandline.in.in b/capplets/default-applications/mate-at-commandline.in.in
new file mode 100644
index 00000000..f9d93b16
--- /dev/null
+++ b/capplets/default-applications/mate-at-commandline.in.in
@@ -0,0 +1,101 @@
+#!/bin/sh
+#
+# Copyright 2006 IBM Corp.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of version 2 of the GNU General Public License
+# as published by the Free Software Foundation
+#
+# 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.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+#
+###############################################################################
+#
+# NOTE: This script is intended to be run from the command line,
+# MATE menu, or from the desktop autostart.
+#
+# /usr/bin/mate-at-visual
+# /usr/bin/mate-at-mobility
+#
+# If the "-s" flag is used then it is assumed to have been invoked
+# from /usr/share/mate/autostart/, and the first AT flagged
+# to "startup" from MATECONF_ALL will be executed.
+#
+
+USAGE="$0 [-s]"
+MATECONF_PATH=/desktop/mate/applications/at
+MATECONF_VISUAL="visual"
+MATECONF_MOBILITY="mobility"
+MATECONF_ALL="$MATECONF_VISUAL $MATECONF_MOBILITY"
+
+run_at() {
+ CMDLINE=`mateconftool-2 --get $MATECONF_PATH/$1/exec`
+ if [ $? -ne 0 ]; then
+ exit $?
+ fi
+
+ if [ -z "$CMDLINE" ]; then
+ exit 2
+ fi
+
+ STARTUP=`mateconftool-2 --get $MATECONF_PATH/$1/startup`
+ if [ $? -ne 0 ]; then
+ exit $?
+ fi
+
+ if [ ! -z "$AUTOSTART" ]; then
+ # assuming ran from /usr/share/mate/autostart
+ if [ "x$STARTUP" = "xtrue" ]; then
+ # mateconf indicated requested autostart
+ ($CMDLINE &)
+ fi
+ else
+ # run from command line or desktop menu
+ ($CMDLINE &)
+ fi
+}
+
+case `basename $0` in
+ mate-at-visual )
+ AT=$MATECONF_VISUAL
+ ;;
+ mate-at-mobility )
+ AT=$MATECONF_MOBILITY
+ ;;
+ mate-at-session | * )
+ AUTOSTART="yes"
+ AT=$MATECONF_ALL
+ ;;
+esac
+
+while getopts "s" options; do
+ case $options in
+ s ) AUTOSTART="yes"
+ AT=$MATECONF_ALL
+ shift
+ ;;
+ \? ) echo $USAGE
+ exit 1
+ ;;
+ * ) echo $USAGE
+ exit 1
+ ;;
+ esac
+done
+
+if [ $# -ne 0 ]; then
+ echo $USAGE
+ exit 1
+fi
+
+for I in $AT ; do
+ run_at $I
+done
+
+#EOF
diff --git a/capplets/default-applications/mate-at-session.desktop.in.in b/capplets/default-applications/mate-at-session.desktop.in.in
new file mode 100644
index 00000000..2e32f8ba
--- /dev/null
+++ b/capplets/default-applications/mate-at-session.desktop.in.in
@@ -0,0 +1,15 @@
+[Desktop Entry]
+_Name=Visual Assistance
+_Comment=Start the preferred visual assistive technology
+Exec=mate-at-visual -s
+Icon=preferences-desktop-accessibility
+Terminal=false
+Type=Application
+StartupNotify=false
+OnlyShowIn=MATE;
+AutostartCondition=MATE /desktop/mate/interface/accessibility
+X-MATE-Bugzilla-Bugzilla=MATE
+X-MATE-Bugzilla-Product=mate-control-center
+X-MATE-Bugzilla-Component=other capplets
+X-MATE-Bugzilla-Version=@VERSION@
+X-MATE-Autostart-enabled=true
diff --git a/capplets/default-applications/mate-da-capplet.c b/capplets/default-applications/mate-da-capplet.c
new file mode 100644
index 00000000..37a01359
--- /dev/null
+++ b/capplets/default-applications/mate-da-capplet.c
@@ -0,0 +1,970 @@
+/*
+ * Authors: Luca Cavalli <[email protected]>
+ *
+ * Copyright 2005-2006 Luca Cavalli
+ * Copyright 2008 Thomas Wood <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <glib/gi18n.h>
+#include <stdlib.h>
+
+#include "mateconf-property-editor.h"
+#include "mate-da-capplet.h"
+#include "mate-da-xml.h"
+#include "mate-da-item.h"
+#include "capplet-util.h"
+
+enum {
+ PIXBUF_COL,
+ TEXT_COL,
+ N_COLUMNS
+};
+
+static void close_cb(GtkWidget* window, gint response, gpointer user_data)
+{
+ if (response == GTK_RESPONSE_HELP)
+ {
+ capplet_help (GTK_WINDOW (window), "prefs-preferredapps");
+ }
+ else
+ {
+ gtk_widget_destroy (window);
+ gtk_main_quit ();
+ }
+}
+
+static void set_icon (GtkImage* image, GtkIconTheme* theme, const char* name)
+{
+ GdkPixbuf* pixbuf;
+
+ if ((pixbuf = gtk_icon_theme_load_icon(theme, name, 48, 0, NULL)))
+ {
+ gtk_image_set_from_pixbuf(image, pixbuf);
+ g_object_unref(pixbuf);
+ }
+}
+
+static void web_radiobutton_toggled_cb(GtkWidget* togglebutton, MateDACapplet* capplet)
+{
+ gint index;
+ MateDAWebItem *item;
+ const gchar *command;
+ GError *error = NULL;
+
+ index = gtk_combo_box_get_active (GTK_COMBO_BOX (capplet->web_combo_box));
+
+ if (index == -1)
+ return;
+
+ item = (MateDAWebItem *) g_list_nth_data (capplet->web_browsers, index);
+ if (item == NULL)
+ return;
+
+ if (togglebutton == capplet->new_win_radiobutton) {
+ command = item->win_command;
+ }
+ else if (togglebutton == capplet->new_tab_radiobutton) {
+ command = item->tab_command;
+ }
+ else {
+ command = item->generic.command;
+ }
+
+ mateconf_client_set_string (capplet->mateconf, DEFAULT_APPS_KEY_HTTP_EXEC, command, &error);
+
+ gtk_entry_set_text (GTK_ENTRY (capplet->web_browser_command_entry), command);
+
+ if (error != NULL) {
+ g_warning (_("Error saving configuration: %s"), error->message);
+ g_error_free (error);
+ }
+}
+
+static void web_combo_changed_cb(GtkComboBox* combo, MateDACapplet* capplet)
+{
+ guint current_index;
+ gboolean is_custom_active;
+ gboolean has_net_remote;
+ MateDAWebItem *item;
+ GtkWidget *active = NULL;
+
+ current_index = gtk_combo_box_get_active (combo);
+
+ if (current_index < g_list_length (capplet->web_browsers)) {
+
+ item = (MateDAWebItem*) g_list_nth_data (capplet->web_browsers, current_index);
+ has_net_remote = item->netscape_remote;
+ is_custom_active = FALSE;
+
+ }
+ else {
+ has_net_remote = FALSE;
+ is_custom_active = TRUE;
+ }
+ gtk_widget_set_sensitive (capplet->default_radiobutton, has_net_remote);
+ gtk_widget_set_sensitive (capplet->new_win_radiobutton, has_net_remote);
+ gtk_widget_set_sensitive (capplet->new_tab_radiobutton, has_net_remote);
+
+ gtk_widget_set_sensitive (capplet->web_browser_command_entry, is_custom_active);
+ gtk_widget_set_sensitive (capplet->web_browser_command_label, is_custom_active);
+ gtk_widget_set_sensitive (capplet->web_browser_terminal_checkbutton, is_custom_active);
+
+ if (has_net_remote) {
+
+ if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (capplet->new_win_radiobutton)))
+ active = capplet->new_win_radiobutton;
+ else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (capplet->new_tab_radiobutton)))
+ active = capplet->new_tab_radiobutton;
+ else
+ active = capplet->default_radiobutton;
+ }
+
+ web_radiobutton_toggled_cb (active, capplet);
+}
+
+/* FIXME: Refactor these two functions below into one... */
+static void mail_combo_changed_cb(GtkComboBox* combo, MateDACapplet* capplet)
+{
+ guint current_index;
+ gboolean is_custom_active;
+
+ current_index = gtk_combo_box_get_active (combo);
+ is_custom_active = (current_index >= g_list_length (capplet->mail_readers));
+
+ gtk_widget_set_sensitive (capplet->mail_reader_command_entry, is_custom_active);
+ gtk_widget_set_sensitive (capplet->mail_reader_command_label, is_custom_active);
+ gtk_widget_set_sensitive (capplet->mail_reader_terminal_checkbutton, is_custom_active);
+}
+
+static void media_combo_changed_cb(GtkComboBox* combo, MateDACapplet* capplet)
+{
+ guint current_index;
+ gboolean is_custom_active;
+
+ current_index = gtk_combo_box_get_active (combo);
+ is_custom_active = (current_index >= g_list_length (capplet->media_players));
+
+ gtk_widget_set_sensitive (capplet->media_player_command_entry, is_custom_active);
+ gtk_widget_set_sensitive (capplet->media_player_command_label, is_custom_active);
+ gtk_widget_set_sensitive (capplet->media_player_terminal_checkbutton, is_custom_active);
+}
+
+static void terminal_combo_changed_cb(GtkComboBox* combo, MateDACapplet* capplet)
+{
+ guint current_index;
+ gboolean is_custom_active;
+
+ current_index = gtk_combo_box_get_active (combo);
+ is_custom_active = (current_index >= g_list_length (capplet->terminals));
+
+ gtk_widget_set_sensitive (capplet->terminal_command_entry, is_custom_active);
+ gtk_widget_set_sensitive (capplet->terminal_command_label, is_custom_active);
+ gtk_widget_set_sensitive (capplet->terminal_exec_flag_entry, is_custom_active);
+ gtk_widget_set_sensitive (capplet->terminal_exec_flag_label, is_custom_active);
+}
+
+static void visual_combo_changed_cb(GtkComboBox* combo, MateDACapplet* capplet)
+{
+ guint current_index;
+ gboolean is_custom_active;
+
+ current_index = gtk_combo_box_get_active (combo);
+ is_custom_active = (current_index >= g_list_length (capplet->visual_ats));
+
+ gtk_widget_set_sensitive (capplet->visual_command_entry, is_custom_active);
+ gtk_widget_set_sensitive (capplet->visual_command_label, is_custom_active);
+}
+
+static void mobility_combo_changed_cb(GtkComboBox* combo, MateDACapplet* capplet)
+{
+ guint current_index;
+ gboolean is_custom_active;
+
+ current_index = gtk_combo_box_get_active (combo);
+ is_custom_active = (current_index >= g_list_length (capplet->mobility_ats));
+
+ gtk_widget_set_sensitive (capplet->mobility_command_entry, is_custom_active);
+ gtk_widget_set_sensitive (capplet->mobility_command_label, is_custom_active);
+}
+
+static void refresh_combo_box_icons(GtkIconTheme* theme, GtkComboBox* combo_box, GList* app_list)
+{
+ GList *entry;
+ MateDAItem *item;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GdkPixbuf *pixbuf;
+
+ for (entry = app_list; entry != NULL; entry = g_list_next (entry)) {
+ item = (MateDAItem *) entry->data;
+
+ model = gtk_combo_box_get_model (combo_box);
+
+ if (item->icon_path && gtk_tree_model_get_iter_from_string (model, &iter, item->icon_path)) {
+ pixbuf = gtk_icon_theme_load_icon (theme, item->icon_name, 22, 0, NULL);
+
+ gtk_list_store_set (GTK_LIST_STORE (model), &iter,
+ PIXBUF_COL, pixbuf,
+ -1);
+
+ if (pixbuf)
+ g_object_unref (pixbuf);
+ }
+ }
+}
+
+static struct {
+ const gchar* name;
+ const gchar* icon;
+} icons[] = {
+ {"web_browser_image", "web-browser"},
+ {"mail_reader_image", "emblem-mail"},
+ {"media_player_image", "applications-multimedia"},
+ {"visual_image", "zoom-best-fit"},
+ {"mobility_image", "preferences-desktop-accessibility"},
+ /*
+ {"messenger_image", "im"},
+ {"file_manager_image", "file-manager"},
+ {"image_image", "image-viewer"},
+ {"video_image", "mate-multimedia"},
+ {"text_image", "text-editor"},
+ */
+ {"terminal_image", "mate-terminal"}
+};
+
+static void theme_changed_cb(GtkIconTheme* theme, MateDACapplet* capplet)
+{
+ GObject *icon;
+ gint i;
+
+ for (i = 0; i < G_N_ELEMENTS (icons); i++)
+ {
+ icon = gtk_builder_get_object (capplet->builder, icons[i].name);
+ set_icon (GTK_IMAGE (icon), theme, icons[i].icon);
+ }
+
+ refresh_combo_box_icons (theme, GTK_COMBO_BOX (capplet->web_combo_box), capplet->web_browsers);
+ refresh_combo_box_icons (theme, GTK_COMBO_BOX (capplet->mail_combo_box), capplet->mail_readers);
+ refresh_combo_box_icons (theme, GTK_COMBO_BOX (capplet->media_combo_box), capplet->media_players);
+ refresh_combo_box_icons (theme, GTK_COMBO_BOX (capplet->term_combo_box), capplet->terminals);
+ refresh_combo_box_icons (theme, GTK_COMBO_BOX (capplet->visual_combo_box), capplet->visual_ats);
+ refresh_combo_box_icons (theme, GTK_COMBO_BOX (capplet->mobility_combo_box), capplet->mobility_ats);
+}
+
+static void screen_changed_cb(GtkWidget* widget, GdkScreen* screen, MateDACapplet* capplet)
+{
+ GtkIconTheme* theme;
+
+ theme = gtk_icon_theme_get_for_screen (screen);
+
+ if (capplet->icon_theme != NULL)
+ {
+ g_signal_handlers_disconnect_by_func (capplet->icon_theme, theme_changed_cb, capplet);
+ }
+
+ g_signal_connect (theme, "changed", G_CALLBACK (theme_changed_cb), capplet);
+ theme_changed_cb (theme, capplet);
+
+ capplet->icon_theme = theme;
+}
+
+static gint generic_item_comp(gconstpointer list_item, gconstpointer command)
+{
+ return (strcmp (((MateDAItem *) list_item)->command, (gchar *) command));
+}
+
+static gint web_item_comp(gconstpointer item, gconstpointer command)
+{
+ MateDAWebItem *web_list_item;
+
+ web_list_item = (MateDAWebItem *) item;
+
+ if (strcmp (web_list_item->generic.command, (gchar *) command) == 0)
+ return 0;
+
+ if (web_list_item->netscape_remote) {
+ if (strcmp (web_list_item->tab_command, (gchar *) command) == 0)
+ return 0;
+
+ if (strcmp (web_list_item->win_command, (gchar *) command) == 0)
+ return 0;
+ }
+
+ return (strcmp (web_list_item->generic.command, (gchar *) command));
+}
+
+static void web_mateconf_changed_cb(MateConfPropertyEditor* peditor, gchar* key, MateConfValue* value, MateDACapplet* capplet)
+{
+ MateConfChangeSet *cs;
+ GError *error = NULL;
+ GList *list_entry;
+
+ /* This function is used to update HTTPS,ABOUT and UNKNOWN handlers, which
+ * should also use the same value as HTTP
+ */
+
+ if (strcmp (key, DEFAULT_APPS_KEY_HTTP_EXEC) == 0) {
+ gchar *short_browser, *pos;
+ const gchar *value_str = mateconf_value_get_string (value);
+
+ cs = mateconf_change_set_new ();
+
+ mateconf_change_set_set (cs, DEFAULT_APPS_KEY_HTTPS_EXEC, value);
+ mateconf_change_set_set (cs, DEFAULT_APPS_KEY_UNKNOWN_EXEC, value);
+ mateconf_change_set_set (cs, DEFAULT_APPS_KEY_ABOUT_EXEC, value);
+ pos = strstr (value_str, " ");
+ if (pos == NULL)
+ short_browser = g_strdup (value_str);
+ else
+ short_browser = g_strndup (value_str, pos - value_str);
+ mateconf_change_set_set_string (cs, DEFAULT_APPS_KEY_BROWSER_EXEC, short_browser);
+ g_free (short_browser);
+
+ list_entry = g_list_find_custom (capplet->web_browsers,
+ value_str,
+ (GCompareFunc) web_item_comp);
+
+ if (list_entry) {
+ MateDAWebItem *item = (MateDAWebItem *) list_entry->data;
+
+ mateconf_change_set_set_bool (cs, DEFAULT_APPS_KEY_BROWSER_NREMOTE, item->netscape_remote);
+ }
+
+ mateconf_client_commit_change_set (capplet->mateconf, cs, TRUE, &error);
+
+ if (error != NULL) {
+ g_warning (_("Error saving configuration: %s"), error->message);
+ g_error_free (error);
+ error = NULL;
+ }
+
+ mateconf_change_set_unref (cs);
+ }
+ else if (strcmp (key, DEFAULT_APPS_KEY_HTTP_NEEDS_TERM) == 0) {
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (capplet->web_browser_terminal_checkbutton),
+ mateconf_value_get_bool (value));
+
+ cs = mateconf_change_set_new ();
+
+ mateconf_change_set_set (cs, DEFAULT_APPS_KEY_HTTPS_NEEDS_TERM, value);
+ mateconf_change_set_set (cs, DEFAULT_APPS_KEY_UNKNOWN_NEEDS_TERM, value);
+ mateconf_change_set_set (cs, DEFAULT_APPS_KEY_ABOUT_NEEDS_TERM, value);
+ mateconf_change_set_set (cs, DEFAULT_APPS_KEY_BROWSER_NEEDS_TERM, value);
+
+ mateconf_client_commit_change_set (capplet->mateconf, cs, TRUE, &error);
+
+ if (error != NULL) {
+ g_warning (_("Error saving configuration: %s"), error->message);
+ g_error_free (error);
+ error = NULL;
+ }
+
+ mateconf_change_set_unref (cs);
+ }
+}
+
+static void web_browser_update_radio_buttons(MateDACapplet* capplet, const gchar* command)
+{
+ GList *entry;
+ gboolean has_net_remote;
+
+ entry = g_list_find_custom (capplet->web_browsers, command, (GCompareFunc) web_item_comp);
+
+ if (entry) {
+ MateDAWebItem *item = (MateDAWebItem *) entry->data;
+
+ has_net_remote = item->netscape_remote;
+
+ if (has_net_remote) {
+ /* disable "toggle" signal emitting, thus preventing calling this function twice */
+ g_signal_handlers_block_matched (capplet->default_radiobutton, G_SIGNAL_MATCH_FUNC, 0,
+ 0, NULL, G_CALLBACK (web_radiobutton_toggled_cb), NULL);
+ g_signal_handlers_block_matched (capplet->new_tab_radiobutton, G_SIGNAL_MATCH_FUNC, 0,
+ 0, NULL, G_CALLBACK (web_radiobutton_toggled_cb), NULL);
+ g_signal_handlers_block_matched (capplet->new_win_radiobutton,G_SIGNAL_MATCH_FUNC, 0,
+ 0, NULL, G_CALLBACK (web_radiobutton_toggled_cb), NULL);
+
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (capplet->default_radiobutton),
+ strcmp (item->generic.command, command) == 0);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (capplet->new_tab_radiobutton),
+ strcmp (item->tab_command, command) == 0);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (capplet->new_win_radiobutton),
+ strcmp (item->win_command, command) == 0);
+
+ g_signal_handlers_unblock_matched (capplet->default_radiobutton, G_SIGNAL_MATCH_FUNC, 0,
+ 0, NULL, G_CALLBACK (web_radiobutton_toggled_cb), NULL);
+ g_signal_handlers_unblock_matched (capplet->new_tab_radiobutton, G_SIGNAL_MATCH_FUNC, 0,
+ 0, NULL, G_CALLBACK (web_radiobutton_toggled_cb), NULL);
+ g_signal_handlers_unblock_matched (capplet->new_win_radiobutton, G_SIGNAL_MATCH_FUNC, 0,
+ 0, NULL, G_CALLBACK (web_radiobutton_toggled_cb), NULL);
+ }
+ }
+ else {
+ has_net_remote = FALSE;
+ }
+
+ gtk_widget_set_sensitive (capplet->default_radiobutton, has_net_remote);
+ gtk_widget_set_sensitive (capplet->new_win_radiobutton, has_net_remote);
+ gtk_widget_set_sensitive (capplet->new_tab_radiobutton, has_net_remote);
+}
+
+static MateConfValue* web_combo_conv_to_widget (MateConfPropertyEditor *peditor, const MateConfValue *value)
+{
+ MateConfValue *ret;
+ GList *entry, *handlers;
+ const gchar *command;
+ gint index;
+ MateDACapplet *capplet;
+
+ g_object_get (G_OBJECT (peditor), "data", &capplet, NULL);
+
+ command = mateconf_value_get_string (value);
+ handlers = capplet->web_browsers;
+
+ if (handlers)
+ {
+ entry = g_list_find_custom (handlers, command, (GCompareFunc) web_item_comp);
+ if (entry)
+ index = g_list_position (handlers, entry);
+ else
+ index = g_list_length (handlers) + 1;
+ }
+ else
+ {
+ /* if the item has no handlers lsit then select the Custom item */
+ index = 1;
+ }
+
+ web_browser_update_radio_buttons (capplet, command);
+
+ ret = mateconf_value_new (MATECONF_VALUE_INT);
+ mateconf_value_set_int (ret, index);
+
+ return ret;
+}
+
+static MateConfValue* web_combo_conv_from_widget (MateConfPropertyEditor *peditor, const MateConfValue *value)
+{
+ MateConfValue *ret;
+ GList *handlers;
+ gint index;
+ MateDAWebItem *item;
+ const gchar *command;
+ MateDACapplet *capplet;
+
+ g_object_get (G_OBJECT (peditor), "data", &capplet, NULL);
+
+ index = mateconf_value_get_int (value);
+ handlers = capplet->web_browsers;
+
+ item = g_list_nth_data (handlers, index);
+
+ ret = mateconf_value_new (MATECONF_VALUE_STRING);
+ if (!item)
+ {
+ /* if item was not found, this is probably the "Custom" item */
+ /* XXX: returning "" as the value here is not ideal, but required to
+ * prevent the combo box from jumping back to the previous value if the
+ * user has selected Custom */
+ mateconf_value_set_string (ret, "");
+ return ret;
+ }
+ else
+ {
+ if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (capplet->new_win_radiobutton)) && item->netscape_remote == TRUE)
+ command = item->win_command;
+ else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (capplet->new_tab_radiobutton)) && item->netscape_remote == TRUE)
+ command = item->tab_command;
+ else
+ command = item->generic.command;
+
+ mateconf_value_set_string (ret, command);
+ return ret;
+ }
+}
+
+static MateConfValue* combo_conv_to_widget (MateConfPropertyEditor *peditor, const MateConfValue *value)
+{
+ MateConfValue *ret;
+ GList *entry, *handlers;
+ const gchar *command;
+ gint index;
+
+ g_object_get (G_OBJECT (peditor), "data", &handlers, NULL);
+
+ command = mateconf_value_get_string (value);
+
+ if (handlers)
+ {
+ entry = g_list_find_custom (handlers, command, (GCompareFunc) generic_item_comp);
+ if (entry)
+ index = g_list_position (handlers, entry);
+ else
+ index = g_list_length (handlers) + 1;
+ }
+ else
+ {
+ /* if the item has no handlers lsit then select the Custom item */
+ index = 1;
+ }
+
+ ret = mateconf_value_new (MATECONF_VALUE_INT);
+ mateconf_value_set_int (ret, index);
+ return ret;
+}
+
+static MateConfValue* combo_conv_from_widget (MateConfPropertyEditor *peditor, const MateConfValue *value)
+{
+ MateConfValue *ret;
+ GList *handlers;
+ gint index;
+ MateDAItem *item;
+
+ g_object_get (G_OBJECT (peditor), "data", &handlers, NULL);
+ index = mateconf_value_get_int (value);
+
+ item = g_list_nth_data (handlers, index);
+ ret = mateconf_value_new (MATECONF_VALUE_STRING);
+
+ if (!item)
+ {
+ /* if item was not found, this is probably the "Custom" item */
+
+ /* XXX: returning "" as the value here is not ideal, but required to
+ * prevent the combo box from jumping back to the previous value if the
+ * user has selected Custom */
+ mateconf_value_set_string (ret, "");
+ return ret;
+ }
+ else
+ {
+ mateconf_value_set_string (ret, item->command);
+ return ret;
+ }
+}
+
+static MateConfValue* combo_conv_from_widget_term_flag (MateConfPropertyEditor *peditor, const MateConfValue *value)
+{
+ MateConfValue *ret;
+ GList *handlers;
+ gint index;
+ MateDATermItem *item;
+
+ g_object_get (G_OBJECT (peditor), "data", &handlers, NULL);
+ index = mateconf_value_get_int (value);
+
+ item = g_list_nth_data (handlers, index);
+ ret = mateconf_value_new (MATECONF_VALUE_STRING);
+
+ if (!item)
+ {
+ /* if item was not found, this is probably the "Custom" item */
+
+ /* XXX: returning "" as the value here is not ideal, but required to
+ * prevent the combo box from jumping back to the previous value if the
+ * user has selected Custom */
+ mateconf_value_set_string (ret, "");
+ return ret;
+ }
+ else
+ {
+ mateconf_value_set_string (ret, item->exec_flag);
+ return ret;
+ }
+}
+
+static MateConfValue* combo_conv_to_widget_term_flag (MateConfPropertyEditor *peditor, const MateConfValue *value)
+{
+ MateConfValue *ret;
+ GtkComboBox *combo;
+
+ combo = GTK_COMBO_BOX (mateconf_property_editor_get_ui_control (peditor));
+
+ ret = mateconf_value_new (MATECONF_VALUE_INT);
+ mateconf_value_set_int (ret, gtk_combo_box_get_active (combo));
+ return ret;
+}
+
+static gboolean is_separator (GtkTreeModel *model, GtkTreeIter *iter, gpointer sep_index)
+{
+ GtkTreePath *path;
+ gboolean result;
+
+ path = gtk_tree_model_get_path (model, iter);
+ result = gtk_tree_path_get_indices (path)[0] == GPOINTER_TO_INT (sep_index);
+ gtk_tree_path_free (path);
+
+ return result;
+}
+
+static void fill_combo_box (GtkIconTheme *theme, GtkComboBox *combo_box, GList *app_list)
+{
+ GList *entry;
+ GtkTreeModel *model;
+ GtkCellRenderer *renderer;
+ GtkTreeIter iter;
+ GdkPixbuf *pixbuf;
+
+ if (theme == NULL) {
+ theme = gtk_icon_theme_get_default ();
+ }
+
+ gtk_combo_box_set_row_separator_func (combo_box, is_separator,
+ GINT_TO_POINTER (g_list_length (app_list)), NULL);
+
+ model = GTK_TREE_MODEL (gtk_list_store_new (2, GDK_TYPE_PIXBUF, G_TYPE_STRING));
+ gtk_combo_box_set_model (combo_box, model);
+
+ renderer = gtk_cell_renderer_pixbuf_new ();
+
+ /* not all cells have a pixbuf, this prevents the combo box to shrink */
+ gtk_cell_renderer_set_fixed_size (renderer, -1, 22);
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), renderer, FALSE);
+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), renderer,
+ "pixbuf", PIXBUF_COL,
+ NULL);
+
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), renderer, TRUE);
+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), renderer,
+ "text", TEXT_COL,
+ NULL);
+
+ for (entry = app_list; entry != NULL; entry = g_list_next (entry)) {
+ MateDAItem *item;
+ item = (MateDAItem *) entry->data;
+
+ pixbuf = gtk_icon_theme_load_icon (theme, item->icon_name, 22, 0, NULL);
+
+ gtk_list_store_append (GTK_LIST_STORE (model), &iter);
+ gtk_list_store_set (GTK_LIST_STORE (model), &iter,
+ PIXBUF_COL, pixbuf,
+ TEXT_COL, item->name,
+ -1);
+
+ item->icon_path = gtk_tree_model_get_string_from_iter (model, &iter);
+
+ if (pixbuf)
+ g_object_unref (pixbuf);
+ }
+
+ gtk_list_store_append (GTK_LIST_STORE (model), &iter);
+ gtk_list_store_set (GTK_LIST_STORE (model), &iter, -1);
+ gtk_list_store_append (GTK_LIST_STORE (model), &iter);
+ gtk_list_store_set (GTK_LIST_STORE (model), &iter,
+ PIXBUF_COL, NULL,
+ TEXT_COL, _("Custom"),
+ -1);
+}
+
+static GtkWidget* _gtk_builder_get_widget (GtkBuilder *builder, const gchar *name)
+{
+ return GTK_WIDGET (gtk_builder_get_object (builder, name));
+}
+
+
+static void show_dialog (MateDACapplet* capplet, const gchar* start_page)
+{
+ GObject *obj;
+ GtkBuilder *builder;
+ guint builder_result;
+
+ capplet->builder = builder = gtk_builder_new ();
+
+ if (g_file_test (MATECC_UI_DIR "/mate-default-applications-properties.ui", G_FILE_TEST_EXISTS) != FALSE) {
+ builder_result = gtk_builder_add_from_file (builder, MATECC_UI_DIR "/mate-default-applications-properties.ui", NULL);
+ }
+ else {
+ builder_result = gtk_builder_add_from_file (builder, "./mate-default-applications-properties.ui", NULL);
+ }
+
+ if (builder_result == 0) {
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
+ _("Could not load the main interface"));
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ _("Please make sure that the applet "
+ "is properly installed"));
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+ exit (EXIT_FAILURE);
+ }
+
+ capplet->window = _gtk_builder_get_widget (builder,"preferred_apps_dialog");
+ g_signal_connect (capplet->window, "response", G_CALLBACK (close_cb), NULL);
+
+ capplet->web_browser_command_entry = _gtk_builder_get_widget (builder, "web_browser_command_entry");
+ capplet->web_browser_command_label = _gtk_builder_get_widget (builder, "web_browser_command_label");
+ capplet->web_browser_terminal_checkbutton = _gtk_builder_get_widget(builder, "web_browser_terminal_checkbutton");
+ capplet->default_radiobutton = _gtk_builder_get_widget (builder, "web_browser_default_radiobutton");
+ capplet->new_win_radiobutton = _gtk_builder_get_widget (builder, "web_browser_new_win_radiobutton");
+ capplet->new_tab_radiobutton = _gtk_builder_get_widget (builder, "web_browser_new_tab_radiobutton");
+
+ capplet->mail_reader_command_entry = _gtk_builder_get_widget (builder, "mail_reader_command_entry");
+ capplet->mail_reader_command_label = _gtk_builder_get_widget (builder, "mail_reader_command_label");
+ capplet->mail_reader_terminal_checkbutton = _gtk_builder_get_widget (builder, "mail_reader_terminal_checkbutton");
+
+ capplet->terminal_command_entry = _gtk_builder_get_widget (builder, "terminal_command_entry");
+ capplet->terminal_command_label = _gtk_builder_get_widget (builder, "terminal_command_label");
+ capplet->terminal_exec_flag_entry = _gtk_builder_get_widget (builder, "terminal_exec_flag_entry");
+ capplet->terminal_exec_flag_label = _gtk_builder_get_widget (builder, "terminal_exec_flag_label");
+
+ capplet->media_player_command_entry = _gtk_builder_get_widget (builder, "media_player_command_entry");
+ capplet->media_player_command_label = _gtk_builder_get_widget (builder, "media_player_command_label");
+ capplet->media_player_terminal_checkbutton = _gtk_builder_get_widget (builder, "media_player_terminal_checkbutton");
+
+ capplet->visual_command_entry = _gtk_builder_get_widget (builder, "visual_command_entry");
+ capplet->visual_command_label = _gtk_builder_get_widget (builder, "visual_command_label");
+ capplet->visual_startup_checkbutton = _gtk_builder_get_widget (builder, "visual_start_checkbutton");
+
+ capplet->mobility_command_entry = _gtk_builder_get_widget (builder, "mobility_command_entry");
+ capplet->mobility_command_label = _gtk_builder_get_widget (builder, "mobility_command_label");
+ capplet->mobility_startup_checkbutton = _gtk_builder_get_widget (builder, "mobility_start_checkbutton");
+
+ capplet->web_combo_box = _gtk_builder_get_widget (builder, "web_browser_combobox");
+ capplet->mail_combo_box = _gtk_builder_get_widget (builder, "mail_reader_combobox");
+ capplet->term_combo_box = _gtk_builder_get_widget (builder, "terminal_combobox");
+ capplet->media_combo_box = _gtk_builder_get_widget (builder, "media_player_combobox");
+ capplet->visual_combo_box = _gtk_builder_get_widget (builder, "visual_combobox");
+ capplet->mobility_combo_box = _gtk_builder_get_widget (builder, "mobility_combobox");
+
+ g_signal_connect (capplet->window, "screen-changed", G_CALLBACK (screen_changed_cb), capplet);
+ screen_changed_cb (capplet->window, gdk_screen_get_default (), capplet);
+
+ fill_combo_box (capplet->icon_theme, GTK_COMBO_BOX (capplet->web_combo_box), capplet->web_browsers);
+ fill_combo_box (capplet->icon_theme, GTK_COMBO_BOX (capplet->mail_combo_box), capplet->mail_readers);
+ fill_combo_box (capplet->icon_theme, GTK_COMBO_BOX (capplet->term_combo_box), capplet->terminals);
+ fill_combo_box (capplet->icon_theme, GTK_COMBO_BOX (capplet->media_combo_box), capplet->media_players);
+ fill_combo_box (capplet->icon_theme, GTK_COMBO_BOX (capplet->visual_combo_box), capplet->visual_ats);
+ fill_combo_box (capplet->icon_theme, GTK_COMBO_BOX (capplet->mobility_combo_box), capplet->mobility_ats);
+
+ g_signal_connect (capplet->web_combo_box, "changed", G_CALLBACK (web_combo_changed_cb), capplet);
+ g_signal_connect (capplet->mail_combo_box, "changed", G_CALLBACK (mail_combo_changed_cb), capplet);
+ g_signal_connect (capplet->term_combo_box, "changed", G_CALLBACK (terminal_combo_changed_cb), capplet);
+ g_signal_connect (capplet->media_combo_box, "changed", G_CALLBACK (media_combo_changed_cb), capplet);
+ g_signal_connect (capplet->visual_combo_box, "changed", G_CALLBACK (visual_combo_changed_cb), capplet);
+ g_signal_connect (capplet->mobility_combo_box, "changed", G_CALLBACK (mobility_combo_changed_cb), capplet);
+
+
+ g_signal_connect (capplet->default_radiobutton, "toggled", G_CALLBACK (web_radiobutton_toggled_cb), capplet);
+ g_signal_connect (capplet->new_win_radiobutton, "toggled", G_CALLBACK (web_radiobutton_toggled_cb), capplet);
+ g_signal_connect (capplet->new_tab_radiobutton, "toggled", G_CALLBACK (web_radiobutton_toggled_cb), capplet);
+
+ /* Setup MateConfPropertyEditors */
+
+ /* Web Browser */
+ mateconf_peditor_new_combo_box (NULL,
+ DEFAULT_APPS_KEY_HTTP_EXEC,
+ capplet->web_combo_box,
+ "conv-from-widget-cb", web_combo_conv_from_widget,
+ "conv-to-widget-cb", web_combo_conv_to_widget,
+ "data", capplet,
+ NULL);
+
+ obj = mateconf_peditor_new_string (NULL,
+ DEFAULT_APPS_KEY_HTTP_EXEC,
+ capplet->web_browser_command_entry,
+ NULL);
+ g_signal_connect (obj, "value-changed", G_CALLBACK (web_mateconf_changed_cb), capplet);
+
+ obj = mateconf_peditor_new_boolean (NULL,
+ DEFAULT_APPS_KEY_HTTP_NEEDS_TERM,
+ capplet->web_browser_terminal_checkbutton,
+ NULL);
+ g_signal_connect (obj, "value-changed", G_CALLBACK (web_mateconf_changed_cb), capplet);
+
+ /* Mailer */
+ mateconf_peditor_new_combo_box (NULL,
+ DEFAULT_APPS_KEY_MAILER_EXEC,
+ capplet->mail_combo_box,
+ "conv-from-widget-cb", combo_conv_from_widget,
+ "conv-to-widget-cb", combo_conv_to_widget,
+ "data", capplet->mail_readers,
+ NULL);
+
+ mateconf_peditor_new_string (NULL,
+ DEFAULT_APPS_KEY_MAILER_EXEC,
+ capplet->mail_reader_command_entry,
+ NULL);
+
+ mateconf_peditor_new_boolean (NULL,
+ DEFAULT_APPS_KEY_MAILER_NEEDS_TERM,
+ capplet->mail_reader_terminal_checkbutton,
+ NULL);
+
+ /* Media player */
+ mateconf_peditor_new_combo_box (NULL,
+ DEFAULT_APPS_KEY_MEDIA_EXEC,
+ capplet->media_combo_box,
+ "conv-from-widget-cb", combo_conv_from_widget,
+ "conv-to-widget-cb", combo_conv_to_widget,
+ "data", capplet->media_players,
+ NULL);
+
+ mateconf_peditor_new_string (NULL,
+ DEFAULT_APPS_KEY_MEDIA_EXEC,
+ capplet->media_player_command_entry,
+ NULL);
+
+ mateconf_peditor_new_boolean (NULL,
+ DEFAULT_APPS_KEY_MEDIA_NEEDS_TERM,
+ capplet->media_player_terminal_checkbutton,
+ NULL);
+
+ /* Terminal */
+ mateconf_peditor_new_combo_box (NULL,
+ DEFAULT_APPS_KEY_TERMINAL_EXEC,
+ capplet->term_combo_box,
+ "conv-from-widget-cb", combo_conv_from_widget,
+ "conv-to-widget-cb", combo_conv_to_widget,
+ "data", capplet->terminals,
+ NULL);
+
+ mateconf_peditor_new_combo_box (NULL,
+ DEFAULT_APPS_KEY_TERMINAL_EXEC_ARG,
+ capplet->term_combo_box,
+ "conv-from-widget-cb", combo_conv_from_widget_term_flag,
+ "conv-to-widget-cb", combo_conv_to_widget_term_flag,
+ "data", capplet->terminals,
+ NULL);
+
+ mateconf_peditor_new_string (NULL,
+ DEFAULT_APPS_KEY_TERMINAL_EXEC,
+ capplet->terminal_command_entry,
+ NULL);
+ mateconf_peditor_new_string (NULL,
+ DEFAULT_APPS_KEY_TERMINAL_EXEC_ARG,
+ capplet->terminal_exec_flag_entry,
+ NULL);
+
+
+ /* Visual */
+ mateconf_peditor_new_combo_box (NULL,
+ DEFAULT_APPS_KEY_VISUAL_EXEC,
+ capplet->visual_combo_box,
+ "conv-from-widget-cb", combo_conv_from_widget,
+ "conv-to-widget-cb", combo_conv_to_widget,
+ "data", capplet->visual_ats,
+ NULL);
+
+ mateconf_peditor_new_string (NULL,
+ DEFAULT_APPS_KEY_VISUAL_EXEC,
+ capplet->visual_command_entry,
+ NULL);
+
+ mateconf_peditor_new_boolean (NULL,
+ DEFAULT_APPS_KEY_VISUAL_STARTUP,
+ capplet->visual_startup_checkbutton,
+ NULL);
+
+
+ /* Mobility */
+ mateconf_peditor_new_combo_box (NULL,
+ DEFAULT_APPS_KEY_MOBILITY_EXEC,
+ capplet->mobility_combo_box,
+ "conv-from-widget-cb", combo_conv_from_widget,
+ "conv-to-widget-cb", combo_conv_to_widget,
+ "data", capplet->mobility_ats,
+ NULL);
+
+ mateconf_peditor_new_string (NULL,
+ DEFAULT_APPS_KEY_MOBILITY_EXEC,
+ capplet->mobility_command_entry,
+ NULL);
+
+ mateconf_peditor_new_boolean (NULL,
+ DEFAULT_APPS_KEY_MOBILITY_STARTUP,
+ capplet->mobility_startup_checkbutton,
+ NULL);
+
+ gtk_window_set_icon_name (GTK_WINDOW (capplet->window),
+ "preferences-desktop-default-applications");
+
+ if (start_page != NULL) {
+ gchar *page_name;
+ GtkWidget *w;
+
+ page_name = g_strconcat (start_page, "_vbox", NULL);
+
+ w = _gtk_builder_get_widget (builder, page_name);
+ if (w != NULL) {
+ GtkNotebook *nb;
+ gint pindex;
+
+ nb = GTK_NOTEBOOK (_gtk_builder_get_widget (builder,
+ "preferred_apps_notebook"));
+ pindex = gtk_notebook_page_num (nb, w);
+ if (pindex != -1)
+ gtk_notebook_set_current_page (nb, pindex);
+ }
+ g_free (page_name);
+ }
+
+ gtk_widget_show (capplet->window);
+}
+
+int main (int argc, char** argv)
+{
+ MateDACapplet* capplet;
+
+ gchar* start_page = NULL;
+
+ GOptionContext* context;
+ GOptionEntry option_entries[] = {
+ {
+ "show-page",
+ 'p',
+ G_OPTION_FLAG_IN_MAIN,
+ G_OPTION_ARG_STRING,
+ &start_page,
+ /* TRANSLATORS: don't translate the terms in brackets */
+ N_("Specify the name of the page to show (internet|multimedia|system|a11y)"),
+ N_("page")
+ },
+ {NULL}
+ };
+
+ context = g_option_context_new(_("- MATE Default Applications"));
+ g_option_context_add_main_entries (context, option_entries, GETTEXT_PACKAGE);
+
+ capplet_init (context, &argc, &argv);
+
+ capplet = g_new0(MateDACapplet, 1);
+ capplet->mateconf = mateconf_client_get_default();
+ mateconf_client_add_dir(capplet->mateconf, "/desktop/mate/url-handlers", MATECONF_CLIENT_PRELOAD_RECURSIVE, NULL);
+ mateconf_client_add_dir(capplet->mateconf, "/desktop/mate/applications", MATECONF_CLIENT_PRELOAD_RECURSIVE, NULL);
+
+ mate_da_xml_load_list(capplet);
+
+ show_dialog(capplet, start_page);
+ g_free(start_page);
+
+ gtk_main();
+
+ g_object_unref(capplet->mateconf);
+
+ mate_da_xml_free(capplet);
+
+ return 0;
+}
diff --git a/capplets/default-applications/mate-da-capplet.h b/capplets/default-applications/mate-da-capplet.h
new file mode 100644
index 00000000..3ce72955
--- /dev/null
+++ b/capplets/default-applications/mate-da-capplet.h
@@ -0,0 +1,139 @@
+/*
+ * Authors: Luca Cavalli <[email protected]>
+ *
+ * Copyright 2005-2006 Luca Cavalli
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef _MATE_DA_CAPPLET_H_
+#define _MATE_DA_CAPPLET_H_
+
+#include <gtk/gtk.h>
+#include <mateconf/mateconf-client.h>
+
+// Set http, https, about, and unknown keys to the chosen web browser.
+#define DEFAULT_APPS_KEY_HTTP_PATH "/desktop/mate/url-handlers/http"
+#define DEFAULT_APPS_KEY_HTTP_NEEDS_TERM DEFAULT_APPS_KEY_HTTP_PATH"/needs_terminal"
+#define DEFAULT_APPS_KEY_HTTP_EXEC DEFAULT_APPS_KEY_HTTP_PATH"/command"
+
+#define DEFAULT_APPS_KEY_HTTPS_PATH "/desktop/mate/url-handlers/https"
+#define DEFAULT_APPS_KEY_HTTPS_NEEDS_TERM DEFAULT_APPS_KEY_HTTPS_PATH"/needs_terminal"
+#define DEFAULT_APPS_KEY_HTTPS_EXEC DEFAULT_APPS_KEY_HTTPS_PATH"/command"
+
+// While mate-vfs2 does not use the "unknown" key, several widespread apps like htmlview
+// have read it for the past few years. Setting it should not hurt.
+#define DEFAULT_APPS_KEY_UNKNOWN_PATH "/desktop/mate/url-handlers/unknown"
+#define DEFAULT_APPS_KEY_UNKNOWN_NEEDS_TERM DEFAULT_APPS_KEY_UNKNOWN_PATH"/needs_terminal"
+#define DEFAULT_APPS_KEY_UNKNOWN_EXEC DEFAULT_APPS_KEY_UNKNOWN_PATH"/command"
+
+// about:blank and other about: URI's are commonly used by browsers too
+#define DEFAULT_APPS_KEY_ABOUT_PATH "/desktop/mate/url-handlers/about"
+#define DEFAULT_APPS_KEY_ABOUT_NEEDS_TERM DEFAULT_APPS_KEY_ABOUT_PATH"/needs_terminal"
+#define DEFAULT_APPS_KEY_ABOUT_EXEC DEFAULT_APPS_KEY_ABOUT_PATH"/command"
+
+#define DEFAULT_APPS_KEY_MAILER_PATH "/desktop/mate/url-handlers/mailto"
+#define DEFAULT_APPS_KEY_MAILER_NEEDS_TERM DEFAULT_APPS_KEY_MAILER_PATH"/needs_terminal"
+#define DEFAULT_APPS_KEY_MAILER_EXEC DEFAULT_APPS_KEY_MAILER_PATH"/command"
+
+#define DEFAULT_APPS_KEY_BROWSER_PATH "/desktop/mate/applications/browser"
+#define DEFAULT_APPS_KEY_BROWSER_EXEC DEFAULT_APPS_KEY_BROWSER_PATH"/exec"
+#define DEFAULT_APPS_KEY_BROWSER_NEEDS_TERM DEFAULT_APPS_KEY_BROWSER_PATH"/needs_term"
+#define DEFAULT_APPS_KEY_BROWSER_NREMOTE DEFAULT_APPS_KEY_BROWSER_PATH"/nremote"
+
+#define DEFAULT_APPS_KEY_TERMINAL_PATH "/desktop/mate/applications/terminal"
+#define DEFAULT_APPS_KEY_TERMINAL_EXEC_ARG DEFAULT_APPS_KEY_TERMINAL_PATH"/exec_arg"
+#define DEFAULT_APPS_KEY_TERMINAL_EXEC DEFAULT_APPS_KEY_TERMINAL_PATH"/exec"
+
+#define DEFAULT_APPS_KEY_MEDIA_PATH "/desktop/mate/applications/media"
+#define DEFAULT_APPS_KEY_MEDIA_EXEC DEFAULT_APPS_KEY_MEDIA_PATH"/exec"
+#define DEFAULT_APPS_KEY_MEDIA_NEEDS_TERM DEFAULT_APPS_KEY_MEDIA_PATH"/needs_term"
+
+#define DEFAULT_APPS_KEY_VISUAL_PATH "/desktop/mate/applications/at/visual"
+#define DEFAULT_APPS_KEY_VISUAL_EXEC DEFAULT_APPS_KEY_VISUAL_PATH"/exec"
+#define DEFAULT_APPS_KEY_VISUAL_STARTUP DEFAULT_APPS_KEY_VISUAL_PATH"/startup"
+
+#define DEFAULT_APPS_KEY_MOBILITY_PATH "/desktop/mate/applications/at/mobility"
+#define DEFAULT_APPS_KEY_MOBILITY_EXEC DEFAULT_APPS_KEY_MOBILITY_PATH"/exec"
+#define DEFAULT_APPS_KEY_MOBILITY_STARTUP DEFAULT_APPS_KEY_MOBILITY_PATH"/startup"
+
+typedef struct _MateDACapplet MateDACapplet;
+
+struct _MateDACapplet {
+ GtkBuilder* builder;
+
+ GtkIconTheme* icon_theme;
+
+ GtkWidget* window;
+
+ GtkWidget* web_combo_box;
+ GtkWidget* mail_combo_box;
+ GtkWidget* term_combo_box;
+ GtkWidget* media_combo_box;
+ GtkWidget* visual_combo_box;
+ GtkWidget* mobility_combo_box;
+ /* Para el File Manager */
+ /*GtkWidget* filemanager_combo_box;*/
+
+ GtkWidget* web_browser_command_entry;
+ GtkWidget* web_browser_command_label;
+ GtkWidget* web_browser_terminal_checkbutton;
+ GtkWidget* default_radiobutton;
+ GtkWidget* new_win_radiobutton;
+ GtkWidget* new_tab_radiobutton;
+
+ /* Para el File Manager */
+ /*GtkWidget* file_manager_command_entry;
+ GtkWidget* file_manager_command_label;
+ GtkWidget* file_manager_terminal_checkbutton;
+ GtkWidget* file_manager_default_radiobutton;
+ GtkWidget* file_manager_new_win_radiobutton;
+ GtkWidget* file_manager_new_tab_radiobutton;*/
+
+
+ GtkWidget* mail_reader_command_entry;
+ GtkWidget* mail_reader_command_label;
+ GtkWidget* mail_reader_terminal_checkbutton;
+
+ GtkWidget* terminal_command_entry;
+ GtkWidget* terminal_command_label;
+ GtkWidget* terminal_exec_flag_entry;
+ GtkWidget* terminal_exec_flag_label;
+
+ GtkWidget* media_player_command_entry;
+ GtkWidget* media_player_command_label;
+ GtkWidget* media_player_terminal_checkbutton;
+
+ GtkWidget* visual_command_entry;
+ GtkWidget* visual_command_label;
+ GtkWidget* visual_startup_checkbutton;
+
+ GtkWidget* mobility_command_entry;
+ GtkWidget* mobility_command_label;
+ GtkWidget* mobility_startup_checkbutton;
+
+ MateConfClient* mateconf;
+
+ GList* web_browsers;
+ GList* mail_readers;
+ GList* terminals;
+ GList* media_players;
+ GList* visual_ats;
+ GList* mobility_ats;
+ /* Para el File Manager */
+ /*GList* file_managers;*/
+};
+
+#endif
diff --git a/capplets/default-applications/mate-da-item.c b/capplets/default-applications/mate-da-item.c
new file mode 100644
index 00000000..06bda549
--- /dev/null
+++ b/capplets/default-applications/mate-da-item.c
@@ -0,0 +1,148 @@
+/*
+ * Authors: Luca Cavalli <[email protected]>
+ *
+ * Copyright 2005-2006 Luca Cavalli
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "mate-da-capplet.h"
+#include "mate-da-item.h"
+
+MateDAWebItem*
+mate_da_web_item_new (void)
+{
+ MateDAWebItem *item = NULL;
+
+ item = g_new0 (MateDAWebItem, 1);
+
+ return item;
+}
+
+MateDASimpleItem*
+mate_da_simple_item_new (void)
+{
+ MateDASimpleItem *item = NULL;
+
+ item = g_new0 (MateDASimpleItem, 1);
+
+ return item;
+}
+
+MateDATermItem*
+mate_da_term_item_new (void)
+{
+ MateDATermItem *item = NULL;
+
+ item = g_new0 (MateDATermItem, 1);
+
+ return item;
+}
+
+MateDAVisualItem*
+mate_da_visual_item_new (void)
+{
+ MateDAVisualItem *item = NULL;
+
+ item = g_new0 (MateDAVisualItem, 1);
+
+ return item;
+}
+
+MateDAMobilityItem*
+mate_da_mobility_item_new (void)
+{
+ MateDAMobilityItem *item = NULL;
+
+ item = g_new0 (MateDAMobilityItem, 1);
+
+ return item;
+}
+
+void
+mate_da_web_item_free (MateDAWebItem *item)
+{
+ g_return_if_fail (item != NULL);
+
+ g_free (item->generic.name);
+ g_free (item->generic.executable);
+ g_free (item->generic.command);
+ g_free (item->generic.icon_name);
+ g_free (item->generic.icon_path);
+
+ g_free (item->tab_command);
+ g_free (item->win_command);
+
+ g_free (item);
+}
+
+void
+mate_da_simple_item_free (MateDASimpleItem *item)
+{
+ g_return_if_fail (item != NULL);
+
+ g_free (item->generic.name);
+ g_free (item->generic.executable);
+ g_free (item->generic.command);
+ g_free (item->generic.icon_name);
+ g_free (item->generic.icon_path);
+
+ g_free (item);
+}
+
+void
+mate_da_term_item_free (MateDATermItem *item)
+{
+ g_return_if_fail (item != NULL);
+
+ g_free (item->generic.name);
+ g_free (item->generic.executable);
+ g_free (item->generic.command);
+ g_free (item->generic.icon_name);
+ g_free (item->generic.icon_path);
+
+ g_free (item->exec_flag);
+
+ g_free (item);
+}
+
+void
+mate_da_visual_item_free (MateDAVisualItem *item)
+{
+ g_return_if_fail (item != NULL);
+
+ g_free (item->generic.name);
+ g_free (item->generic.executable);
+ g_free (item->generic.command);
+ g_free (item->generic.icon_name);
+ g_free (item->generic.icon_path);
+
+ g_free (item);
+}
+
+void
+mate_da_mobility_item_free (MateDAMobilityItem *item)
+{
+ g_return_if_fail (item != NULL);
+
+ g_free (item->generic.name);
+ g_free (item->generic.executable);
+ g_free (item->generic.command);
+ g_free (item->generic.icon_name);
+ g_free (item->generic.icon_path);
+
+ g_free (item);
+}
+
diff --git a/capplets/default-applications/mate-da-item.h b/capplets/default-applications/mate-da-item.h
new file mode 100644
index 00000000..81223f4e
--- /dev/null
+++ b/capplets/default-applications/mate-da-item.h
@@ -0,0 +1,81 @@
+/*
+ * Authors: Luca Cavalli <[email protected]>
+ *
+ * Copyright 2005-2006 Luca Cavalli
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef _MATE_DA_ITEM_H_
+#define _MATE_DA_ITEM_H_
+
+#include <glib.h>
+
+typedef struct _MateDAItem MateDAItem;
+
+typedef struct _MateDAWebItem MateDAWebItem;
+typedef struct _MateDATermItem MateDATermItem;
+typedef struct _MateDASimpleItem MateDASimpleItem;
+typedef struct _MateDAVisualItem MateDAVisualItem;
+typedef struct _MateDAMobilityItem MateDAMobilityItem;
+
+struct _MateDAItem {
+ gchar *name;
+ gchar *executable;
+ gchar *command;
+ gchar *icon_name;
+ gchar *icon_path;
+};
+
+struct _MateDAWebItem {
+ MateDAItem generic;
+ gboolean run_in_terminal;
+ gboolean netscape_remote;
+ gchar *tab_command;
+ gchar *win_command;
+};
+
+struct _MateDASimpleItem {
+ MateDAItem generic;
+ gboolean run_in_terminal;
+};
+
+struct _MateDATermItem {
+ MateDAItem generic;
+ gchar *exec_flag;
+};
+
+struct _MateDAVisualItem {
+ MateDAItem generic;
+ gboolean run_at_startup;
+};
+
+struct _MateDAMobilityItem {
+ MateDAItem generic;
+ gboolean run_at_startup;
+};
+
+MateDAWebItem* mate_da_web_item_new (void);
+MateDATermItem* mate_da_term_item_new (void);
+MateDASimpleItem* mate_da_simple_item_new (void);
+MateDAVisualItem* mate_da_visual_item_new (void);
+MateDAMobilityItem* mate_da_mobility_item_new (void);
+void mate_da_web_item_free (MateDAWebItem *item);
+void mate_da_term_item_free (MateDATermItem *item);
+void mate_da_simple_item_free (MateDASimpleItem *item);
+void mate_da_visual_item_free (MateDAVisualItem *item);
+void mate_da_mobility_item_free (MateDAMobilityItem *item);
+
+#endif
diff --git a/capplets/default-applications/mate-da-xml.c b/capplets/default-applications/mate-da-xml.c
new file mode 100644
index 00000000..288495c7
--- /dev/null
+++ b/capplets/default-applications/mate-da-xml.c
@@ -0,0 +1,327 @@
+/*
+ * Authors: Luca Cavalli <[email protected]>
+ *
+ * Copyright 2005-2006 Luca Cavalli
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include <string.h>
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <libxml/parser.h>
+
+#include "mate-da-capplet.h"
+#include "mate-da-xml.h"
+#include "mate-da-item.h"
+
+
+static gboolean
+mate_da_xml_get_bool (const xmlNode *parent, const gchar *val_name)
+{
+ xmlNode *element;
+ gboolean ret_val = FALSE;
+ xmlChar *xml_val_name;
+ gint len;
+
+ g_return_val_if_fail (parent != NULL, FALSE);
+ g_return_val_if_fail (parent->children != NULL, ret_val);
+ g_return_val_if_fail (val_name != NULL, FALSE);
+
+ xml_val_name = xmlCharStrdup (val_name);
+ len = xmlStrlen (xml_val_name);
+
+ for (element = parent->children; element != NULL; element = element->next) {
+ if (!xmlStrncmp (element->name, xml_val_name, len)) {
+ xmlChar *cont = xmlNodeGetContent (element);
+
+ if (!xmlStrcasecmp (cont, "true") || !xmlStrcasecmp (cont, "1"))
+ ret_val = TRUE;
+ else
+ ret_val = FALSE;
+
+ xmlFree (cont);
+ }
+ }
+
+ xmlFree (xml_val_name);
+ return ret_val;
+}
+
+static gchar*
+mate_da_xml_get_string (const xmlNode *parent, const gchar *val_name)
+{
+ const gchar * const *sys_langs;
+ xmlChar *node_lang;
+ xmlNode *element;
+ gchar *ret_val = NULL;
+ xmlChar *xml_val_name;
+ gint len;
+ gint i;
+
+ g_return_val_if_fail (parent != NULL, ret_val);
+ g_return_val_if_fail (parent->children != NULL, ret_val);
+ g_return_val_if_fail (val_name != NULL, ret_val);
+
+#if GLIB_CHECK_VERSION (2, 6, 0)
+ sys_langs = g_get_language_names ();
+#endif
+
+ xml_val_name = xmlCharStrdup (val_name);
+ len = xmlStrlen (xml_val_name);
+
+ for (element = parent->children; element != NULL; element = element->next) {
+ if (!xmlStrncmp (element->name, xml_val_name, len)) {
+ node_lang = xmlNodeGetLang (element);
+
+ if (node_lang == NULL) {
+ ret_val = (gchar *) xmlNodeGetContent (element);
+ }
+ else {
+ for (i = 0; sys_langs[i] != NULL; i++) {
+ if (!strcmp (sys_langs[i], node_lang)) {
+ ret_val = (gchar *) xmlNodeGetContent (element);
+ /* since sys_langs is sorted from most desirable to
+ * least desirable, exit at first match
+ */
+ break;
+ }
+ }
+ }
+ xmlFree (node_lang);
+ }
+ }
+
+ xmlFree (xml_val_name);
+ return ret_val;
+}
+
+static gboolean
+is_executable_valid (gchar *executable)
+{
+ gchar *path;
+
+ path = g_find_program_in_path (executable);
+
+ if (path) {
+ g_free (path);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+mate_da_xml_load_xml (MateDACapplet *capplet, const gchar * filename)
+{
+ xmlDoc *xml_doc;
+ xmlNode *root, *section, *element;
+ gchar *executable;
+ MateDAWebItem *web_item;
+ MateDASimpleItem *mail_item;
+ MateDASimpleItem *media_item;
+ MateDATermItem *term_item;
+ MateDAVisualItem *visual_item;
+ MateDAMobilityItem *mobility_item;
+
+ xml_doc = xmlParseFile (filename);
+
+ if (!xml_doc)
+ return;
+
+ root = xmlDocGetRootElement (xml_doc);
+
+ for (section = root->children; section != NULL; section = section->next) {
+ if (!xmlStrncmp (section->name, "web-browsers", 12)) {
+ for (element = section->children; element != NULL; element = element->next) {
+ if (!xmlStrncmp (element->name, "web-browser", 11)) {
+ executable = mate_da_xml_get_string (element, "executable");
+ if (is_executable_valid (executable)) {
+ web_item = mate_da_web_item_new ();
+
+ web_item->generic.name = mate_da_xml_get_string (element, "name");
+ web_item->generic.executable = executable;
+ web_item->generic.command = mate_da_xml_get_string (element, "command");
+ web_item->generic.icon_name = mate_da_xml_get_string (element, "icon-name");
+
+ web_item->run_in_terminal = mate_da_xml_get_bool (element, "run-in-terminal");
+ web_item->netscape_remote = mate_da_xml_get_bool (element, "netscape-remote");
+ if (web_item->netscape_remote) {
+ web_item->tab_command = mate_da_xml_get_string (element, "tab-command");
+ web_item->win_command = mate_da_xml_get_string (element, "win-command");
+ }
+
+ capplet->web_browsers = g_list_append (capplet->web_browsers, web_item);
+ }
+ else
+ g_free (executable);
+ }
+ }
+ }
+ else if (!xmlStrncmp (section->name, "mail-readers", 12)) {
+ for (element = section->children; element != NULL; element = element->next) {
+ if (!xmlStrncmp (element->name, "mail-reader", 11)) {
+ executable = mate_da_xml_get_string (element, "executable");
+ if (is_executable_valid (executable)) {
+ mail_item = mate_da_simple_item_new ();
+
+ mail_item->generic.name = mate_da_xml_get_string (element, "name");
+ mail_item->generic.executable = executable;
+ mail_item->generic.command = mate_da_xml_get_string (element, "command");
+ mail_item->generic.icon_name = mate_da_xml_get_string (element, "icon-name");
+
+ mail_item->run_in_terminal = mate_da_xml_get_bool (element, "run-in-terminal");
+
+ capplet->mail_readers = g_list_append (capplet->mail_readers, mail_item);
+ }
+ else
+ g_free (executable);
+ }
+ }
+ }
+ else if (!xmlStrncmp (section->name, "terminals", 9)) {
+ for (element = section->children; element != NULL; element = element->next) {
+ if (!xmlStrncmp (element->name, "terminal", 8)) {
+ executable = mate_da_xml_get_string (element, "executable");
+ if (is_executable_valid (executable)) {
+ term_item = mate_da_term_item_new ();
+
+ term_item->generic.name = mate_da_xml_get_string (element, "name");
+ term_item->generic.executable = executable;
+ term_item->generic.command = mate_da_xml_get_string (element, "command");
+ term_item->generic.icon_name = mate_da_xml_get_string (element, "icon-name");
+
+ term_item->exec_flag = mate_da_xml_get_string (element, "exec-flag");
+
+ capplet->terminals = g_list_append (capplet->terminals, term_item);
+ }
+ else
+ g_free (executable);
+ }
+ }
+ }
+ else if (!xmlStrncmp (section->name, "media-players", 13)) {
+ for (element = section->children; element != NULL; element = element->next) {
+ if (!xmlStrncmp (element->name, "media-player", 12)) {
+ executable = mate_da_xml_get_string (element, "executable");
+ if (is_executable_valid (executable)) {
+ media_item = mate_da_simple_item_new ();
+
+ media_item->generic.name = mate_da_xml_get_string (element, "name");
+ media_item->generic.executable = executable;
+ media_item->generic.command = mate_da_xml_get_string (element, "command");
+ media_item->generic.icon_name = mate_da_xml_get_string (element, "icon-name");
+
+ media_item->run_in_terminal = mate_da_xml_get_bool (element, "run-in-terminal");
+
+ capplet->media_players = g_list_append (capplet->media_players, media_item);
+ }
+ else
+ g_free (executable);
+ }
+ }
+ }
+ else if (!xmlStrncmp (section->name, "a11y-visual", 11)) {
+ for (element = section->children; element != NULL; element = element->next) {
+ if (!xmlStrncmp (element->name, "visual", 6)) {
+ executable = mate_da_xml_get_string (element,"executable");
+ if (is_executable_valid (executable)) {
+ visual_item = mate_da_visual_item_new ();
+
+ visual_item->generic.name = mate_da_xml_get_string (element, "name");
+ visual_item->generic.executable = executable;
+ visual_item->generic.command = mate_da_xml_get_string (element, "command");
+ visual_item->generic.icon_name = mate_da_xml_get_string (element, "icon-name");
+
+ visual_item->run_at_startup = mate_da_xml_get_bool (element, "run-at-startup");
+
+ capplet->visual_ats = g_list_append (capplet->visual_ats, visual_item);
+ }
+ else
+ g_free (executable);
+ }
+ }
+ }
+ else if (!xmlStrncmp (section->name, "a11y-mobility", 13)) {
+ for (element = section->children; element != NULL; element = element->next) {
+ if (!xmlStrncmp (element->name, "mobility", 8)) {
+ executable = mate_da_xml_get_string (element,"executable");
+ if (is_executable_valid (executable)) {
+ mobility_item = mate_da_mobility_item_new ();
+
+ mobility_item->generic.name = mate_da_xml_get_string (element, "name");
+ mobility_item->generic.executable = executable;
+ mobility_item->generic.command = mate_da_xml_get_string (element, "command");
+ mobility_item->generic.icon_name = mate_da_xml_get_string (element, "icon-name");
+
+ mobility_item->run_at_startup = mate_da_xml_get_bool (element, "run-at-startup");
+
+ capplet->mobility_ats = g_list_append (capplet->mobility_ats, mobility_item);
+ }
+ else
+ g_free (executable);
+ }
+ }
+ }
+ }
+
+ xmlFreeDoc (xml_doc);
+}
+
+void mate_da_xml_load_list(MateDACapplet* capplet)
+{
+ GDir* app_dir = g_dir_open(MATECC_APPS_DIR, 0, NULL);
+
+ if (app_dir != NULL)
+ {
+ const gchar* extra_file;
+ gchar* filename;
+
+ while ((extra_file = g_dir_read_name(app_dir)) != NULL)
+ {
+ filename = g_build_filename(MATECC_APPS_DIR, extra_file, NULL);
+
+ if (g_str_has_suffix(filename, ".xml"))
+ {
+ mate_da_xml_load_xml(capplet, filename);
+ }
+
+ g_free(filename);
+ }
+
+ g_dir_close(app_dir);
+ }
+}
+
+void
+mate_da_xml_free (MateDACapplet *capplet)
+{
+ g_list_foreach (capplet->web_browsers, (GFunc) mate_da_web_item_free, NULL);
+ g_list_foreach (capplet->mail_readers, (GFunc) mate_da_simple_item_free, NULL);
+ g_list_foreach (capplet->terminals, (GFunc) mate_da_term_item_free, NULL);
+ g_list_foreach (capplet->media_players, (GFunc) mate_da_simple_item_free, NULL);
+ g_list_foreach (capplet->visual_ats, (GFunc) mate_da_visual_item_free, NULL);
+ g_list_foreach (capplet->mobility_ats, (GFunc) mate_da_mobility_item_free, NULL);
+
+ g_list_free (capplet->web_browsers);
+ g_list_free (capplet->mail_readers);
+ g_list_free (capplet->terminals);
+ g_list_free (capplet->media_players);
+ g_list_free (capplet->visual_ats);
+ g_list_free (capplet->mobility_ats);
+
+ g_object_unref (capplet->builder);
+ g_free (capplet);
+}
diff --git a/capplets/default-applications/mate-da-xml.h b/capplets/default-applications/mate-da-xml.h
new file mode 100644
index 00000000..b209355c
--- /dev/null
+++ b/capplets/default-applications/mate-da-xml.h
@@ -0,0 +1,27 @@
+/*
+ * Authors: Luca Cavalli <[email protected]>
+ *
+ * Copyright 2005-2006 Luca Cavalli
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef _MATE_DA_XML_H_
+#define _MATE_DA_XML_H_
+
+void mate_da_xml_load_list (MateDACapplet *capplet);
+void mate_da_xml_free (MateDACapplet *capplet);
+
+#endif
diff --git a/capplets/default-applications/mate-default-applications-properties.ui b/capplets/default-applications/mate-default-applications-properties.ui
new file mode 100644
index 00000000..4edc2968
--- /dev/null
+++ b/capplets/default-applications/mate-default-applications-properties.ui
@@ -0,0 +1,1518 @@
+<?xml version="1.0"?>
+<interface>
+ <requires lib="gtk+" version="2.16"/>
+ <!-- interface-naming-policy toplevel-contextual -->
+ <object class="GtkDialog" id="preferred_apps_dialog">
+ <property name="border_width">5</property>
+ <property name="title" translatable="yes">Preferred Applications</property>
+ <property name="resizable">False</property>
+ <property name="type_hint">dialog</property>
+ <property name="has_separator">False</property>
+ <child internal-child="vbox">
+ <object class="GtkVBox" id="dialog-vbox">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkNotebook" id="preferred_apps_notebook">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="border_width">5</property>
+ <child>
+ <object class="GtkVBox" id="internet_vbox">
+ <property name="visible">True</property>
+ <property name="border_width">12</property>
+ <property name="spacing">18</property>
+ <child>
+ <object class="GtkVBox" id="web_browser_vbox">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="web_browser_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Web Browser</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="web_browser_hbox">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkImage" id="web_browser_image">
+ <property name="visible">True</property>
+ <property name="yalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="web_browser_options_vbox">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkComboBox" id="web_browser_combobox">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkTable" id="web_browser_options_table">
+ <property name="visible">True</property>
+ <property name="n_rows">4</property>
+ <property name="n_columns">3</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkEntry" id="web_browser_command_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip_text" translatable="yes">All %s occurrences will be replaced with actual link</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="web_browser_terminal_checkbutton">
+ <property name="label" translatable="yes">Run in t_erminal</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="web_browser_default_radiobutton">
+ <property name="label" translatable="yes">Open link with web browser _default</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="right_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="web_browser_new_tab_radiobutton">
+ <property name="label" translatable="yes">Open link in new _tab</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">web_browser_default_radiobutton</property>
+ </object>
+ <packing>
+ <property name="right_attach">3</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="web_browser_new_win_radiobutton">
+ <property name="label" translatable="yes">Open link in new _window</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">web_browser_default_radiobutton</property>
+ </object>
+ <packing>
+ <property name="right_attach">3</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="web_browser_command_label">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">C_ommand:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">web_browser_command_entry</property>
+ </object>
+ <packing>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="mail_reader_vbox">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="mail_reader_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Mail Reader</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="mail_reader_hbox">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkImage" id="mail_reader_image">
+ <property name="visible">True</property>
+ <property name="yalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="mail_reader_options_vbox">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkComboBox" id="mail_reader_combobox">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkTable" id="mail_reader_options_table">
+ <property name="visible">True</property>
+ <property name="n_columns">3</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="mail_reader_command_label">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Co_mmand:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">mail_reader_command_entry</property>
+ </object>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="mail_reader_command_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip_text" translatable="yes">All %s occurrences will be replaced with actual link</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="mail_reader_terminal_checkbutton">
+ <property name="label" translatable="yes">Run in t_erminal</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="messenger_vbox">
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="messenger_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Instant Messenger</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="messenger_hbox">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkImage" id="messenger_image">
+ <property name="visible">True</property>
+ <property name="yalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="messenger_options_vbox">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkComboBox" id="messenger_combobox">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkTable" id="messenger_options_table">
+ <property name="visible">True</property>
+ <property name="n_columns">3</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="messenger_command_label">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Co_mmand:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">messenger_command_entry</property>
+ </object>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="messenger_command_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip_text" translatable="yes">All %s occurrences will be replaced with actual link</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="messenger_terminal_checkbutton">
+ <property name="label" translatable="yes">Run in t_erminal</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="internet_apps_label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Internet</property>
+ </object>
+ <packing>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="multimedia_vbox">
+ <property name="visible">True</property>
+ <property name="border_width">12</property>
+ <property name="spacing">18</property>
+ <child>
+ <object class="GtkVBox" id="image_vbox">
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="image_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Image Viewer</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="image_hbox">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkImage" id="image_image">
+ <property name="visible">True</property>
+ <property name="yalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="image_options_vbox">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkComboBox" id="image_combobox">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkTable" id="image_options_table">
+ <property name="visible">True</property>
+ <property name="n_columns">3</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="image_command_label">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Co_mmand:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">image_command_entry</property>
+ </object>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="image_command_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip_text" translatable="yes">All %s occurrences will be replaced with actual link</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="image_terminal_checkbox">
+ <property name="label" translatable="yes">Run in t_erminal</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="media_player_vbox">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="media_player_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Multimedia Player</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="media_player_hbox">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkImage" id="media_player_image">
+ <property name="visible">True</property>
+ <property name="yalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="media_player_options_vbox">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkComboBox" id="media_player_combobox">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkTable" id="media_player_options_table">
+ <property name="visible">True</property>
+ <property name="n_columns">3</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="media_player_command_label">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Co_mmand:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">media_player_command_entry</property>
+ </object>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="media_player_command_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip_text" translatable="yes">All %s occurrences will be replaced with actual link</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="media_player_terminal_checkbutton">
+ <property name="label" translatable="yes">Run in t_erminal</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="video_vbox">
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="video_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Video Player</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="video_hbox">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkImage" id="video_image">
+ <property name="visible">True</property>
+ <property name="yalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="video_options_vbox">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkComboBox" id="video_combobox">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkTable" id="video_options_table">
+ <property name="visible">True</property>
+ <property name="n_columns">3</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="video_command_label">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Co_mmand:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">video_command_entry</property>
+ </object>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="video_command_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip_text" translatable="yes">All %s occurrences will be replaced with actual link</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="video_terminal_checkbox">
+ <property name="label" translatable="yes">Run in t_erminal</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="multimedia_label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Multimedia</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="system_vbox">
+ <property name="visible">True</property>
+ <property name="border_width">12</property>
+ <property name="spacing">18</property>
+ <child>
+ <object class="GtkVBox" id="text_vbox">
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="text_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Text Editor</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="text_hbox">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkImage" id="text_image">
+ <property name="visible">True</property>
+ <property name="yalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="text_options_vbox">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkComboBox" id="text_combobox">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkTable" id="text_options_table">
+ <property name="visible">True</property>
+ <property name="n_columns">3</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="text_command_label">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Co_mmand:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">text_command_entry</property>
+ </object>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="text_command_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip_text" translatable="yes">All %s occurrences will be replaced with actual link</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="text_terminal_checkbox">
+ <property name="label" translatable="yes">Run in t_erminal</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="terminal_vbox">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="terminal_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Terminal Emulator</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="terminal_hbox">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkImage" id="terminal_image">
+ <property name="visible">True</property>
+ <property name="yalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="terminal_options_vbox">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkComboBox" id="terminal_combobox">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkTable" id="terminal_options_table">
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="terminal_command_label">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Co_mmand:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">terminal_command_entry</property>
+ </object>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="terminal_command_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip_text" translatable="yes">All %s occurrences will be replaced with actual link</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="terminal_exec_flag_label">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">E_xecute flag:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">terminal_exec_flag_entry</property>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="terminal_exec_flag_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+
+ <!-- el file manager -- >
+ <child>
+ <object class="GtkVBox" id="filemanager_vbox">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="filemanager_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">File Manager</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="filemanager_hbox">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkImage" id="filemanager_image">
+ <property name="visible">True</property>
+ <property name="yalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="filemanager_options_vbox">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkComboBox" id="filemanager_combobox">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkTable" id="filemanager_options_table">
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="filemanager_command_label">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Co_mmand:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">filemanager_command_entry</property>
+ </object>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="filemanager_command_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip_text" translatable="yes">All %s occurrences will be replaced with actual link</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="filemanager_exec_flag_label">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">E_xecute flag:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">filemanager_exec_flag_entry</property>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="filemanager_exec_flag_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+
+ < ! -- / el file manager -->
+
+ </object>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="system_label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">System</property>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="a11y_vbox">
+ <property name="visible">True</property>
+ <property name="border_width">12</property>
+ <property name="spacing">18</property>
+ <child>
+ <object class="GtkVBox" id="visual_vbox">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="visual_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Visual</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="visual_hbox">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkImage" id="visual_image">
+ <property name="visible">True</property>
+ <property name="yalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="visual_options_vbox">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkComboBox" id="visual_combobox">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="visual_start_checkbutton">
+ <property name="label" translatable="yes">_Run at start</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkTable" id="visual_options_table">
+ <property name="visible">True</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="visual_command_label">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">C_ommand:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">image_command_entry</property>
+ </object>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="visual_command_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip_text" translatable="yes">All %s occurrences will be replaced with actual link</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="mobility_vbox">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="mobility_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Mobility</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="mobility_hbox">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkImage" id="mobility_image">
+ <property name="visible">True</property>
+ <property name="yalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="mobility_options_vbox">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkComboBox" id="mobility_combobox">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="mobility_start_checkbutton">
+ <property name="label" translatable="yes">Run at st_art</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkTable" id="mobility_options_table">
+ <property name="visible">True</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="mobility_command_label">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Co_mmand:</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="mobility_command_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip_text" translatable="yes">All %s occurrences will be replaced with actual link</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="a11y_apps_label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Accessibility</property>
+ </object>
+ <packing>
+ <property name="position">3</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <object class="GtkHButtonBox" id="dialog-action_area">
+ <property name="visible">True</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="helpbutton1">
+ <property name="label">gtk-help</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="closebutton1">
+ <property name="label">gtk-close</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-11">helpbutton1</action-widget>
+ <action-widget response="-7">closebutton1</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/capplets/default-applications/mate-default-applications.pc.in b/capplets/default-applications/mate-default-applications.pc.in
new file mode 100644
index 00000000..1bdae900
--- /dev/null
+++ b/capplets/default-applications/mate-default-applications.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+datarootdir=@datarootdir@
+datadir=@datadir@
+pkgdatadir=${datadir}/@PACKAGE@
+defappsdir=${pkgdatadir}/default-apps
+
+Name: mate-default-applications
+Description: Default MATE applications configuration
+Version: @VERSION@
+
diff --git a/capplets/default-applications/mate-default-applications.xml.in b/capplets/default-applications/mate-default-applications.xml.in
new file mode 100644
index 00000000..4bd2f8b9
--- /dev/null
+++ b/capplets/default-applications/mate-default-applications.xml.in
@@ -0,0 +1,483 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE default-apps SYSTEM "mate-da-list.dtd">
+<default-apps>
+
+<!-- Remember to never use the same string for <command>, <tab-command> and <win-command> entries -->
+
+ <web-browsers>
+ <web-browser>
+ <_name>Opera</_name>
+ <executable>opera</executable>
+ <command>opera %s</command>
+ <icon-name>opera</icon-name>
+ <run-in-terminal>false</run-in-terminal>
+ <netscape-remote>true</netscape-remote>
+ <tab-command>opera -newpage %s</tab-command>
+ <win-command>opera -newwindow %s</win-command>
+ </web-browser>
+ <web-browser>
+ <_name>Debian Sensible Browser</_name>
+ <executable>sensible-browser</executable>
+ <command>sensible-browser %s</command>
+ <icon-name></icon-name>
+ <run-in-terminal>false</run-in-terminal>
+ <netscape-remote>false</netscape-remote>
+ </web-browser>
+ <web-browser>
+ <_name>Epiphany Web Browser</_name>
+ <executable>epiphany</executable>
+ <command>epiphany %s</command>
+ <icon-name>web-browser</icon-name>
+ <run-in-terminal>false</run-in-terminal>
+ <netscape-remote>true</netscape-remote>
+ <tab-command>epiphany --new-tab %s</tab-command>
+ <win-command>epiphany --new-window %s</win-command>
+ </web-browser>
+ <web-browser>
+ <_name>Galeon</_name>
+ <executable>galeon</executable>
+ <command>galeon %s</command>
+ <icon-name>galeon</icon-name>
+ <run-in-terminal>false</run-in-terminal>
+ <netscape-remote>true</netscape-remote>
+ <tab-command>galeon -n %s</tab-command>
+ <win-command>galeon -w %s</win-command>
+ </web-browser>
+ <web-browser>
+ <_name>Encompass</_name>
+ <executable>encompass</executable>
+ <command>encompass %s</command>
+ <icon-name>encompass</icon-name>
+ <run-in-terminal>false</run-in-terminal>
+ <netscape-remote>false</netscape-remote>
+ </web-browser>
+ <web-browser>
+ <_name>Firebird</_name>
+ <executable>mozilla-firebird</executable>
+ <command>mozilla-firebird %s</command>
+ <icon-name></icon-name>
+ <run-in-terminal>false</run-in-terminal>
+ <netscape-remote>true</netscape-remote>
+ <tab-command>mozilla-firebird -remote "openurl(%s,new-tab)"</tab-command>
+ <win-command>mozilla-firebird -remote "openurl(%s,new-window)"</win-command>
+ </web-browser>
+ <web-browser>
+ <_name>Firefox</_name>
+ <executable>firefox</executable>
+ <command>firefox %s</command>
+ <icon-name>firefox</icon-name>
+ <run-in-terminal>false</run-in-terminal>
+ <netscape-remote>true</netscape-remote>
+ <tab-command>firefox -new-tab "%s"</tab-command>
+ <win-command>firefox -new-window "%s"</win-command>
+ </web-browser>
+ <web-browser>
+ <_name>Iceweasel</_name>
+ <executable>iceweasel</executable>
+ <command>iceweasel %s</command>
+ <icon-name>iceweasel</icon-name>
+ <run-in-terminal>false</run-in-terminal>
+ <netscape-remote>true</netscape-remote>
+ <tab-command>iceweasel -new-tab "%s"</tab-command>
+ <win-command>iceweasel -new-window "%s"</win-command>
+ </web-browser>
+ <web-browser>
+ <_name>Mozilla 1.6</_name>
+ <executable>mozilla-1.6</executable>
+ <command>mozilla-1.6 %s</command>
+ <icon-name>mozilla-icon</icon-name>
+ <run-in-terminal>false</run-in-terminal>
+ <netscape-remote>true</netscape-remote>
+ <tab-command>mozilla-1.6 -remote "openurl(%s,new-tab)"</tab-command>
+ <win-command>mozilla-1.6 -remote "openurl(%s,new-window)"</win-command>
+ </web-browser>
+ <web-browser>
+ <_name>Mozilla</_name>
+ <executable>mozilla</executable>
+ <command>mozilla %s</command>
+ <icon-name>mozilla-icon</icon-name>
+ <run-in-terminal>false</run-in-terminal>
+ <netscape-remote>true</netscape-remote>
+ <tab-command>mozilla -remote "openurl(%s,new-tab)"</tab-command>
+ <win-command>mozilla -remote "openurl(%s,new-window)"</win-command>
+ </web-browser>
+ <web-browser>
+ <_name>SeaMonkey</_name>
+ <executable>seamonkey</executable>
+ <command>seamonkey %s</command>
+ <icon-name>seamonkey</icon-name>
+ <run-in-terminal>false</run-in-terminal>
+ <netscape-remote>true</netscape-remote>
+ <tab-command>seamonkey -remote "openurl(%s,new-tab)"</tab-command>
+ <win-command>seamonkey -remote "openurl(%s,new-window)"</win-command>
+ </web-browser>
+ <web-browser>
+ <_name>Iceape</_name>
+ <executable>iceape</executable>
+ <command>iceape %s</command>
+ <icon-name>iceape</icon-name>
+ <run-in-terminal>false</run-in-terminal>
+ <netscape-remote>true</netscape-remote>
+ <tab-command>iceape -remote "openurl(%s,new-tab)"</tab-command>
+ <win-command>iceape -remote "openurl(%s,new-window)"</win-command>
+ </web-browser>
+ <web-browser>
+ <_name>Netscape Communicator</_name>
+ <executable>netscape</executable>
+ <command>netscape %s</command>
+ <icon-name>netscape</icon-name>
+ <run-in-terminal>false</run-in-terminal>
+ <netscape-remote>true</netscape-remote>
+ <tab-command>netscape -remote "openurl(%s,new-tab)"</tab-command>
+ <win-command>netscape -remote "openurl(%s,new-window)"</win-command>
+ </web-browser>
+ <web-browser>
+ <_name>Konqueror</_name>
+ <executable>konqueror</executable>
+ <command>konqueror %s</command>
+ <icon-name>konqueror</icon-name>
+ <run-in-terminal>false</run-in-terminal>
+ <netscape-remote>false</netscape-remote>
+ </web-browser>
+ <web-browser>
+ <_name>Midori</_name>
+ <executable>midori</executable>
+ <command>midori %s</command>
+ <icon-name>web-browser</icon-name>
+ <run-in-terminal>false</run-in-terminal>
+ <netscape-remote>false</netscape-remote>
+ </web-browser>
+ </web-browsers>
+
+ <mail-readers>
+ <mail-reader>
+ <_name>Evolution Mail Reader</_name>
+ <executable>evolution</executable>
+ <command>evolution %s</command>
+ <icon-name>evolution</icon-name>
+ <run-in-terminal>false</run-in-terminal>
+ </mail-reader>
+ <mail-reader>
+ <_name>Balsa</_name>
+ <executable>balsa</executable>
+ <command>balsa -m %s</command>
+ <icon-name>mate-balsa2</icon-name>
+ <run-in-terminal>false</run-in-terminal>
+ </mail-reader>
+ <mail-reader>
+ <_name>KMail</_name>
+ <executable>kmail</executable>
+ <command>kmail %s</command>
+ <icon-name>kmail</icon-name>
+ <run-in-terminal>false</run-in-terminal>
+ </mail-reader>
+ <mail-reader>
+ <_name>Icedove</_name>
+ <executable>icedove</executable>
+ <command>icedove %s</command>
+ <icon-name>icedove</icon-name>
+ <run-in-terminal>false</run-in-terminal>
+ </mail-reader>
+ <mail-reader>
+ <_name>Thunderbird</_name>
+ <executable>thunderbird</executable>
+ <command>thunderbird %s</command>
+ <icon-name>thunderbird</icon-name>
+ <run-in-terminal>false</run-in-terminal>
+ </mail-reader>
+ <mail-reader>
+ <_name>Mozilla Thunderbird</_name>
+ <executable>mozilla-thunderbird</executable>
+ <command>mozilla-thunderbird %s</command>
+ <icon-name>thunderbird</icon-name>
+ <run-in-terminal>false</run-in-terminal>
+ </mail-reader>
+ <mail-reader>
+ <_name>Mozilla Mail</_name>
+ <executable>mozilla</executable>
+ <command>mozilla -mail %s</command>
+ <icon-name>mozilla-mail-icon</icon-name>
+ <run-in-terminal>false</run-in-terminal>
+ </mail-reader>
+ <mail-reader>
+ <_name>SeaMonkey Mail</_name>
+ <executable>seamonkey</executable>
+ <command>seamonkey -mail %s</command>
+ <icon-name>seamonkey</icon-name>
+ <run-in-terminal>false</run-in-terminal>
+ </mail-reader>
+ <mail-reader>
+ <_name>Iceape Mail</_name>
+ <executable>iceape</executable>
+ <command>iceape -mail %s</command>
+ <icon-name>iceape</icon-name>
+ <run-in-terminal>false</run-in-terminal>
+ </mail-reader>
+ <mail-reader>
+ <_name>Mutt</_name>
+ <executable>mutt</executable>
+ <command>mutt %s</command>
+ <icon-name>mate-mime-application-x-executable</icon-name>
+ <run-in-terminal>true</run-in-terminal>
+ </mail-reader>
+ <mail-reader>
+ <_name>Claws Mail</_name>
+ <executable>claws-mail</executable>
+ <command>claws-mail --compose %s</command>
+ <icon-name>claws-mail</icon-name>
+ <run-in-terminal>false</run-in-terminal>
+ </mail-reader>
+ <mail-reader>
+ <_name>Sylpheed-Claws</_name>
+ <executable>sylpheed-claws</executable>
+ <command>sylpheed-claws --compose %s</command>
+ <icon-name>sylpheed</icon-name>
+ <run-in-terminal>false</run-in-terminal>
+ </mail-reader>
+ <mail-reader>
+ <_name>Sylpheed</_name>
+ <executable>sylpheed</executable>
+ <command>sylpheed --compose %s</command>
+ <icon-name>sylpheed</icon-name>
+ <run-in-terminal>false</run-in-terminal>
+ </mail-reader>
+ </mail-readers>
+
+ <!-- agregando para los ... -->
+ <file-managers>
+ <file-manager>
+ <_name>Mate File Manager</_name>
+ <executable>caja</executable>
+ <run-in-terminal>false</run-in-terminal>
+ <command>caja %s</command>
+ <icon-name>file-manager</icon-name>
+ </file-manager>
+
+ <file-manager>
+ <_name>Nautilus</_name>
+ <executable>nautilus</executable>
+ <run-in-terminal>false</run-in-terminal>
+ <command>nautilus %s</command>
+ <icon-name>nautilus</icon-name>
+ </file-manager>
+
+ <file-manager>
+ <_name>Thunar</_name>
+ <executable>thunar</executable>
+ <run-in-terminal>false</run-in-terminal>
+ <command>thunar %s</command>
+ <icon-name>thunar</icon-name>
+ </file-manager>
+
+ </file-managers>
+
+ <terminals>
+ <terminal>
+ <_name>Debian Terminal Emulator</_name>
+ <executable>x-terminal-emulator</executable>
+ <command>x-terminal-emulator</command>
+ <icon-name>mate-mime-application-x-executable</icon-name>
+ <exec-flag>-e</exec-flag>
+ </terminal>
+ <terminal>
+ <_name>MATE Terminal</_name>
+ <executable>mate-terminal</executable>
+ <command>mate-terminal</command>
+ <icon-name>utilities-terminal</icon-name>
+ <exec-flag>-x</exec-flag>
+ </terminal>
+ <terminal>
+ <_name>GNOME Terminal</_name>
+ <executable>gnome-terminal</executable>
+ <command>gnome-terminal</command>
+ <icon-name>gnome-terminal</icon-name>
+ <exec-flag>-x</exec-flag>
+ </terminal>
+ <terminal>
+ <_name>Terminator</_name>
+ <executable>terminator</executable>
+ <command>terminator</command>
+ <icon-name>terminator</icon-name>
+ <exec-flag>-x</exec-flag>
+ </terminal>
+ <terminal>
+ <_name>Standard XTerminal</_name>
+ <executable>xterm</executable>
+ <command>xterm</command>
+ <icon-name>mate-mime-application-x-executable</icon-name>
+ <exec-flag>-e</exec-flag>
+ </terminal>
+ <terminal>
+ <_name>NXterm</_name>
+ <executable>nxterm</executable>
+ <command>nxterm</command>
+ <icon-name>mate-mime-application-x-executable</icon-name>
+ <exec-flag>-e</exec-flag>
+ </terminal>
+ <terminal>
+ <_name>RXVT</_name>
+ <executable>rxvt</executable>
+ <command>rxvt</command>
+ <icon-name>mate-mime-application-x-executable</icon-name>
+ <exec-flag>-e</exec-flag>
+ </terminal>
+ <terminal>
+ <_name>aterm</_name>
+ <executable>aterm</executable>
+ <command>aterm</command>
+ <icon-name>mate-mime-application-x-executable</icon-name>
+ <exec-flag>-e</exec-flag>
+ </terminal>
+ <terminal>
+ <_name>ETerm</_name>
+ <executable>ETerm</executable>
+ <command>ETerm</command>
+ <icon-name>mate-mime-application-x-executable</icon-name>
+ <exec-flag>-e</exec-flag>
+ </terminal>
+ <terminal>
+ <_name>Konsole</_name>
+ <executable>konsole</executable>
+ <command>konsole</command>
+ <icon-name>konsole</icon-name>
+ <exec-flag>-e</exec-flag>
+ </terminal>
+ <terminal>
+ <_name>Terminal</_name>
+ <executable>terminal</executable>
+ <command>terminal</command>
+ <icon-name>utilities-terminal</icon-name>
+ <exec-flag>-e</exec-flag>
+ </terminal>
+ <terminal>
+ <_name>Sakura</_name>
+ <executable>sakura</executable>
+ <command>sakura</command>
+ <icon-name>terminal-tango</icon-name>
+ <exec-flag>-e</exec-flag>
+ </terminal>
+ </terminals>
+
+ <media-players>
+ <media-player>
+ <_name>Banshee Music Player</_name>
+ <executable>banshee</executable>
+ <command>banshee</command>
+ <icon-name>music-player-banshee</icon-name>
+ <run-in-terminal>false</run-in-terminal>
+ </media-player>
+ <media-player>
+ <_name>Muine Music Player</_name>
+ <executable>muine</executable>
+ <command>muine</command>
+ <icon-name>muine</icon-name>
+ <run-in-terminal>false</run-in-terminal>
+ </media-player>
+ <media-player>
+ <_name>Rhythmbox Music Player</_name>
+ <executable>rhythmbox</executable>
+ <command>rhythmbox</command>
+ <icon-name>rhythmbox</icon-name>
+ <run-in-terminal>false</run-in-terminal>
+ </media-player>
+ <media-player>
+ <_name>Totem Movie Player</_name>
+ <executable>totem</executable>
+ <command>totem</command>
+ <icon-name>totem</icon-name>
+ <run-in-terminal>false</run-in-terminal>
+ </media-player>
+ <media-player>
+ <_name>Listen</_name>
+ <executable>listen</executable>
+ <command>listen</command>
+ <icon-name>listen</icon-name>
+ <run-in-terminal>false</run-in-terminal>
+ </media-player>
+ </media-players>
+
+ <a11y-visual>
+ <visual>
+ <_name>Orca</_name>
+ <executable>orca</executable>
+ <command>orca</command>
+ <icon-name>orca</icon-name>
+ <run-at-start>false</run-at-start>
+ </visual>
+ <visual>
+ <_name>Orca with Magnifier</_name>
+ <executable>orca</executable>
+ <command>orca -e magnifier</command>
+ <icon-name>orca</icon-name>
+ <run-at-start>false</run-at-start>
+ </visual>
+ <visual>
+ <_name>Linux Screen Reader</_name>
+ <executable>lsr</executable>
+ <command>lsr</command>
+ <icon-name>lsr</icon-name>
+ <run-at-start>false</run-at-start>
+ </visual>
+ <visual>
+ <_name>Linux Screen Reader with Magnifier</_name>
+ <executable>lsr</executable>
+ <command>lsr -p mag</command>
+ <icon-name>lsr</icon-name>
+ <run-at-start>false</run-at-start>
+ </visual>
+ <visual>
+ <_name>Gnopernicus</_name>
+ <executable>gnopernicus</executable>
+ <command>gnopernicus</command>
+ <icon-name>icon-accessibility</icon-name>
+ <run-at-start>false</run-at-start>
+ </visual>
+ <visual>
+ <_name>Gnopernicus with Magnifier</_name>
+ <executable>gnopernicus</executable>
+ <command>gnopernicus -m</command>
+ <icon-name>icon-accessibility</icon-name>
+ <run-at-start>false</run-at-start>
+ </visual>
+ <visual>
+ <_name>MATE Magnifier without Screen Reader</_name>
+ <executable>magnifier</executable>
+ <command>magnifier -m</command>
+ <icon-name>mate-searchtool</icon-name>
+ <run-at-start>false</run-at-start>
+ </visual>
+ <visual>
+ <_name>KDE Magnifier without Screen Reader</_name>
+ <executable>kmag</executable>
+ <command>kmag</command>
+ <icon-name>mate-searchtool</icon-name>
+ <run-at-start>false</run-at-start>
+ </visual>
+
+ </a11y-visual>
+
+ <a11y-mobility>
+ <mobility>
+ <_name>MATE OnScreen Keyboard</_name>
+ <executable>gok</executable>
+ <command>gok</command>
+ <icon-name>accessibility-keyboard-capplet</icon-name>
+ <run-at-start>false</run-at-start>
+ </mobility>
+ <mobility>
+ <_name>Dasher</_name>
+ <executable>dasher</executable>
+ <command>dasher</command>
+ <icon-name>mate-searchtool</icon-name>
+ <run-at-start>false</run-at-start>
+ </mobility>
+ <mobility>
+ <name>onBoard</name>
+ <executable>onboard</executable>
+ <command>onboard</command>
+ <icon-name>onboard</icon-name>
+ <run-at-start>false</run-at-start>
+ </mobility>
+ </a11y-mobility>
+
+</default-apps>
diff --git a/capplets/display/Makefile.am b/capplets/display/Makefile.am
new file mode 100644
index 00000000..70f417c7
--- /dev/null
+++ b/capplets/display/Makefile.am
@@ -0,0 +1,78 @@
+# This is used in MATECC_CAPPLETS_CFLAGS
+cappletname = display
+
+uidir = $(pkgdatadir)/ui
+dist_ui_DATA = display-capplet.ui
+
+bin_PROGRAMS = mate-display-properties
+
+sbin_PROGRAMS = mate-display-properties-install-systemwide
+
+mate_display_properties_SOURCES = \
+ xrandr-capplet.c \
+ scrollarea.c \
+ foo-marshal.c \
+ scrollarea.h \
+ foo-marshal.h
+
+mate_display_properties_LDFLAGS = -export-dynamic
+mate_display_properties_LDADD = \
+ $(top_builddir)/capplets/common/libcommon.la \
+ $(DISPLAY_CAPPLET_LIBS)
+
+mate_display_properties_install_systemwide_SOURCES = \
+ mate-display-properties-install-systemwide.c
+
+mate_display_properties_install_systemwide_LDADD = \
+ $(GLIB_LIBS)
+
+polkit_policydir = $(datadir)/polkit-1/actions
+dist_polkit_policy_DATA = \
+ org.mate.randr.policy
+
+# You will need a recent intltool or the patch from this bug
+# http://bugzilla.gnome.org/show_bug.cgi?id=462312
+@INTLTOOL_POLICY_RULE@
+
+@INTLTOOL_DESKTOP_RULE@
+
+icons16dir = $(datadir)/icons/hicolor/16x16/apps
+dist_icons16_DATA = icons/16x16/mate-preferences-desktop-display.png
+icons22dir = $(datadir)/icons/hicolor/22x22/apps
+dist_icons22_DATA = icons/22x22/mate-preferences-desktop-display.png
+icons24dir = $(datadir)/icons/hicolor/24x24/apps
+dist_icons24_DATA = icons/24x24/mate-preferences-desktop-display.png
+icons32dir = $(datadir)/icons/hicolor/32x32/apps
+dist_icons32_DATA = icons/32x32/mate-preferences-desktop-display.png
+iconssvgdir = $(datadir)/icons/hicolor/scalable/apps
+dist_iconssvg_DATA = icons/scalable/mate-preferences-desktop-display.svg
+
+desktopdir = $(datadir)/applications
+Desktop_in_files = display-properties.desktop.in
+desktop_DATA = $(Desktop_in_files:.desktop.in=.desktop)
+
+INCLUDES = $(DISPLAY_CAPPLET_CFLAGS) \
+ $(MATECC_CAPPLETS_CFLAGS) \
+ -DSBINDIR="\"$(sbindir)\"" \
+ -DUIDIR="\"$(uidir)\"" \
+ -DMATELOCALEDIR="\"$(datadir)/locale\"" \
+ -DMATECC_DATA_DIR="\"$(pkgdatadir)\""
+
+CLEANFILES = $(MATECC_CAPPLETS_CLEANFILES) $(Desktop_in_files) $(desktop_DATA)
+
+gtk_update_icon_cache = gtk-update-icon-cache -f -t $(datadir)/icons/hicolor
+install-data-hook: update-icon-cache
+uninstall-hook: update-icon-cache
+update-icon-cache:
+ @-if test -z "$(DESTDIR)"; then \
+ echo "Updating Gtk icon cache."; \
+ $(gtk_update_icon_cache); \
+ else \
+ echo "*** Icon cache not updated. After (un)install, run this:"; \
+ echo "*** $(gtk_update_icon_cache)"; \
+ fi
+
+EXTRA_DIST = org.mate.randr.policy.in
+DISTCLEANFILES = org.mate.randr.policy
+
+-include $(top_srcdir)/git.mk
diff --git a/capplets/display/TODO b/capplets/display/TODO
new file mode 100644
index 00000000..08f9e21b
--- /dev/null
+++ b/capplets/display/TODO
@@ -0,0 +1,837 @@
+Highlevel overview:
+
+Tablet rotation things
+only when there is a tablet attached.
+
+Here is the OS X Display menu:
+
+ Detect Displays
+ Turn on mirroring
+ --------------------------
+ SyncMaster
+ - 1280 x 1024, 60 Hz, Millions
+ - 1344 x ...
+ --------------------------------
+ Color LCD
+ - 1024 x 1024 ...
+ --------------------------
+ Displays Preferences
+
+ Color LCD means "laptop panel".
+
+- GTK+ work.
+
+ Allow applications to be notified whenever monitors are added
+ or removed. Allow applications to get more detailed
+ information about the connected monitors.
+
+ The main complication is that XRRGetScreenResources() is very
+ slow. We could call it only when the X server sends an event,
+ but it's not desirable to have every application freeze for
+ half a second. And certainly not desirable to have the X
+ server block for n * 0.5 seconds.
+
+ With the X server work below we should be fine just calling
+ XRRGetScreenResources on startup and in response to events.
+
+- X server work:
+
+ X server needs to poll for whether a monitor is plugged
+ in. Whenever it detects a change, it should do an EDID query,
+ and cache the resulting information. That way XRRGetScreenResources()
+ can be the speed of a normal roundtrip. It's desirable that
+ normal client requests can still be processed during the EDID
+ querying, but only a nice-to-have.
+
+ Drivers need to work reliably. There could be substantial work
+ here. For F9, possibly only the Intel driver can be made to
+ work.
+
+ Interrupts and events must be generated whenever something changes
+ about the outputs, if necessary by polling.
+
+ Events must be emitted whenever something changes, including when
+ the reason for the change is a manual change.
+
+ The maximum framebuffer must be dynamically changable.
+
+- Control panel work:
+ Capplet needs to be written. The main complications:
+
+ - It needs to pay attention to events from the X server
+ and update itself, ie., add show new monitors if they become
+ available when the applet is shown.
+
+ - It needs to store information under a key computed
+ from a monitor identifier. The complication here is that
+ it's not completely clear how to do this in MateConf.
+
+ - Would probably be worthwhile to drop libmate/libmateui from
+ the craplets.
+
+- Marco work:
+ - Marco is already Xinerama aware, but it needs to update itself
+ when monitors come and go.
+
+- MATE panel work:
+ - Is already Xinerama aware, but needs to listen and update itself
+ when monitors change.
+
+- Evince work:
+ - Make sure it deals sensibly with multiple monitors
+
+- OpenOffice work:
+ - Make sure it deals sensibly with multiple monitors
+
+- An Xlib call to just return all the available information would be
+ useful. At the moment we have to do a bunch of roundtrips to
+ get the information. This is a would-be-nice though.
+
+- A dbus service could be written that pops up the applet whenever a
+ monitor. It should only pop up if the new monitor is unknown. This
+ is at best a nice-to-have, and low priority in my opinion.
+
+
+******************* Marco
+
+Havoc:
+
+> I was just talking to bryan about this and "helping" him design it ;-)
+
+> But I wanted to be sure and lobby for a fix window managers
+> need. Basically right now the WM can't tell "physical" from
+> "logical" monitors.
+
+> A "logical" monitor is a desktop; it has its own panel, windows
+> maximize to it, etc.
+
+> A "physical" monitor is a piece of hardware.
+
+> Sometimes people want to combine physical monitors into a video wall
+> or just two monitors treated as one. Or at least a couple of noisy
+> people in bugzilla want to do this.
+
+> When people talk about a "Xinerama aware" app or WM they usually
+> mean that all physical monitors are treated as logical monitors,
+> while lack of Xinerama-aware means treating the entire X screen (all
+> physical monitors) as one logical monitor.
+
+> The problem is that the setting for "ignore Xinerama" or "don't be
+> Xinerama aware" should be global to the desktop (GTK, all apps, WM)
+> and should not be a window manager setting.
+
+> Bryan thought people who wanted non-Xinerama-aware should just use
+> fvwm, which may be right, but what I'd say is that if there is any
+> setting for this, it should be desktop-global and in this monitor
+> config dialog.
+
+> It should not be a marco or Compiz option, but in some way an X
+> option in short. The implementation could be either an X server
+> feature or an EWMH hint or whatever, but it should be controlled by
+> the monitor config dialog and used by apps, GTK, etc. in addition to
+> used by the WM.
+
+> People tend to insist this should be a WM option, but that's just
+> busted, since GTK and apps also have Xinerama-awareness features.
+
+
+******************* EDID
+
+edid-decode enhancements:
+
+- Rejects years <= 0x0f for all versions, but this should only be done
+ for monitors claiming conformance to 1.4 (since 1.4 was released in
+ 2006). A monitor produced in 2005 should have 0x0f - it's the only
+ reasonable thing to do.
+
+- Uses 0x80 as the conformance mask for 1.4, should be 0
+
+- Should read from stdin
+
+- Should parse xrandr -verbose output more robustly
+
+- Color depth computation is wrong. It uses the formula
+
+ (edid[0x14] >> 3) + 2
+
+ The correct formula to use is
+
+ (edid[0x14] & 0x70) >> 3 + 4
+
+-
+
+-=-=-=-
+Computing a display name from EDID information:
+
+ vendor = lookup_vendor (code);
+
+ if (dsc_product && !is_gobbledigook (dsc_product))
+ {
+ if (vendor && !fuzzy_string_search (vendor, dsc_product))
+ prepend (vendor);
+ }
+ else
+ {
+ if (vendor)
+ append (vendor);
+ else
+ append ("Unknown");
+ }
+
+ if (has size)
+ {
+ convert_to_inches()
+
+ append (" %d\"", inches)
+ }
+
+(Does this internationalize at all)?
+
+We also need the ability to get laptop names. The laptop panel may report
+a manufacturer that has nothing to do with the laptop manufacturer.
+
+Needed XRandr output properties:
+
+- Modes that the monitor supports, or enough information that the
+ client can go throught the list of modes for the relevant
+ CRTC/Outputs and filter those out that the monitor can't support.
+
+- The preferred mode, if any. Also useful if we could get a "strongly
+ preferred" indication if it's an LCD with a fixed resolution.
+
+- Sufficient information that a fairly specific identifier can be
+ computed. The algorithm the client should use is:
+
+ 1 Have we seen exactly this monitor before? If yes, use
+ settings for that.
+
+ 2 Have we seen a monitor with similar specs before? If yes,
+ use settings for that. (But don't save, unless the user
+ changes the settings).
+
+ 3 Otherwise, use some reasonable default for the monitor and
+ save it.
+
+ A setting should only be used if the CRTC/Output allows it. Ie,. if
+ a user has installed a new video card, then previously-used settings
+ may no longer apply, so this must be checked every time.
+
+ (1) Implies that we really need a globally unique identifier for
+ monitors. (2) is useful in an enterprise setting, but not absolutely
+ critical, since (3) would still handle the majority of cases.
+
+ There is a question here: Where are machine specific preferences
+ stored? Havoc mentions three possibilities here:
+
+ http://mail.gnome.org/archives/matecc-list/2001-October/msg00023.html
+
+ I'm not sure if any of them are implementable at this point. Also
+ (1) may mostly take care of the problem.
+
+
+ Usecases:
+
+ 1. Fixed setup with some number of monitors.
+ - They should be set to the correct mode on login.
+ Note that this involves setting the right position in the
+ framebuffer too.
+
+ What if someone swaps two monitors? Users are going to expect
+ that the images will switch position.
+
+ 2. Laptop being moved between home and work
+ - Setups should be detected and the correct mode set, at least on
+ login, but ideally when you put the laptop into the docking
+ station.
+
+ 3. Laptop gets projector plugged in.
+
+ Note the same model monitor can be used in two different ways. Ie.,
+ at home, it's being used at one resolution, at work the same type of
+ monitor is used at a different resolution.
+
+ Simple solution:
+
+ - The on-disk database is just a list of monitors. Each monitor has an
+ associated mode. This has these problems:
+ - If someone uses the same monitor model in two different ways.
+ - If someone swaps the monitors around
+
+ Better solution
+
+ - The on-disk database is a list of configurations, where a
+ configuration is a list of monitors and what outputs they are
+ connected to, and the position in the framebuffer.
+
+ - Picking a default configuration is then a matter of selecting the
+ closest existing configuration from the database.
+
+ - If the stored configuration is a subset of the existing,
+ then use that - then pick the best mode available for the
+ rest of the monitors
+
+ - If the stored configuration is a superset of the existing,
+ then use the projection of the configuration onto the monitors.
+
+ - Pick the configuration with the most overlap in monitors.
+ Although, if a configuration differs only in what outputs
+ they are connected to, then those outputs should probably
+ get their original modes set.
+
+ - Or maybe simply:
+
+ - If there is an exact match, use it, if not, pick a default.
+
+ - Picking a new default must never change the mode of any existing
+ output.
+
+******************* Capplet
+
+Somehow the applet will find out that a new monitor is plugged in
+(either through notification, or through a refresh button). When this
+happens, this monitor is looked up in a database and if it is found,
+some suitable mode is set.
+
+Restrictions on the modes:
+
+- Monitors that are already plugged in should not get their mode
+ changed just because a new monitor is plugged in.
+
+- If the exact configuration of monitors is known, and all the old
+ monitors have the same mode as the known configuration, then just use
+ the known configuration. Also do this, if the configuration is a
+ subset of something known.
+
+- Otherwise, if the configuration is a subset of a known configuration
+ where the only difference is that existing monitors have different
+ modes, then try and convert that mode to something we can know
+ about. Maybe configurations should be stored in terms of edges that
+ line up.
+
+- Otherwise, just pick some good default for the mode, probably based
+ on the EDID prferred mode if possible. By default cloning is
+ probably best.
+
+- How do virtual desktops interact with this?
+
+
+g-s-d:
+
+- On startup
+
+ - It reads the configuration file into memory
+
+ capplet --configure
+
+ - It gathers the existing configuration from randr
+
+ - If the existing config is in the file, set that mode
+
+- On changes, including changes to the config file [this is crack]
+
+ - Reread configuration file
+
+ - Compare new configuration to database, if it is there, set the
+ mode as appropriate
+
+ - If a monitor was added, pop up a bubble
+
+ capplet --show-bubble
+
+ capplet --set-mode
+
+capplet
+
+- On changes
+
+ - Update GUI
+
+- When user changes something,
+
+ - Write configuration to file
+
+ - Signal gsd somehow
+
+Schemes:
+ - configuration file changes
+ - randr code will have to be shared between gcc and gsd
+
+ - binary installed by gcc
+ - something will still have to listen for changes to pop
+ up the notification bubble.
+
+Structure of capplet:
+
+- There is a database on disk with monitors and their corresponding
+ settings.
+
+- On startup, this database is read into memory. When the user accepts
+ new settings, it is written back to disk.
+
+- When something changes about the settings
+
+ - If new configuration is in the database, use that mode
+
+ - Else, find all outputs that are now connected but weren't before,
+ and set a default mode for them.
+
+ - If GUI is running, update graphics.
+
+
+ - Notification thing:
+ - if
+
+ - if the new configuration is found in the database, use it
+
+ and added if they are not already there. Initial settings are
+ 1 what the output is already doing, if anything
+ 2 based on an existing sufficiently similar monitor, if possible
+ 3 some reasonable default.
+
+- When the user changes settings in the GUI, the corresponding monitor
+ in the database is updated.
+
+- Whenever the GUI settings change, for all displayed monitors the
+ possible modes are recomputed.
+
+- Whenever a new monitor is selected in the GUI, it first gets all its
+ possible modes computed based on the selections on other
+ outputs. Then, if the possible modes include the existing choice of
+ resolution, that is selected.
+
+ Actually,
+
+ - initially, the settings are copied from the current settings
+
+ - whenever a gui setting changes for a monitor, all the other
+ monitors get their list of choices set to whatever is possible
+ given the chocie for the current monitor. A 'desired mode' is
+ maintained, and the closest choice to that is displayed. Whenever
+ the user actively selects something, that becomes the desired mode
+ for that monitor.
+
+- Required
+
+ - Generate all outputs that are newly connected
+
+ foreach_newly_connected (Configuration *before, Configuration *after,
+ OutputFunc);
+
+ - A way to generate the best mode for a connected output
+
+ existing best_mode() can probably be used
+
+ - Given a list of modes, pick the one closest to a given mode.
+
+ (a possibility here is: pick an exact match, if that's
+ impossible, then pick the best one with the same
+ width/height, if that's impossible, then just pick the
+ best mode on the list).
+
+ - For a configuation, fix the mode for a subset of the outputs, then
+ list the combinations for the rest of the outputs.
+
+ An obvious possibility here is to simply list all possibilities,
+ then weed out those that don't work. Is this too expensive?
+ It might be.
+
+Structure of login time program:
+
+- The configuration database is read
+
+- The current hardware configuration is generated
+
+- If the current configuration is found in the database, that mode is set.
+
+- If it isn't found, then nothing changes.
+
+ This could just be mate-screen-resolution-capplet --reset
+
+******************* Things that need to be done to the xrandr.patch:
+
+===
+
+XRRGetScreenResources() is a roundtrip and very slow (~0.5 s). GTK+
+needs to keep information up-to-date by tracking events rather than
+calling this function. In fact we probably can't call it at all unless
+its performance improves significantly.
+
+If EDID processing really has to be this slow, and we can't get
+interrupts when monitors are plugged in, then we have a problem,
+because we can't do anything this expensive once per second.
+
+
+Detailed notes (but most of the patch should be rewritten):
+
+
+=== FIXME in gdkscreen-x11.c in get_width_mm()
+
+/* monitor pixel width / screen pixel width * screen_physical width */
+
+
+
+=== Check for 1.2 library
+
+The patch should check that the 1.2 version of the XRandR library is
+available before using the functions. A possibility is to not use any
+RandR unless 1.2 is available, another is to conditionalize the code.
+
+The most sane thing is probably to just require 1.2.
+
+On the other hand, installing a newer gtk+ on a system with older X is
+probably not that unusual, so maybe it's better to do the full 1.0,
+vs. 1.1 vs 1.2 check.
+
+For now it just requires 1.2.
+
+Actually, this might be fine because the only place where we make use
+of a 1.1 library is in the _gdk_x11_screen_size_changed() function,
+but there we have a fallback that just updates the variables in the
+Screen struct itself.
+
+So, only defining HAVE_RANDR if we detect 1.2 should be ok.
+
+=== Monitor information available
+
+- Subpixel information. This should be set automatically for the fonts and
+ store under the name of the monitor. If the user changes the font
+ configuration, that change should also be stored under the monitor name.
+
+- When a monitor we don't know about is plugged in, a configuration should
+ be generated:
+
+ - Screen size, computed based on the location of the screens
+
+ - RGBA information
+
+ - Whether the screen has a panel on it
+
+ - If there is a conflict between stored information and EDID,
+ the stored information wins
+
+
+
+New API so far:
+
+(* monitors_changed) signal
+gdk_screen_get_monitor_width_mm()
+gdk_screen_get_monitor_height_mm()
+gdk_screen_get_monitor_name() => Note this is the output (eg. "DVI-0")
+
+We should probably also have
+get_manufacturer()
+get_serial()
+get_resolutions()
+
+etc.
+
+Should there be a GdkMonitor object that would correspond to an
+output? Or maybe GdkOutput?
+
+screen_list_monitors()
+
+
+*************************** Issues XRandR/Xserver
+
+- We need polling in the X server, whenever something changes, X must
+ recompute the information and cache it, then send an event. Note the
+ situation where the user disconnects and reconnects a monitor within
+ the polling interval. The event could missed in that case since the polling
+ cannot do a full EDID query. Difficult to see a way around this.
+
+ Actually, DDC allows random access, so it should be possible to just
+ read theq vendor id and manufacturer codes. This can be done once a
+ second without a problem. The polling should be turned off in power
+ saving mode anyway.
+
+ - Driver work:
+
+ - Intel driver:
+
+ - EDID information is not reported for VGA when the output is not
+ turned on (i945 laptop).
+
+ - Screen size must be dynamically changable. (No xorg.conf changes
+ should be required).
+
+ - Make use of ACPI information when possible.
+
+ Adam has code on his freedesktop page.
+
+ - i830 laptop can be put in a state where XRandr reports that no
+ outputs are connected to a CRTC, but the panel is on.
+
+ - Plug in VGA
+ - xrandr --auto
+ - xrandr --output VGA --off
+ - run chk
+ - xrandr --verbose will now not report any outputs as turned on
+ - run chk again - all screens will be turned off
+
+ - Small Sun monitor - an 1152x921 mode is generated, but the
+ monitor doesn't handle that. The monitor itself only claims to
+ handle 1152x920. It doesn't look to me like there is anything
+ in the EDID information that would indicate that it could handle
+ 1152x921.
+
+ This happens with a radeon as wellso it may be a bug in the
+ generic X server EDID parsing. The X server apparently
+ interpretes the standard timing 1152x920 as 1152x921.
+
+ This happens because the X server uses
+
+ hsize * 4 / 5
+
+ which gives 921 for 1152. By using
+
+ (hsize / 5) * 4
+
+ you get 920. The 66 Hz version can bet set, the 76 Hz mode gets
+ sync out of range. (Would be interesting to find out whether the
+ 1152x920 ModeLine would allow the 76 Hz version to be set).
+
+ This is for the ATI driver as shipped in F8:
+
+ - XRRGetScreenResources() takes half a second.
+
+ - Adam has now removed a workaround that caused some of the slowdown.
+
+ - If a DVI monitor is disconnected, you get "Unknown" for connection
+ status.
+
+ - If a VGA monitor is plugged in, then EDID information is not
+ available, even after running xrandr --verbose. The monitor has
+ to be plugged in at driver startup time, apparently.
+
+ - Logging out and logging back in often results in some random mode being
+ set. We need mode selection to not be completely screwed up.
+ Currently it is.
+
+ - The set up at server startup needs to be fixed. *If* randr actually works,
+ then we might be able to do something sensible.
+
+ - We need to revisit the idea that many monitors have broken EDID data.
+ This may be less widespread than previously believed.
+
+- It may be useful to return the connector names as identifiers instead
+ of relying on UTF-8 strings. Ie., have an enum
+
+ { UNKNOWN, OTHER, DVI, VGA, HDMI, ..., }
+
+ in addition to the string. The difference between UNKNOWN and OTHER is that
+ UNKNOWN means the driver doesn't know, whereas OTHER means it is something
+ not listed in the enum (which could be listed in a later version).
+
+- Mouse cursor should be confined to the visible area. (It is already, I think)
+
+- It looks like EDID information is only available for one output
+ even though it is actually read according to the log file.
+ (nv, intel drivers)
+
+
+*********************************
+
+
+
+DONE:
+
+Server work:
+
+ - i830 laptop incorrectly reports BadMatch when you configure the
+ CRTC to drive both VGA and LVDS with the 1024x768 mode that both
+ outputs can handle. (It should return 'failed' if it can't do
+ that). Same for i945 laptop. It seems as if the same CRTC can't
+ drive more than one output at the same time on Intel.
+
+ This was a client bug, but the documentation for SetCrtcConfig
+ should say that BadMatch will be returned if the outputs aren't
+ clones.
+
+GTK+ patch is in now.
+
+=== Add helper function
+
+
++ if (screen_x11->randr12)
++ {
++ XRRScreenResources *sr;
++ XRROutputInfo *output;
++ gchar *retval;
++
++ sr = XRRGetScreenResources ( screen_x11->xdisplay,
++ screen_x11->xroot_window );
++
++ output = XRRGetOutputInfo ( screen_x11->xdisplay,
++ sr,
++ (RROutput)screen_x11->act_outputs[monitor_num]
+);
+
+ Might be worthwhile to factor this out into a
+ gdk_screen_get_output_info (screen, monitor_num)
+ helper function ?
+
+Instead of cutting and pasting all over creation
+
+* Calling XRRGetScreenResources all the time is not going to fly. It
+ takes hundreds of milliseconds ... Even if it didn't, it wouldn't
+ be acceptable to do all those roundtrips.
+
+
+=== Some g_prints left
+
+
+=== Version check
+
+Should be (maj > 1) || (maj == 1 && min >= 2)
+
+
+=== Grep for TODO
+
+
+=== Setup XRRSelectInput()
+
+ You should call XRRSelectInput() at the same place where you are
+ calling XSelectInput() right now. The right place to handle the
+ XRandr events is the huge switch in gdkevents-x11.c:gdk_event_translate
+ Check out how other extension events are handled there, like
+ XKB, or XFixes.
+
+
+=== Lots of variable naming issues, such as act_output and noutput
+
+=== Needs to select the input, and hook it up to the signal
+
+=== Add version markers to API
+
+=== API to turn monitors on and off?
+
+- DPMS not exposed through randr, maybe should be
+
+ - DPMS is presumably a property of either an
+ output or a CRTC. Logically it's an output.
+
+- Need events when DPMS happens. Exposing the "screen saving on" on
+ dbus may not be good enough.
+
+=== Why does init_multihead_support() start by freeing monitors and
+outputs?
+
+=== Do we disable Xinerama support entirely when 1.2 is in use?
+
+=== We should expose information about what parts of the screen monitors
+are viewing.
+
+=== Make use of the EDID information?
+
+
+-- details for X server --
+
+In nv driver SorSetOutputProperty should return TRUE for unknown
+properties. (Like the Intel driver does).
+
+Detecting plugged in
+
+- Periodically poll
+ -
+
+ - One ddc probe takes 5 ms, according to a comment in the intel
+ driver. Running this twice a second would mean spending 1% of
+ overall time doing ddc polling, which is almost certainly not
+ acceptable.
+
+ 1) Async I2C:
+
+ void I2CProbeAsync(..., callback, data);
+ Bool I2CPending()
+ void I2CUpdate()
+
+ In Dispatch, call I2CUpdate()
+ Before going idle, do
+
+ while (I2CPending())
+ I2CUpdate()
+
+ Would need
+ RegisterDispatchFunction() (Is this called Wakeup?)
+ RegisterIdleFunction()
+
+ Note the idle function should have the option of saying:
+ "check if something else happened; if not, call me again" and
+ "ok, I'm done - go idle". Otherwise, we would be blocking for
+ 5 ms whenever the X server went idle. So actually the idle
+ function should be
+
+ if (I2CPending())
+ {
+ I2CUpdate();
+ return TRUE; /* call me again */
+ }
+ else
+ {
+ return FALSE; /* I'm done */
+ }
+
+ What happens if another I2C requests come in while an async one
+ is pending? Most likely we simply finish whatever is going on,
+ then process the new request.
+
+ What happens if an X request takes so long that we get timeouts on
+ the i2c bus? Good question. Need to read the VESA ddc spec.
+
+ 2) Run the polling in a separate thread.
+
+ Probably crack.
+
+ 3) Run the polling less, maybe once every three seconds.
+
+-- details for control panel --
+Screen changes
+ - Currently it is polling via rw_screen_refresh(), which will always emit
+ a screen-changed event. In reponse to this event the capplet currently
+ checks whether anything changed physically about the setup. This means
+ the capplet can't react to external changes to modes. On the other hand
+ if it didn't
+Disallow combinations that would exceed the screen ranges.
+ - Note rotations
+
+Give rw objects stable positions in memory so that they can be cached
+across screen_changed events.
+
+Add Clone Mode
+
+Drag and drop for the monitors
+ - 2 dimensional layout
+
+Store make and model in monitors.xml, then if serial numbers don't
+match, fall back to a make and model match. Users with an nfs mounted
+home directory should not have to reconfigure for each new system they
+log in to.
+
+Make sure text is scaled correctly
+
+Need to sanitize naming
+ RWOutput vs Output - should probably be OutputInfo
+ rate vs. freq - decide on one
+
+Should probably reconsider the use of null terminated arrays.
+Maybe lists would be better.
+
+Pick a fixed scale, so that two 1024x768 don't look like two 6x4.
+ - An alternative would be to draw a checkerboard pattern
+ below the monitors.
+
+
+
+done:
+
+Add rotation
+
+Disable panel checkbox for now
+
+Patch into mate-desktop
+
+Find out how to share code between gcc and gsd
+
+Make it assign coordinates correctly
+ - including computing correct screen size
+
diff --git a/capplets/display/display-capplet.ui b/capplets/display/display-capplet.ui
new file mode 100644
index 00000000..82ed92bd
--- /dev/null
+++ b/capplets/display/display-capplet.ui
@@ -0,0 +1,437 @@
+<?xml version="1.0"?>
+<interface>
+ <requires lib="gtk+" version="2.16"/>
+ <!-- interface-naming-policy toplevel-contextual -->
+ <object class="GtkDialog" id="dialog">
+ <property name="border_width">5</property>
+ <property name="title" translatable="yes">Monitor Preferences</property>
+ <property name="type_hint">dialog</property>
+ <property name="has_separator">False</property>
+ <child internal-child="vbox">
+ <object class="GtkVBox" id="dialog-vbox1">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">2</property>
+ <child>
+ <object class="GtkTable" id="table2">
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">12</property>
+ <child>
+ <object class="GtkVBox" id="vbox3">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkAlignment" id="align">
+ <property name="visible">True</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox1">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkCheckButton" id="clone_checkbox">
+ <property name="label" translatable="yes">Sa_me image in all monitors</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="detect_displays_button">
+ <property name="label" translatable="yes">_Detect monitors</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox4">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel" id="label8">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Panel icon</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment2">
+ <property name="visible">True</property>
+ <property name="left_padding">12</property>
+ <child>
+ <object class="GtkCheckButton" id="show_notification_icon">
+ <property name="label" translatable="yes">_Show monitors in panel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment1">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0</property>
+ <child>
+ <object class="GtkTable" id="table1">
+ <property name="visible">True</property>
+ <property name="n_rows">6</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Resolution:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">resolution_combo</property>
+ </object>
+ <packing>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Re_fresh rate:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">refresh_combo</property>
+ </object>
+ <packing>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBox" id="resolution_combo">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBox" id="refresh_combo">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox2">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkRadioButton" id="monitor_on_radio">
+ <property name="label" translatable="yes">On</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="monitor_off_radio">
+ <property name="label" translatable="yes">Off</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">monitor_on_radio</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEventBox" id="current_monitor_event_box">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkLabel" id="current_monitor_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Monitor</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="right_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label5">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">R_otation:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">rotation_combo</property>
+ </object>
+ <packing>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBox" id="rotation_combo">
+ <property name="visible">True</property>
+ <property name="model">liststore1</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderertext1"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="panel_checkbox">
+ <property name="label" translatable="yes">Include _panel</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="top_attach">5</property>
+ <property name="bottom_attach">6</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment4">
+ <property name="visible">True</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">5</property>
+ <property name="bottom_attach">6</property>
+ <property name="x_options"></property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="x_options"></property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <object class="GtkHButtonBox" id="dialog-action_area1">
+ <property name="visible">True</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="helpbutton1">
+ <property name="label">gtk-help</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ <property name="secondary">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="make_default_button">
+ <property name="label" translatable="yes">Make Default</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="apply_button">
+ <property name="label">gtk-apply</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="button2">
+ <property name="label">gtk-close</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-11">helpbutton1</action-widget>
+ <action-widget response="1">make_default_button</action-widget>
+ <action-widget response="-10">apply_button</action-widget>
+ <action-widget response="-7">button2</action-widget>
+ </action-widgets>
+ </object>
+ <object class="GtkListStore" id="liststore1">
+ <columns>
+ <!-- column-name item -->
+ <column type="gchararray"/>
+ </columns>
+ <data>
+ <row>
+ <col id="0" translatable="yes">Normal</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">Left</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">Right</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">Upside-down</col>
+ </row>
+ </data>
+ </object>
+</interface>
diff --git a/capplets/display/display-properties.desktop.in.in b/capplets/display/display-properties.desktop.in.in
new file mode 100644
index 00000000..bcfb5935
--- /dev/null
+++ b/capplets/display/display-properties.desktop.in.in
@@ -0,0 +1,14 @@
+[Desktop Entry]
+_Name=Monitors
+_Comment=Change resolution and position of monitors
+Exec=mate-display-properties
+Icon=mate-preferences-desktop-display
+Terminal=false
+Type=Application
+StartupNotify=true
+Categories=MATE;GTK;Settings;HardwareSettings;
+OnlyShowIn=MATE;
+X-MATE-Bugzilla-Bugzilla=MATE
+X-MATE-Bugzilla-Product=mate-control-center
+X-MATE-Bugzilla-Component=Screen resolution
+X-MATE-Bugzilla-Version=@VERSION@
diff --git a/capplets/display/foo-marshal.c b/capplets/display/foo-marshal.c
new file mode 100644
index 00000000..a40b0863
--- /dev/null
+++ b/capplets/display/foo-marshal.c
@@ -0,0 +1,279 @@
+
+#include <glib-object.h>
+
+
+#ifdef G_ENABLE_DEBUG
+#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v)
+#define g_marshal_value_peek_char(v) g_value_get_char (v)
+#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v)
+#define g_marshal_value_peek_int(v) g_value_get_int (v)
+#define g_marshal_value_peek_uint(v) g_value_get_uint (v)
+#define g_marshal_value_peek_long(v) g_value_get_long (v)
+#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v)
+#define g_marshal_value_peek_int64(v) g_value_get_int64 (v)
+#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v)
+#define g_marshal_value_peek_enum(v) g_value_get_enum (v)
+#define g_marshal_value_peek_flags(v) g_value_get_flags (v)
+#define g_marshal_value_peek_float(v) g_value_get_float (v)
+#define g_marshal_value_peek_double(v) g_value_get_double (v)
+#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v)
+#define g_marshal_value_peek_param(v) g_value_get_param (v)
+#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v)
+#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v)
+#define g_marshal_value_peek_object(v) g_value_get_object (v)
+#else /* !G_ENABLE_DEBUG */
+/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API.
+ * Do not access GValues directly in your code. Instead, use the
+ * g_value_get_*() functions
+ */
+#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int
+#define g_marshal_value_peek_char(v) (v)->data[0].v_int
+#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint
+#define g_marshal_value_peek_int(v) (v)->data[0].v_int
+#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint
+#define g_marshal_value_peek_long(v) (v)->data[0].v_long
+#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong
+#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64
+#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64
+#define g_marshal_value_peek_enum(v) (v)->data[0].v_long
+#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong
+#define g_marshal_value_peek_float(v) (v)->data[0].v_float
+#define g_marshal_value_peek_double(v) (v)->data[0].v_double
+#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer
+#endif /* !G_ENABLE_DEBUG */
+
+
+/* VOID:OBJECT,OBJECT (marshal.list:1) */
+void
+foo_marshal_VOID__OBJECT_OBJECT (GClosure *closure,
+ GValue *return_value G_GNUC_UNUSED,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint G_GNUC_UNUSED,
+ gpointer marshal_data)
+{
+ typedef void (*GMarshalFunc_VOID__OBJECT_OBJECT) (gpointer data1,
+ gpointer arg_1,
+ gpointer arg_2,
+ gpointer data2);
+ register GMarshalFunc_VOID__OBJECT_OBJECT callback;
+ register GCClosure *cc = (GCClosure*) closure;
+ register gpointer data1, data2;
+
+ g_return_if_fail (n_param_values == 3);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ }
+ else
+ {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback = (GMarshalFunc_VOID__OBJECT_OBJECT) (marshal_data ? marshal_data : cc->callback);
+
+ callback (data1,
+ g_marshal_value_peek_object (param_values + 1),
+ g_marshal_value_peek_object (param_values + 2),
+ data2);
+}
+
+/* VOID:UINT,UINT,UINT,UINT (marshal.list:2) */
+void
+foo_marshal_VOID__UINT_UINT_UINT_UINT (GClosure *closure,
+ GValue *return_value G_GNUC_UNUSED,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint G_GNUC_UNUSED,
+ gpointer marshal_data)
+{
+ typedef void (*GMarshalFunc_VOID__UINT_UINT_UINT_UINT) (gpointer data1,
+ guint arg_1,
+ guint arg_2,
+ guint arg_3,
+ guint arg_4,
+ gpointer data2);
+ register GMarshalFunc_VOID__UINT_UINT_UINT_UINT callback;
+ register GCClosure *cc = (GCClosure*) closure;
+ register gpointer data1, data2;
+
+ g_return_if_fail (n_param_values == 5);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ }
+ else
+ {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback = (GMarshalFunc_VOID__UINT_UINT_UINT_UINT) (marshal_data ? marshal_data : cc->callback);
+
+ callback (data1,
+ g_marshal_value_peek_uint (param_values + 1),
+ g_marshal_value_peek_uint (param_values + 2),
+ g_marshal_value_peek_uint (param_values + 3),
+ g_marshal_value_peek_uint (param_values + 4),
+ data2);
+}
+
+/* VOID:UINT,UINT (marshal.list:3) */
+void
+foo_marshal_VOID__UINT_UINT (GClosure *closure,
+ GValue *return_value G_GNUC_UNUSED,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint G_GNUC_UNUSED,
+ gpointer marshal_data)
+{
+ typedef void (*GMarshalFunc_VOID__UINT_UINT) (gpointer data1,
+ guint arg_1,
+ guint arg_2,
+ gpointer data2);
+ register GMarshalFunc_VOID__UINT_UINT callback;
+ register GCClosure *cc = (GCClosure*) closure;
+ register gpointer data1, data2;
+
+ g_return_if_fail (n_param_values == 3);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ }
+ else
+ {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback = (GMarshalFunc_VOID__UINT_UINT) (marshal_data ? marshal_data : cc->callback);
+
+ callback (data1,
+ g_marshal_value_peek_uint (param_values + 1),
+ g_marshal_value_peek_uint (param_values + 2),
+ data2);
+}
+
+/* VOID:BOXED (marshal.list:4) */
+
+/* VOID:BOXED,BOXED (marshal.list:5) */
+void
+foo_marshal_VOID__BOXED_BOXED (GClosure *closure,
+ GValue *return_value G_GNUC_UNUSED,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint G_GNUC_UNUSED,
+ gpointer marshal_data)
+{
+ typedef void (*GMarshalFunc_VOID__BOXED_BOXED) (gpointer data1,
+ gpointer arg_1,
+ gpointer arg_2,
+ gpointer data2);
+ register GMarshalFunc_VOID__BOXED_BOXED callback;
+ register GCClosure *cc = (GCClosure*) closure;
+ register gpointer data1, data2;
+
+ g_return_if_fail (n_param_values == 3);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ }
+ else
+ {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback = (GMarshalFunc_VOID__BOXED_BOXED) (marshal_data ? marshal_data : cc->callback);
+
+ callback (data1,
+ g_marshal_value_peek_boxed (param_values + 1),
+ g_marshal_value_peek_boxed (param_values + 2),
+ data2);
+}
+
+/* VOID:POINTER,BOXED,POINTER (marshal.list:6) */
+void
+foo_marshal_VOID__POINTER_BOXED_POINTER (GClosure *closure,
+ GValue *return_value G_GNUC_UNUSED,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint G_GNUC_UNUSED,
+ gpointer marshal_data)
+{
+ typedef void (*GMarshalFunc_VOID__POINTER_BOXED_POINTER) (gpointer data1,
+ gpointer arg_1,
+ gpointer arg_2,
+ gpointer arg_3,
+ gpointer data2);
+ register GMarshalFunc_VOID__POINTER_BOXED_POINTER callback;
+ register GCClosure *cc = (GCClosure*) closure;
+ register gpointer data1, data2;
+
+ g_return_if_fail (n_param_values == 4);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ }
+ else
+ {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback = (GMarshalFunc_VOID__POINTER_BOXED_POINTER) (marshal_data ? marshal_data : cc->callback);
+
+ callback (data1,
+ g_marshal_value_peek_pointer (param_values + 1),
+ g_marshal_value_peek_boxed (param_values + 2),
+ g_marshal_value_peek_pointer (param_values + 3),
+ data2);
+}
+
+/* VOID:POINTER,POINTER (marshal.list:7) */
+void
+foo_marshal_VOID__POINTER_POINTER (GClosure *closure,
+ GValue *return_value G_GNUC_UNUSED,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint G_GNUC_UNUSED,
+ gpointer marshal_data)
+{
+ typedef void (*GMarshalFunc_VOID__POINTER_POINTER) (gpointer data1,
+ gpointer arg_1,
+ gpointer arg_2,
+ gpointer data2);
+ register GMarshalFunc_VOID__POINTER_POINTER callback;
+ register GCClosure *cc = (GCClosure*) closure;
+ register gpointer data1, data2;
+
+ g_return_if_fail (n_param_values == 3);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ }
+ else
+ {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback = (GMarshalFunc_VOID__POINTER_POINTER) (marshal_data ? marshal_data : cc->callback);
+
+ callback (data1,
+ g_marshal_value_peek_pointer (param_values + 1),
+ g_marshal_value_peek_pointer (param_values + 2),
+ data2);
+}
+
diff --git a/capplets/display/foo-marshal.h b/capplets/display/foo-marshal.h
new file mode 100644
index 00000000..4bef795d
--- /dev/null
+++ b/capplets/display/foo-marshal.h
@@ -0,0 +1,67 @@
+
+#ifndef __foo_marshal_MARSHAL_H__
+#define __foo_marshal_MARSHAL_H__
+
+#include <glib-object.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* VOID:OBJECT,OBJECT (marshal.list:1) */
+extern void foo_marshal_VOID__OBJECT_OBJECT (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+
+/* VOID:UINT,UINT,UINT,UINT (marshal.list:2) */
+extern void foo_marshal_VOID__UINT_UINT_UINT_UINT (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+
+/* VOID:UINT,UINT (marshal.list:3) */
+extern void foo_marshal_VOID__UINT_UINT (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+
+/* VOID:BOXED (marshal.list:4) */
+#define foo_marshal_VOID__BOXED g_cclosure_marshal_VOID__BOXED
+
+/* VOID:BOXED,BOXED (marshal.list:5) */
+extern void foo_marshal_VOID__BOXED_BOXED (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+
+/* VOID:POINTER,BOXED,POINTER (marshal.list:6) */
+extern void foo_marshal_VOID__POINTER_BOXED_POINTER (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+
+/* VOID:POINTER,POINTER (marshal.list:7) */
+extern void foo_marshal_VOID__POINTER_POINTER (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __foo_marshal_MARSHAL_H__ */
+
diff --git a/capplets/display/icons/16x16/mate-preferences-desktop-display.png b/capplets/display/icons/16x16/mate-preferences-desktop-display.png
new file mode 100644
index 00000000..f996ddf5
--- /dev/null
+++ b/capplets/display/icons/16x16/mate-preferences-desktop-display.png
Binary files differ
diff --git a/capplets/display/icons/22x22/mate-preferences-desktop-display.png b/capplets/display/icons/22x22/mate-preferences-desktop-display.png
new file mode 100644
index 00000000..cc47eec6
--- /dev/null
+++ b/capplets/display/icons/22x22/mate-preferences-desktop-display.png
Binary files differ
diff --git a/capplets/display/icons/24x24/mate-preferences-desktop-display.png b/capplets/display/icons/24x24/mate-preferences-desktop-display.png
new file mode 100644
index 00000000..49b4e12c
--- /dev/null
+++ b/capplets/display/icons/24x24/mate-preferences-desktop-display.png
Binary files differ
diff --git a/capplets/display/icons/32x32/mate-preferences-desktop-display.png b/capplets/display/icons/32x32/mate-preferences-desktop-display.png
new file mode 100644
index 00000000..95de3eaa
--- /dev/null
+++ b/capplets/display/icons/32x32/mate-preferences-desktop-display.png
Binary files differ
diff --git a/capplets/display/icons/scalable/mate-preferences-desktop-display.svg b/capplets/display/icons/scalable/mate-preferences-desktop-display.svg
new file mode 100644
index 00000000..0679b6b3
--- /dev/null
+++ b/capplets/display/icons/scalable/mate-preferences-desktop-display.svg
@@ -0,0 +1,470 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="48.000000px"
+ height="48.000000px"
+ id="svg3304"
+ sodipodi:version="0.32"
+ inkscape:version="0.44+devel"
+ sodipodi:docbase="/home/jimmac/gfx/ximian/art/icons/control-center/scalable"
+ sodipodi:docname="change-resolution.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ sodipodi:modified="true">
+ <defs
+ id="defs3306">
+ <linearGradient
+ id="linearGradient2804">
+ <stop
+ style="stop-color:black;stop-opacity:0;"
+ offset="0"
+ id="stop2806" />
+ <stop
+ id="stop2812"
+ offset="0.5"
+ style="stop-color:black;stop-opacity:1;" />
+ <stop
+ style="stop-color:black;stop-opacity:0;"
+ offset="1"
+ id="stop2808" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2804"
+ id="linearGradient2831"
+ gradientUnits="userSpaceOnUse"
+ x1="21.875"
+ y1="48.000977"
+ x2="21.875"
+ y2="40" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2781"
+ id="radialGradient2829"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(2,0,0,0.8,36,8.8)"
+ cx="1"
+ cy="44"
+ fx="1"
+ fy="44"
+ r="5" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient2781">
+ <stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0"
+ id="stop2783" />
+ <stop
+ style="stop-color:black;stop-opacity:0;"
+ offset="1"
+ id="stop2785" />
+ </linearGradient>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2781"
+ id="radialGradient2827"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(2,0,0,0.8,-13,-79.2)"
+ cx="1"
+ cy="44"
+ fx="1"
+ fy="44"
+ r="5" />
+ <linearGradient
+ id="linearGradient5137">
+ <stop
+ style="stop-color:#eeeeec;stop-opacity:1;"
+ offset="0"
+ id="stop5139" />
+ <stop
+ style="stop-color:#e6e6e3;stop-opacity:1;"
+ offset="1"
+ id="stop5141" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient6240">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop6242" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop6244" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient11400">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop11402" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop11404" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient11400"
+ id="linearGradient11406"
+ x1="23.154902"
+ y1="34.572548"
+ x2="23.529411"
+ y2="40.219608"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(0,0.7954955)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5137"
+ id="linearGradient5147"
+ gradientUnits="userSpaceOnUse"
+ x1="17.247635"
+ y1="6.3760414"
+ x2="39.904388"
+ y2="38.876041"
+ gradientTransform="translate(0,0.7954955)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5137"
+ id="linearGradient5223"
+ gradientUnits="userSpaceOnUse"
+ x1="31.743324"
+ y1="37.842293"
+ x2="31.86105"
+ y2="43.82579"
+ gradientTransform="translate(0,0.7954955)" />
+ <linearGradient
+ id="linearGradient7025"
+ inkscape:collect="always">
+ <stop
+ id="stop7027"
+ offset="0"
+ style="stop-color:#e6ce46;stop-opacity:1" />
+ <stop
+ id="stop7029"
+ offset="1"
+ style="stop-color:#d6ba1c;stop-opacity:1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient22122"
+ inkscape:collect="always">
+ <stop
+ id="stop22124"
+ offset="0"
+ style="stop-color:black;stop-opacity:1;" />
+ <stop
+ id="stop22126"
+ offset="1"
+ style="stop-color:black;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient22140">
+ <stop
+ id="stop22142"
+ offset="0"
+ style="stop-color:black;stop-opacity:0;" />
+ <stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0.5"
+ id="stop22148" />
+ <stop
+ id="stop22144"
+ offset="1"
+ style="stop-color:black;stop-opacity:0;" />
+ </linearGradient>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient22122"
+ id="radialGradient4770"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0,-1.000001,1.142856,0,-41.10259,45.50001)"
+ cx="7"
+ cy="39.464806"
+ fx="7"
+ fy="39.464806"
+ r="3.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient22122"
+ id="radialGradient4772"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0,-1.000001,1.142856,0,-89.10259,-31.49999)"
+ cx="7"
+ cy="39.464806"
+ fx="7"
+ fy="39.464806"
+ r="3.5" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient22140"
+ id="linearGradient4774"
+ gradientUnits="userSpaceOnUse"
+ x1="18.142136"
+ y1="35"
+ x2="18.142136"
+ y2="42.040661" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient7025"
+ id="linearGradient4776"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(53,1.428571)"
+ x1="13.630114"
+ y1="28.5"
+ x2="25.208096"
+ y2="41.180992" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient6240"
+ id="linearGradient4778"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(7.843e-3,0.7954955)"
+ x1="20.156862"
+ y1="5.0996137"
+ x2="20.156862"
+ y2="26.039215" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#849193"
+ borderopacity="1.0000000"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="1"
+ inkscape:cx="39.697787"
+ inkscape:cy="26.598514"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:grid-bbox="true"
+ inkscape:document-units="px"
+ inkscape:showpageshadow="false"
+ showborder="true"
+ inkscape:window-width="923"
+ inkscape:window-height="937"
+ inkscape:window-x="2004"
+ inkscape:window-y="169"
+ showguides="true"
+ inkscape:guide-bbox="true"
+ inkscape:grid-points="true" />
+ <metadata
+ id="metadata3309">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title>Change Resolution</dc:title>
+ <dc:creator>
+ <cc:Agent>
+ <dc:title>Jakub Steiner</dc:title>
+ </cc:Agent>
+ </dc:creator>
+ <cc:license
+ rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" />
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>display</rdf:li>
+ <rdf:li>resolution</rdf:li>
+ <rdf:li>video</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:contributor>
+ <cc:Agent>
+ <dc:title>Andreas Nilsson
+Luca Ferretti &lt;[email protected]&gt;</dc:title>
+ </cc:Agent>
+ </dc:contributor>
+ <dc:date></dc:date>
+ <dc:source>http://www.gnome.org</dc:source>
+ </cc:Work>
+ <cc:License
+ rdf:about="http://creativecommons.org/licenses/GPL/2.0/">
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Reproduction" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Distribution" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/Notice" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/ShareAlike" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/SourceCode" />
+ </cc:License>
+ </rdf:RDF>
+ </metadata>
+ <g
+ id="layer1"
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer">
+ <g
+ id="g2822"
+ style="opacity:0.3"
+ transform="matrix(0.9308511,0,0,1.037397,1.6941489,-1.795056)">
+ <rect
+ transform="scale(-1,-1)"
+ y="-48"
+ x="-11"
+ height="8"
+ width="10"
+ id="rect1892"
+ style="opacity:1;color:#000000;fill:url(#radialGradient2827);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ y="40"
+ x="38"
+ height="8"
+ width="10"
+ id="rect2789"
+ style="opacity:1;color:#000000;fill:url(#radialGradient2829);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ y="40"
+ x="11"
+ height="8"
+ width="27"
+ id="rect2793"
+ style="opacity:1;color:#000000;fill:url(#linearGradient2831);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ </g>
+ <rect
+ style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect4784"
+ width="48"
+ height="48"
+ x="0"
+ y="0.79549509" />
+ <path
+ style="opacity:1;color:#000000;fill:url(#linearGradient5223);fill-opacity:1;fill-rule:evenodd;stroke:#888a85;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 14.375479,36.328843 C 14.375479,36.328843 15.592355,41.263443 10.51915,41.309767 C 8.0888743,41.331672 8.5866723,45.344918 8.5866723,45.344918 L 39.433139,45.313545 C 39.433139,45.313545 39.851577,41.418182 37.410922,41.372513 C 32.423455,41.280374 33.600393,36.266098 33.600393,36.266098 L 14.375479,36.328843 z "
+ id="path9222"
+ sodipodi:nodetypes="csccscc" />
+ <path
+ style="fill:url(#linearGradient5147);fill-opacity:1;fill-rule:evenodd;stroke:#888a85;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1"
+ d="M 4.8886262,4.2739318 L 43.01746,4.2739318 C 45.042579,4.2739318 46.518438,5.7015863 46.518438,7.9000726 L 46.529388,34.103908 C 46.529388,35.795975 46.001041,36.319137 44.494732,36.319137 L 3.5320635,36.300202 C 2.3527922,36.271409 1.513468,35.805541 1.4976345,34.280899 L 1.5128113,7.7123281 C 1.5128113,5.9385022 3.0522187,4.2739318 4.8886262,4.2739318 z "
+ id="rect5040"
+ sodipodi:nodetypes="ccccccccc" />
+ <rect
+ style="fill:#555753;fill-opacity:1;fill-rule:evenodd;stroke:#2e3436;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect9208"
+ width="37.00032"
+ height="22.996691"
+ x="5.5059438"
+ y="8.2973185" />
+ <path
+ sodipodi:type="inkscape:offset"
+ inkscape:radius="-0.875"
+ inkscape:original="M 4.875 4.28125 C 3.0385925 4.28125 1.5 5.9449242 1.5 7.71875 L 1.5 34.28125 C 1.5158335 35.805892 2.3519787 36.283708 3.53125 36.3125 L 44.5 36.3125 C 46.006309 36.3125 46.53125 35.785816 46.53125 34.09375 L 46.53125 7.90625 C 46.53125 5.7077637 45.056369 4.2812498 43.03125 4.28125 L 4.875 4.28125 z "
+ xlink:href="#rect5040"
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1"
+ id="path5145"
+ inkscape:href="#rect5040"
+ d="M 4.875,5.0625 C 3.5670573,5.0625 2.375,6.3571498 2.375,7.625 L 2.375,34.1875 C 2.3812657,34.79084 2.515801,34.970853 2.65625,35.09375 C 2.796699,35.216647 3.0858905,35.332113 3.5625,35.34375 L 44.5,35.34375 C 45.151173,35.34375 45.356981,35.24273 45.4375,35.15625 C 45.518019,35.06977 45.65625,34.755549 45.65625,34 L 45.65625,7.8125 C 45.65625,6.0053499 44.645463,5.0624999 43.03125,5.0625 L 4.875,5.0625 z " />
+ <path
+ style="opacity:0.6;fill:url(#linearGradient11406);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 13.992156,36.834708 C 14.075817,39.007257 13.708803,39.746151 12.358532,40.509939 L 35.973934,41.807257 C 35.024915,40.638629 33.644523,38.873923 34.020993,36.819022 L 13.992156,36.834708 z "
+ id="path10672"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#8d8d8f;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:0.43902438"
+ d="M 9.9921262,42.291555 C 16.698819,42.293524 37.78891,42.291555 37.78891,42.291555"
+ id="path6575"
+ sodipodi:nodetypes="cc" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path8029"
+ d="M 9.647928,43.299429 C 16.354621,43.301398 38.367789,43.299429 38.367789,43.299429"
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ style="opacity:0.4;fill:url(#linearGradient4778);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 6.031372,8.8268676 L 6.031372,26.834708 C 22.475817,25.480459 28.630065,16.722289 41.999999,15.807256 L 42,8.7954956 L 6.031372,8.8268676 z "
+ id="path4073"
+ sodipodi:nodetypes="ccccc" />
+ <g
+ id="g4754"
+ transform="translate(-46.77135,-7.3370294)">
+ <g
+ transform="matrix(0.916667,0,0,0.714282,49.771334,11.132681)"
+ style="opacity:0.3"
+ id="g22150">
+ <rect
+ style="opacity:1;fill:url(#radialGradient4770);fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1"
+ id="rect22120"
+ width="4"
+ height="7"
+ x="0"
+ y="35" />
+ <rect
+ style="opacity:1;fill:url(#radialGradient4772);fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1"
+ id="rect22134"
+ width="4"
+ height="7"
+ x="-48"
+ y="-42"
+ transform="scale(-1,-1)" />
+ <rect
+ style="opacity:1;fill:url(#linearGradient4774);fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1"
+ id="rect22138"
+ width="40"
+ height="7"
+ x="4"
+ y="35" />
+ </g>
+ <g
+ id="g4743">
+ <g
+ id="g10824"
+ transform="translate(-5.228666,-6.29601)">
+ <path
+ id="path4319"
+ d="M 57.5,14.928571 L 57.5,44.928571 L 96.5,44.928571 L 57.5,14.928571 z M 63.5,27.928571 L 78.5,38.928571 L 63.5,38.928571 L 63.5,27.928571 z "
+ style="fill:url(#linearGradient4776);fill-opacity:1;fill-rule:evenodd;stroke:#a38503;stroke-width:1.00000024px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path4326"
+ d="M 61.5,44.928571 L 61.5,41.928571"
+ style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#a38503;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path4328"
+ d="M 67.5,44.928571 L 67.5,41.928571"
+ style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#a38503;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path4330"
+ d="M 73.5,44.928571 L 73.5,41.964285"
+ style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#a38503;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path4332"
+ d="M 79.5,44.928571 L 79.5,41.928571"
+ style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#a38503;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path4334"
+ d="M 85.5,44.928571 L 85.5,41.928571"
+ style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#a38503;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ id="path6126"
+ d="M 58.500002,16.928575 L 58.500002,43.928586 L 93.500014,43.928586 L 58.500002,16.928575 z "
+ style="opacity:0.4;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.0000006px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ </g>
+ <path
+ style="opacity:0.4;fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#ffffff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 9.5017474,38.542446 L 9.4575532,24.532894 L 28.541592,38.563262 L 9.5017474,38.542446 z "
+ id="path12221"
+ sodipodi:nodetypes="cccc"
+ transform="translate(47.771334,-4.867439)" />
+ </g>
+ </g>
+ </g>
+</svg>
diff --git a/capplets/display/mate-display-properties-install-systemwide.c b/capplets/display/mate-display-properties-install-systemwide.c
new file mode 100644
index 00000000..2d074eb8
--- /dev/null
+++ b/capplets/display/mate-display-properties-install-systemwide.c
@@ -0,0 +1,272 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * mate-display-properties-install-systemwide - Install a RANDR profile for the whole system
+ *
+ * Copyright (C) 2010 Novell, Inc.
+ *
+ * Authors: Federico Mena Quintero <[email protected]>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include <errno.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <glib/gi18n.h>
+#include <glib.h>
+
+#define SYSTEM_RANDR_PATH "/etc/mate-settings-daemon/xrandr"
+
+static void
+usage (const char *program_name)
+{
+ g_print (_("Usage: %s SOURCE_FILE DEST_NAME\n"
+ "\n"
+ "This program installs a RANDR profile for multi-monitor setups into\n"
+ "a systemwide location. The resulting profile will get used when\n"
+ "the RANDR plug-in gets run in mate-settings-daemon.\n"
+ "\n"
+ "SOURCE_FILE - a full pathname, typically /home/username/.config/monitors.xml\n"
+ "\n"
+ "DEST_NAME - relative name for the installed file. This will get put in\n"
+ " the systemwide directory for RANDR configurations,\n"
+ " so the result will typically be %s/DEST_NAME\n"),
+ program_name,
+ SYSTEM_RANDR_PATH);
+}
+
+static gboolean
+is_basename (const char *filename)
+{
+ if (*filename == '\0')
+ return FALSE; /* no empty strings, please */
+
+ for (; *filename; filename++)
+ if (G_IS_DIR_SEPARATOR (*filename))
+ return FALSE;
+
+ return TRUE;
+}
+
+static gboolean
+copy_file (int source_fd, int dest_fd)
+{
+ char buf[1024];
+ int num_read;
+ int num_written;
+
+ while (TRUE) {
+ char *p;
+
+ num_read = read (source_fd, buf, sizeof (buf));
+ if (num_read == 0)
+ break;
+
+ if (num_read == -1) {
+ if (errno == EINTR)
+ continue;
+ else
+ return FALSE;
+ }
+
+ p = buf;
+ while (num_read > 0) {
+ num_written = write (dest_fd, p, num_read);
+ if (num_written == -1) {
+ if (errno == EINTR)
+ continue;
+ else
+ return FALSE;
+ }
+
+ num_read -= num_written;
+ p += num_written;
+ }
+ }
+
+ return TRUE;
+}
+
+/* This is essentially a "please copy a file to a privileged location" program.
+ * We try to be paranoid in the following ways:
+ *
+ * - We copy only regular files, owned by the user who called pkexec(1), to
+ * avoid attacks like "copy a file that I'm not allowed to read into a
+ * world-readable location".
+ *
+ * - We copy only to a well-known directory.
+ *
+ * - We try to avoid race conditions. We only fstat() files that we have open
+ * to avoid files moving under our feet. We only create files in directories
+ * that we have open.
+ *
+ * - We replace the destination file atomically.
+ */
+
+int
+main (int argc, char **argv)
+{
+ uid_t uid, euid;
+ const char *source_filename;
+ const char *dest_name;
+ const char *pkexec_uid_str;
+ int pkexec_uid;
+ struct stat statbuf;
+ int err;
+ int source_fd;
+ int dest_fd;
+ char template[100];
+
+ setlocale (LC_ALL, "");
+ bindtextdomain (GETTEXT_PACKAGE, MATELOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+ textdomain (GETTEXT_PACKAGE);
+
+ /* We only run as root */
+ uid = getuid ();
+ euid = geteuid ();
+ if (uid != 0 || euid != 0) {
+ /* Translators: only able to install RANDR profiles as root */
+ g_print ("%s\n", _("This program can only be used by the root user"));
+ return EXIT_FAILURE;
+ }
+
+ /* Usage: gsd-xrandr-install-systemwide SOURCE_FILE DEST_NAME */
+
+ if (argc != 3) {
+ usage (argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ source_filename = argv[1];
+ dest_name = argv[2];
+
+ /* Absolute source filenames only, please */
+
+ if (!g_path_is_absolute (source_filename)) {
+ g_print ("%s\n", _("The source filename must be absolute"));
+ return EXIT_FAILURE;
+ }
+
+ /* We only copy regular files */
+
+ source_fd = open (source_filename, O_RDONLY);
+ if (source_fd == -1) {
+ err = errno;
+
+ /* Translators: first %s is a filename; second %s is an error message */
+ g_print (_("Could not open %s: %s\n"),
+ source_filename,
+ g_strerror (err));
+ return EXIT_FAILURE;
+ }
+
+ if (fstat (source_fd, &statbuf) != 0) {
+ err = errno;
+ /* Translators: first %s is a filename; second %s is an error message */
+ g_print (_("Could not get information for %s: %s\n"),
+ source_filename,
+ g_strerror (err));
+ return EXIT_FAILURE;
+ }
+
+ if (!S_ISREG (statbuf.st_mode)) {
+ g_print (_("%s must be a regular file\n"),
+ source_filename);
+ return EXIT_FAILURE;
+ }
+
+ /* We only copy files that are really owned by the calling user */
+
+ pkexec_uid_str = g_getenv ("PKEXEC_UID");
+ if (pkexec_uid_str == NULL) {
+ g_print ("%s\n", _("This program must only be run through pkexec(1)"));
+ return EXIT_FAILURE;
+ }
+
+ if (sscanf (pkexec_uid_str, "%d", &pkexec_uid) != 1) {
+ g_print ("%s\n", _("PKEXEC_UID must be set to an integer value"));
+ return EXIT_FAILURE;
+ }
+
+ if (statbuf.st_uid != pkexec_uid) {
+ /* Translators: we are complaining that a file must be really owned by the user who called this program */
+ g_print (_("%s must be owned by you\n"), source_filename);
+ return EXIT_FAILURE;
+ }
+
+ /* We only accept basenames for the destination */
+
+ if (!is_basename (dest_name)) {
+ /* Translators: here we are saying that a plain filename must look like "filename", not like "some_dir/filename" */
+ g_print (_("%s must not have any directory components\n"),
+ dest_name);
+ return EXIT_FAILURE;
+ }
+
+ /* Chdir to the destination directory to keep it open... */
+
+ if (chdir (SYSTEM_RANDR_PATH) != 0) {
+ g_print (_("%s must be a directory\n"), SYSTEM_RANDR_PATH);
+ return EXIT_FAILURE;
+ }
+
+ /* ... and open our temporary destination file right there */
+
+ strcpy (template, "gsd-XXXXXX");
+ dest_fd = g_mkstemp_full (template, O_WRONLY, 0644);
+ if (dest_fd == -1) {
+ err = errno;
+ /* Translators: the first %s/%s is a directory/filename; the last %s is an error message */
+ g_print (_("Could not open %s/%s: %s\n"),
+ SYSTEM_RANDR_PATH,
+ template,
+ g_strerror (err));
+ return EXIT_FAILURE;
+ }
+
+ /* Do the copy */
+
+ if (!copy_file (source_fd, dest_fd)) {
+ /* If something went wrong, remove the destination file to avoid leaving trash around */
+ unlink (template);
+ return EXIT_FAILURE;
+ }
+
+ /* Rename to the final filename */
+
+ if (rename (template, dest_name) != 0) {
+ err = errno;
+ unlink (template);
+ g_print (_("Could not rename %s to %s: %s\n"),
+ template,
+ dest_name,
+ g_strerror (err));
+ return EXIT_FAILURE;
+ }
+
+ /* Whew! We'll leave the final closing of the files to the almighty kernel. */
+
+ return EXIT_SUCCESS;
+}
diff --git a/capplets/display/org.mate.randr.policy.in b/capplets/display/org.mate.randr.policy.in
new file mode 100644
index 00000000..6e9f65d2
--- /dev/null
+++ b/capplets/display/org.mate.randr.policy.in
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE policyconfig PUBLIC
+ "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd">
+<policyconfig>
+
+ <!--
+ Policy definitions for MATE's system-wide configuration of RANDR options
+ Copyright (c) 2010 Novell, Inc.
+ -->
+
+ <vendor>MATE Monitor Preferences</vendor>
+ <vendor_url>http://live.gnome.org/RandR</vendor_url>
+ <icon_name>mate-display-properties</icon_name>
+
+ <action id="org.mate.randr.install-system-wide">
+ <_description>Install multi-monitor settings for the whole system</_description>
+ <_message>Authentication is required to install multi-monitor settings for all users</_message>
+ <icon_name>mate-display-properties</icon_name>
+ <defaults>
+ <allow_any>no</allow_any>
+ <allow_inactive>no</allow_inactive>
+ <allow_active>auth_admin_keep</allow_active>
+ </defaults>
+ <annotate key="org.freedesktop.policykit.exec.path">/usr/sbin/mate-display-properties-install-systemwide</annotate>
+ </action>
+
+</policyconfig>
+
diff --git a/capplets/display/scrollarea.c b/capplets/display/scrollarea.c
new file mode 100644
index 00000000..9da2fb66
--- /dev/null
+++ b/capplets/display/scrollarea.c
@@ -0,0 +1,1944 @@
+/* Copyright 2006, 2007, 2008, Soren Sandmann <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <gdk/gdkprivate.h> /* For GDK_PARENT_RELATIVE_BG */
+#include "scrollarea.h"
+#include "foo-marshal.h"
+
+G_DEFINE_TYPE (FooScrollArea, foo_scroll_area, GTK_TYPE_CONTAINER);
+
+static GtkWidgetClass *parent_class;
+
+typedef struct BackingStore BackingStore;
+
+typedef void (* ExposeFunc) (cairo_t *cr, GdkRegion *region, gpointer data);
+
+#if 0
+static void backing_store_draw (BackingStore *store,
+ GdkDrawable *dest,
+ GdkRegion *clip,
+ int dest_x,
+ int dest_y);
+static void backing_store_scroll (BackingStore *store,
+ int dx, int dy);
+static void backing_store_invalidate_rect (BackingStore *store,
+ GdkRectangle *rect);
+static void backing_store_invalidate_region (BackingStore *store,
+ GdkRegion *region);
+static void backing_store_invalidate_all (BackingStore *store);
+static BackingStore *backing_store_new (GdkWindow *window,
+ int width, int height);
+static void backing_store_resize (BackingStore *store,
+ int width, int height);
+static void backing_store_process_updates (BackingStore *store,
+ ExposeFunc func,
+ gpointer data);
+static void backing_store_free (BackingStore *store);
+#endif
+
+typedef struct InputPath InputPath;
+typedef struct InputRegion InputRegion;
+typedef struct AutoScrollInfo AutoScrollInfo;
+
+struct InputPath
+{
+ gboolean is_stroke;
+ cairo_fill_rule_t fill_rule;
+ double line_width;
+ cairo_path_t *path; /* In canvas coordinates */
+
+ FooScrollAreaEventFunc func;
+ gpointer data;
+
+ InputPath *next;
+};
+
+/* InputRegions are mutually disjoint */
+struct InputRegion
+{
+ GdkRegion *region; /* the boundary of this area in canvas coordinates */
+ InputPath *paths;
+};
+
+struct AutoScrollInfo
+{
+ int dx;
+ int dy;
+ int timeout_id;
+ int begin_x;
+ int begin_y;
+ double res_x;
+ double res_y;
+ GTimer *timer;
+};
+
+struct FooScrollAreaPrivate
+{
+ GdkWindow *input_window;
+
+ int width;
+ int height;
+
+ GtkAdjustment *hadj;
+ GtkAdjustment *vadj;
+ int x_offset;
+ int y_offset;
+
+ int min_width;
+ int min_height;
+
+ GPtrArray *input_regions;
+
+ AutoScrollInfo *auto_scroll_info;
+
+ /* During expose, this region is set to the region
+ * being exposed. At other times, it is NULL
+ *
+ * It is used for clipping of input areas
+ */
+ GdkRegion *expose_region;
+ InputRegion *current_input;
+
+ gboolean grabbed;
+ FooScrollAreaEventFunc grab_func;
+ gpointer grab_data;
+
+ GdkPixmap *pixmap;
+ GdkRegion *update_region; /* In canvas coordinates */
+};
+
+enum
+{
+ VIEWPORT_CHANGED,
+ PAINT,
+ INPUT,
+ LAST_SIGNAL,
+};
+
+static guint signals [LAST_SIGNAL] = { 0 };
+
+static void foo_scroll_area_size_request (GtkWidget *widget,
+ GtkRequisition *requisition);
+static gboolean foo_scroll_area_expose (GtkWidget *widget,
+ GdkEventExpose *expose);
+static void foo_scroll_area_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation);
+static void foo_scroll_area_set_scroll_adjustments (FooScrollArea *scroll_area,
+ GtkAdjustment *hadjustment,
+ GtkAdjustment *vadjustment);
+static void foo_scroll_area_realize (GtkWidget *widget);
+static void foo_scroll_area_unrealize (GtkWidget *widget);
+static void foo_scroll_area_map (GtkWidget *widget);
+static void foo_scroll_area_unmap (GtkWidget *widget);
+static gboolean foo_scroll_area_button_press (GtkWidget *widget,
+ GdkEventButton *event);
+static gboolean foo_scroll_area_button_release (GtkWidget *widget,
+ GdkEventButton *event);
+static gboolean foo_scroll_area_motion (GtkWidget *widget,
+ GdkEventMotion *event);
+
+static void
+foo_scroll_area_map (GtkWidget *widget)
+{
+ FooScrollArea *area = FOO_SCROLL_AREA (widget);
+
+ GTK_WIDGET_CLASS (parent_class)->map (widget);
+
+ if (area->priv->input_window)
+ gdk_window_show (area->priv->input_window);
+}
+
+static void
+foo_scroll_area_unmap (GtkWidget *widget)
+{
+ FooScrollArea *area = FOO_SCROLL_AREA (widget);
+
+ if (area->priv->input_window)
+ gdk_window_hide (area->priv->input_window);
+
+ GTK_WIDGET_CLASS (parent_class)->unmap (widget);
+}
+
+static void
+foo_scroll_area_finalize (GObject *object)
+{
+ FooScrollArea *scroll_area = FOO_SCROLL_AREA (object);
+
+ g_object_unref (scroll_area->priv->hadj);
+ g_object_unref (scroll_area->priv->vadj);
+
+ g_ptr_array_free (scroll_area->priv->input_regions, TRUE);
+
+ g_free (scroll_area->priv);
+
+ G_OBJECT_CLASS (foo_scroll_area_parent_class)->finalize (object);
+}
+
+static void
+foo_scroll_area_class_init (FooScrollAreaClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
+
+ object_class->finalize = foo_scroll_area_finalize;
+ widget_class->size_request = foo_scroll_area_size_request;
+ widget_class->expose_event = foo_scroll_area_expose;
+ widget_class->size_allocate = foo_scroll_area_size_allocate;
+ widget_class->realize = foo_scroll_area_realize;
+ widget_class->unrealize = foo_scroll_area_unrealize;
+ widget_class->button_press_event = foo_scroll_area_button_press;
+ widget_class->button_release_event = foo_scroll_area_button_release;
+ widget_class->motion_notify_event = foo_scroll_area_motion;
+ widget_class->map = foo_scroll_area_map;
+ widget_class->unmap = foo_scroll_area_unmap;
+
+ class->set_scroll_adjustments = foo_scroll_area_set_scroll_adjustments;
+
+ parent_class = g_type_class_peek_parent (class);
+
+ signals[VIEWPORT_CHANGED] =
+ g_signal_new ("viewport_changed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (FooScrollAreaClass,
+ viewport_changed),
+ NULL, NULL,
+ foo_marshal_VOID__BOXED_BOXED,
+ G_TYPE_NONE, 2,
+ GDK_TYPE_RECTANGLE,
+ GDK_TYPE_RECTANGLE);
+
+ signals[PAINT] =
+ g_signal_new ("paint",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (FooScrollAreaClass,
+ paint),
+ NULL, NULL,
+ foo_marshal_VOID__POINTER_BOXED_POINTER,
+ G_TYPE_NONE, 3,
+ G_TYPE_POINTER,
+ GDK_TYPE_RECTANGLE,
+ G_TYPE_POINTER);
+
+ widget_class->set_scroll_adjustments_signal =
+ g_signal_new ("set_scroll_adjustments",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (FooScrollAreaClass,
+ set_scroll_adjustments),
+ NULL, NULL,
+ foo_marshal_VOID__OBJECT_OBJECT,
+ G_TYPE_NONE, 2,
+ GTK_TYPE_ADJUSTMENT,
+ GTK_TYPE_ADJUSTMENT);
+}
+
+static GtkAdjustment *
+new_adjustment (void)
+{
+ return GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
+}
+
+static void
+foo_scroll_area_init (FooScrollArea *scroll_area)
+{
+ GtkWidget *widget;
+
+ widget = GTK_WIDGET (scroll_area);
+
+ gtk_widget_set_has_window (widget, FALSE);
+ gtk_widget_set_redraw_on_allocate (widget, FALSE);
+
+ scroll_area->priv = g_new0 (FooScrollAreaPrivate, 1);
+ scroll_area->priv->width = 0;
+ scroll_area->priv->height = 0;
+ scroll_area->priv->hadj = g_object_ref_sink (new_adjustment());
+ scroll_area->priv->vadj = g_object_ref_sink (new_adjustment());
+ scroll_area->priv->x_offset = 0.0;
+ scroll_area->priv->y_offset = 0.0;
+ scroll_area->priv->min_width = -1;
+ scroll_area->priv->min_height = -1;
+ scroll_area->priv->auto_scroll_info = NULL;
+ scroll_area->priv->input_regions = g_ptr_array_new ();
+ scroll_area->priv->pixmap = NULL;
+ scroll_area->priv->update_region = gdk_region_new ();
+
+ gtk_widget_set_double_buffered (widget, FALSE);
+}
+
+static void
+translate_cairo_device (cairo_t *cr,
+ int x_offset,
+ int y_offset)
+{
+ cairo_surface_t *surface = cairo_get_target (cr);
+ double dev_x;
+ double dev_y;
+
+ cairo_surface_get_device_offset (surface, &dev_x, &dev_y);
+ dev_x += x_offset;
+ dev_y += y_offset;
+ cairo_surface_set_device_offset (surface, dev_x, dev_y);
+}
+
+#if 0
+static void
+print_region (const char *header, GdkRegion *region)
+{
+ GdkRectangle *rects;
+ int n_rects;
+ int i;
+
+ g_print ("%s\n", header);
+
+ gdk_region_get_rectangles (region, &rects, &n_rects);
+ for (i = 0; i < n_rects; ++i)
+ {
+ GdkRectangle *rect = &(rects[i]);
+ g_print (" %d %d %d %d\n",
+ rect->x, rect->y, rect->width, rect->height);
+ }
+}
+#endif
+
+typedef void (* PathForeachFunc) (double *x,
+ double *y,
+ gpointer data);
+
+static void
+path_foreach_point (cairo_path_t *path,
+ PathForeachFunc func,
+ gpointer user_data)
+{
+ int i;
+
+ for (i = 0; i < path->num_data; i += path->data[i].header.length)
+ {
+ cairo_path_data_t *data = &(path->data[i]);
+
+ switch (data->header.type)
+ {
+ case CAIRO_PATH_MOVE_TO:
+ case CAIRO_PATH_LINE_TO:
+ func (&(data[1].point.x), &(data[1].point.y), user_data);
+ break;
+
+ case CAIRO_PATH_CURVE_TO:
+ func (&(data[1].point.x), &(data[1].point.y), user_data);
+ func (&(data[2].point.x), &(data[2].point.y), user_data);
+ func (&(data[3].point.x), &(data[3].point.y), user_data);
+ break;
+
+ case CAIRO_PATH_CLOSE_PATH:
+ break;
+ }
+ }
+}
+
+typedef struct
+{
+ double x1, y1, x2, y2;
+} Box;
+
+#if 0
+static void
+update_box (double *x, double *y, gpointer data)
+{
+ Box *box = data;
+
+ if (*x < box->x1)
+ box->x1 = *x;
+
+ if (*y < box->y1)
+ box->y1 = *y;
+
+ if (*y > box->y2)
+ box->y2 = *y;
+
+ if (*x > box->x2)
+ box->x2 = *x;
+}
+#endif
+
+#if 0
+static void
+path_compute_extents (cairo_path_t *path,
+ GdkRectangle *rect)
+{
+ if (rect)
+ {
+ Box box = { G_MAXDOUBLE, G_MAXDOUBLE, G_MINDOUBLE, G_MINDOUBLE };
+
+ path_foreach_point (path, update_box, &box);
+
+ rect->x = box.x1;
+ rect->y = box.y1;
+ rect->width = box.x2 - box.x1;
+ rect->height = box.y2 - box.y1;
+ }
+}
+#endif
+
+static void
+input_path_free_list (InputPath *paths)
+{
+ if (!paths)
+ return;
+
+ input_path_free_list (paths->next);
+ cairo_path_destroy (paths->path);
+ g_free (paths);
+}
+
+static void
+input_region_free (InputRegion *region)
+{
+ input_path_free_list (region->paths);
+ gdk_region_destroy (region->region);
+
+ g_free (region);
+}
+
+static void
+get_viewport (FooScrollArea *scroll_area,
+ GdkRectangle *viewport)
+{
+ GtkAllocation allocation;
+ GtkWidget *widget = GTK_WIDGET (scroll_area);
+
+ gtk_widget_get_allocation (widget, &allocation);
+
+ viewport->x = scroll_area->priv->x_offset;
+ viewport->y = scroll_area->priv->y_offset;
+ viewport->width = allocation.width;
+ viewport->height = allocation.height;
+}
+
+static void
+allocation_to_canvas (FooScrollArea *area,
+ int *x,
+ int *y)
+{
+ *x += area->priv->x_offset;
+ *y += area->priv->y_offset;
+}
+
+static void
+clear_exposed_input_region (FooScrollArea *area,
+ GdkRegion *exposed) /* in canvas coordinates */
+{
+ int i;
+ GdkRegion *viewport;
+ GdkRectangle allocation;
+
+ gtk_widget_get_allocation (GTK_WIDGET (area), &allocation);
+ allocation.x = 0;
+ allocation.y = 0;
+ allocation_to_canvas (area, &allocation.x, &allocation.y);
+ viewport = gdk_region_rectangle (&allocation);
+ gdk_region_subtract (viewport, exposed);
+
+ for (i = 0; i < area->priv->input_regions->len; ++i)
+ {
+ InputRegion *region = area->priv->input_regions->pdata[i];
+
+ gdk_region_intersect (region->region, viewport);
+
+ if (gdk_region_empty (region->region))
+ {
+ input_region_free (region);
+ g_ptr_array_remove_index_fast (area->priv->input_regions, i--);
+ }
+ }
+
+ gdk_region_destroy (viewport);
+
+#if 0
+ path = region->paths;
+ while (path != NULL)
+ {
+ GdkRectangle rect;
+
+ path_compute_extents (path->path, &rect);
+
+ if (gdk_region_rect_in (area->priv->expose_region, &rect) == GDK_OVERLAP_RECTANGLE_IN)
+ g_print ("we would have deleted it\n");
+#if 0
+ else
+ g_print ("nope (%d %d %d %d)\n", );
+#endif
+
+ path = path->next;
+ }
+
+ /* FIXME: we should also delete paths (and path segments)
+ * completely contained in the expose_region
+ */
+ }
+#endif
+}
+
+static void
+setup_background_cr (GdkWindow *window,
+ cairo_t *cr,
+ int x_offset,
+ int y_offset)
+{
+ GdkWindowObject *private = (GdkWindowObject *)window;
+
+ if (private->bg_pixmap == GDK_PARENT_RELATIVE_BG && private->parent)
+ {
+ x_offset += private->x;
+ y_offset += private->y;
+
+ setup_background_cr (GDK_WINDOW (private->parent), cr, x_offset, y_offset);
+ }
+ else if (private->bg_pixmap &&
+ private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
+ private->bg_pixmap != GDK_NO_BG)
+ {
+ gdk_cairo_set_source_pixmap (cr, private->bg_pixmap, -x_offset, -y_offset);
+ }
+ else
+ {
+ gdk_cairo_set_source_color (cr, &private->bg_color);
+ }
+}
+
+static void
+initialize_background (GtkWidget *widget,
+ cairo_t *cr)
+{
+ setup_background_cr (gtk_widget_get_window (widget), cr, 0, 0);
+
+ cairo_paint (cr);
+}
+
+static void
+clip_to_region (cairo_t *cr, GdkRegion *region)
+{
+ int n_rects;
+ GdkRectangle *rects;
+
+ gdk_region_get_rectangles (region, &rects, &n_rects);
+
+ cairo_new_path (cr);
+ while (n_rects--)
+ {
+ GdkRectangle *rect = &(rects[n_rects]);
+
+ cairo_rectangle (cr, rect->x, rect->y, rect->width, rect->height);
+ }
+ cairo_clip (cr);
+
+ g_free (rects);
+}
+
+static void
+simple_draw_drawable (GdkDrawable *dst,
+ GdkDrawable *src,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ int width,
+ int height)
+{
+ GdkGC *gc = gdk_gc_new (dst);
+
+ gdk_draw_drawable (dst, gc, src, src_x, src_y, dst_x, dst_y, width, height);
+
+ g_object_unref (gc);
+}
+
+static gboolean
+foo_scroll_area_expose (GtkWidget *widget,
+ GdkEventExpose *expose)
+{
+ FooScrollArea *scroll_area = FOO_SCROLL_AREA (widget);
+ cairo_t *cr;
+ GdkRectangle extents;
+ GdkRegion *region;
+ int x_offset, y_offset;
+ GdkGC *gc;
+ GtkAllocation widget_allocation;
+ GdkWindow *window = gtk_widget_get_window (widget);
+
+ /* I don't think expose can ever recurse for the same area */
+ g_assert (!scroll_area->priv->expose_region);
+
+ /* Note that this function can be called at a time
+ * where the adj->value is different from x_offset.
+ * Ie., the GtkScrolledWindow changed the adj->value
+ * without emitting the value_changed signal.
+ *
+ * Hence we must always use the value we got
+ * the last time the signal was emitted, ie.,
+ * priv->{x,y}_offset.
+ */
+
+ x_offset = scroll_area->priv->x_offset;
+ y_offset = scroll_area->priv->y_offset;
+
+ scroll_area->priv->expose_region = expose->region;
+
+ /* Setup input areas */
+ clear_exposed_input_region (scroll_area, scroll_area->priv->update_region);
+
+ scroll_area->priv->current_input = g_new0 (InputRegion, 1);
+ scroll_area->priv->current_input->region = gdk_region_copy (scroll_area->priv->update_region);
+ scroll_area->priv->current_input->paths = NULL;
+ g_ptr_array_add (scroll_area->priv->input_regions,
+ scroll_area->priv->current_input);
+
+ region = scroll_area->priv->update_region;
+ scroll_area->priv->update_region = gdk_region_new ();
+
+ /* Create cairo context */
+ cr = gdk_cairo_create (scroll_area->priv->pixmap);
+ translate_cairo_device (cr, -x_offset, -y_offset);
+ clip_to_region (cr, region);
+ initialize_background (widget, cr);
+
+ /* Create regions */
+ gdk_region_get_clipbox (region, &extents);
+
+ g_signal_emit (widget, signals[PAINT], 0, cr, &extents, region);
+
+ /* Destroy stuff */
+ cairo_destroy (cr);
+
+ scroll_area->priv->expose_region = NULL;
+ scroll_area->priv->current_input = NULL;
+
+ /* Finally draw the backing pixmap */
+ gc = gdk_gc_new (window);
+
+ gdk_gc_set_clip_region (gc, expose->region);
+
+ gtk_widget_get_allocation (widget, &widget_allocation);
+ gdk_draw_drawable (window, gc, scroll_area->priv->pixmap,
+ 0, 0, widget_allocation.x, widget_allocation.y,
+ widget_allocation.width, widget_allocation.height);
+
+ g_object_unref (gc);
+ gdk_region_destroy (region);
+
+ return TRUE;
+}
+
+void
+foo_scroll_area_get_viewport (FooScrollArea *scroll_area,
+ GdkRectangle *viewport)
+{
+ g_return_if_fail (FOO_IS_SCROLL_AREA (scroll_area));
+
+ if (!viewport)
+ return;
+
+ get_viewport (scroll_area, viewport);
+}
+
+static void
+process_event (FooScrollArea *scroll_area,
+ FooScrollAreaEventType input_type,
+ int x,
+ int y);
+
+static void
+emit_viewport_changed (FooScrollArea *scroll_area,
+ GdkRectangle *new_viewport,
+ GdkRectangle *old_viewport)
+{
+ int px, py;
+ g_signal_emit (scroll_area, signals[VIEWPORT_CHANGED], 0,
+ new_viewport, old_viewport);
+
+ gdk_window_get_pointer (scroll_area->priv->input_window, &px, &py, NULL);
+
+#if 0
+ g_print ("procc\n");
+#endif
+
+ process_event (scroll_area, FOO_MOTION, px, py);
+}
+
+static void
+clamp_adjustment (GtkAdjustment *adj)
+{
+ if (gtk_adjustment_get_upper (adj) >= gtk_adjustment_get_page_size (adj))
+ gtk_adjustment_set_value (adj, CLAMP (gtk_adjustment_get_value (adj), 0.0,
+ gtk_adjustment_get_upper (adj)
+ - gtk_adjustment_get_page_size (adj)));
+ else
+ gtk_adjustment_set_value (adj, 0.0);
+
+ gtk_adjustment_changed (adj);
+}
+
+static gboolean
+set_adjustment_values (FooScrollArea *scroll_area)
+{
+ GtkAllocation allocation;
+
+ GtkAdjustment *hadj = scroll_area->priv->hadj;
+ GtkAdjustment *vadj = scroll_area->priv->vadj;
+
+ /* Horizontal */
+ gtk_widget_get_allocation (GTK_WIDGET (scroll_area), &allocation);
+ g_object_freeze_notify (G_OBJECT (hadj));
+ gtk_adjustment_set_page_size (hadj, allocation.width);
+ gtk_adjustment_set_step_increment (hadj, 0.1 * allocation.width);
+ gtk_adjustment_set_page_increment (hadj, 0.9 * allocation.width);
+ gtk_adjustment_set_lower (hadj, 0.0);
+ gtk_adjustment_set_upper (hadj, scroll_area->priv->width);
+ g_object_thaw_notify (G_OBJECT (hadj));
+
+ /* Vertical */
+ g_object_freeze_notify (G_OBJECT (vadj));
+ gtk_adjustment_set_page_size (vadj, allocation.height);
+ gtk_adjustment_set_step_increment (vadj, 0.1 * allocation.height);
+ gtk_adjustment_set_page_increment (vadj, 0.9 * allocation.height);
+ gtk_adjustment_set_lower (vadj, 0.0);
+ gtk_adjustment_set_upper (vadj, scroll_area->priv->height);
+ g_object_thaw_notify (G_OBJECT (vadj));
+
+ clamp_adjustment (hadj);
+ clamp_adjustment (vadj);
+
+ return TRUE;
+}
+
+static void
+foo_scroll_area_realize (GtkWidget *widget)
+{
+ FooScrollArea *area = FOO_SCROLL_AREA (widget);
+ GdkWindowAttr attributes;
+ GtkAllocation widget_allocation;
+ GdkWindow *window;
+ gint attributes_mask;
+
+ gtk_widget_get_allocation (widget, &widget_allocation);
+ gtk_widget_set_realized (widget, TRUE);
+
+ attributes.window_type = GDK_WINDOW_CHILD;
+ attributes.x = widget_allocation.x;
+ attributes.y = widget_allocation.y;
+ attributes.width = widget_allocation.width;
+ attributes.height = widget_allocation.height;
+ attributes.wclass = GDK_INPUT_ONLY;
+ attributes.event_mask = gtk_widget_get_events (widget);
+ attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
+ GDK_BUTTON_RELEASE_MASK |
+ GDK_BUTTON1_MOTION_MASK |
+ GDK_BUTTON2_MOTION_MASK |
+ GDK_BUTTON3_MOTION_MASK |
+ GDK_POINTER_MOTION_MASK |
+ GDK_ENTER_NOTIFY_MASK |
+ GDK_LEAVE_NOTIFY_MASK);
+
+ attributes_mask = GDK_WA_X | GDK_WA_Y;
+
+ window = gtk_widget_get_parent_window (widget);
+ gtk_widget_set_window (widget, window);
+ g_object_ref (window);
+
+ area->priv->input_window = gdk_window_new (window,
+ &attributes, attributes_mask);
+ area->priv->pixmap = gdk_pixmap_new (window,
+ widget_allocation.width,
+ widget_allocation.height,
+ -1);
+ gdk_window_set_user_data (area->priv->input_window, area);
+
+ gtk_widget_style_attach (widget);
+}
+
+static void
+foo_scroll_area_unrealize (GtkWidget *widget)
+{
+ FooScrollArea *area = FOO_SCROLL_AREA (widget);
+
+ if (area->priv->input_window)
+ {
+ gdk_window_set_user_data (area->priv->input_window, NULL);
+ gdk_window_destroy (area->priv->input_window);
+ area->priv->input_window = NULL;
+ }
+
+ GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
+}
+
+static GdkPixmap *
+create_new_pixmap (GtkWidget *widget,
+ GdkPixmap *old)
+{
+ GtkAllocation widget_allocation;
+ GdkPixmap *new;
+
+ gtk_widget_get_allocation (widget, &widget_allocation);
+ new = gdk_pixmap_new (gtk_widget_get_window (widget),
+ widget_allocation.width,
+ widget_allocation.height,
+ -1);
+
+ /* Unfortunately we don't know in which direction we were resized,
+ * so we just assume we were dragged from the south-east corner.
+ *
+ * Although, maybe we could get the root coordinates of the input-window?
+ * That might just work, actually. We need to make sure marco uses
+ * static gravity for the window before this will be useful.
+ */
+ simple_draw_drawable (new, old, 0, 0, 0, 0, -1, -1);
+
+ return new;
+}
+
+static void
+allocation_to_canvas_region (FooScrollArea *area,
+ GdkRegion *region)
+{
+ gdk_region_offset (region, area->priv->x_offset, area->priv->y_offset);
+}
+
+
+static void
+foo_scroll_area_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ FooScrollArea *scroll_area = FOO_SCROLL_AREA (widget);
+ GdkRectangle new_viewport;
+ GdkRectangle old_viewport;
+ GdkRegion *old_allocation;
+ GdkRegion *invalid;
+ GtkAllocation widget_allocation;
+
+ get_viewport (scroll_area, &old_viewport);
+
+ gtk_widget_get_allocation (widget, &widget_allocation);
+ old_allocation = gdk_region_rectangle (&widget_allocation);
+ gdk_region_offset (old_allocation,
+ -widget_allocation.x, -widget_allocation.y);
+ invalid = gdk_region_rectangle (allocation);
+ gdk_region_offset (invalid, -allocation->x, -allocation->y);
+ gdk_region_xor (invalid, old_allocation);
+ allocation_to_canvas_region (scroll_area, invalid);
+ foo_scroll_area_invalidate_region (scroll_area, invalid);
+ gdk_region_destroy (old_allocation);
+ gdk_region_destroy (invalid);
+
+ gtk_widget_set_allocation (widget, allocation);
+
+ if (scroll_area->priv->input_window)
+ {
+ GdkPixmap *new_pixmap;
+
+ gdk_window_move_resize (scroll_area->priv->input_window,
+ allocation->x, allocation->y,
+ allocation->width, allocation->height);
+
+ new_pixmap = create_new_pixmap (widget, scroll_area->priv->pixmap);
+
+ g_object_unref (scroll_area->priv->pixmap);
+
+ scroll_area->priv->pixmap = new_pixmap;
+ }
+
+ get_viewport (scroll_area, &new_viewport);
+
+ emit_viewport_changed (scroll_area, &new_viewport, &old_viewport);
+}
+
+static void
+emit_input (FooScrollArea *scroll_area,
+ FooScrollAreaEventType type,
+ int x,
+ int y,
+ FooScrollAreaEventFunc func,
+ gpointer data)
+{
+ FooScrollAreaEvent event;
+
+ if (!func)
+ return;
+
+ if (type != FOO_MOTION)
+ emit_input (scroll_area, FOO_MOTION, x, y, func, data);
+
+#if 0
+ x += scroll_area->priv->x_offset;
+ y += scroll_area->priv->y_offset;
+#endif
+
+ event.type = type;
+ event.x = x;
+ event.y = y;
+
+ func (scroll_area, &event, data);
+}
+
+#if 0
+static void
+print_path (const char *header,
+ cairo_path_t *path)
+{
+ int i;
+
+ g_print ("%s\n", header);
+
+ for (i=0; i < path->num_data; i += path->data[i].header.length)
+ {
+ cairo_path_data_t *data = &(path->data[i]);
+
+ switch (data->header.type)
+ {
+ case CAIRO_PATH_MOVE_TO:
+ g_print ("move to: %f, %f\n", data[1].point.x, data[1].point.y);
+ break;
+
+ case CAIRO_PATH_LINE_TO:
+ g_print ("line to: %f, %f\n", data[1].point.x, data[1].point.y);
+ break;
+
+ case CAIRO_PATH_CURVE_TO:
+ g_print ("curve to: %f, %f\n", data[1].point.x, data[1].point.y);
+ g_print (" %f, %f\n", data[1].point.x, data[1].point.y);
+ g_print (" %f, %f\n", data[1].point.x, data[1].point.y);
+ break;
+
+ case CAIRO_PATH_CLOSE_PATH:
+ break;
+ }
+ }
+}
+#endif
+
+static void
+process_event (FooScrollArea *scroll_area,
+ FooScrollAreaEventType input_type,
+ int x,
+ int y)
+{
+ GtkWidget *widget = GTK_WIDGET (scroll_area);
+ int i;
+
+ allocation_to_canvas (scroll_area, &x, &y);
+
+ if (scroll_area->priv->grabbed)
+ {
+ emit_input (scroll_area, input_type, x, y,
+ scroll_area->priv->grab_func,
+ scroll_area->priv->grab_data);
+ return;
+ }
+
+
+#if 0
+ x += widget->allocation.x;
+ y += widget->allocation.y;
+#endif
+
+#if 0
+ g_print ("number of input regions: %d\n", scroll_area->priv->input_regions->len);
+#endif
+
+ for (i = 0; i < scroll_area->priv->input_regions->len; ++i)
+ {
+ InputRegion *region = scroll_area->priv->input_regions->pdata[i];
+
+#if 0
+ g_print ("%d ", i);
+ print_region ("region:", region->region);
+#endif
+
+ if (gdk_region_point_in (region->region, x, y))
+ {
+ InputPath *path;
+
+ path = region->paths;
+ while (path)
+ {
+ cairo_t *cr;
+ gboolean inside;
+
+ cr = gdk_cairo_create (gtk_widget_get_window (widget));
+ cairo_set_fill_rule (cr, path->fill_rule);
+ cairo_set_line_width (cr, path->line_width);
+ cairo_append_path (cr, path->path);
+
+ if (path->is_stroke)
+ inside = cairo_in_stroke (cr, x, y);
+ else
+ inside = cairo_in_fill (cr, x, y);
+
+ cairo_destroy (cr);
+
+ if (inside)
+ {
+ emit_input (scroll_area, input_type,
+ x, y,
+ path->func,
+ path->data);
+ return;
+ }
+
+ path = path->next;
+ }
+
+ /* Since the regions are all disjoint, no other region
+ * can match. Of course we could be clever and try and
+ * sort the regions, but so far I have been unable to
+ * make this loop show up on a profile.
+ */
+ return;
+ }
+ }
+}
+
+static void
+process_gdk_event (FooScrollArea *scroll_area,
+ int x,
+ int y,
+ GdkEvent *event)
+{
+ FooScrollAreaEventType input_type;
+
+ if (event->type == GDK_BUTTON_PRESS)
+ input_type = FOO_BUTTON_PRESS;
+ else if (event->type == GDK_BUTTON_RELEASE)
+ input_type = FOO_BUTTON_RELEASE;
+ else if (event->type == GDK_MOTION_NOTIFY)
+ input_type = FOO_MOTION;
+ else
+ return;
+
+ process_event (scroll_area, input_type, x, y);
+}
+
+static gboolean
+foo_scroll_area_button_press (GtkWidget *widget,
+ GdkEventButton *event)
+{
+ FooScrollArea *area = FOO_SCROLL_AREA (widget);
+
+ process_gdk_event (area, event->x, event->y, (GdkEvent *)event);
+
+ return TRUE;
+}
+
+static gboolean
+foo_scroll_area_button_release (GtkWidget *widget,
+ GdkEventButton *event)
+{
+ FooScrollArea *area = FOO_SCROLL_AREA (widget);
+
+ process_gdk_event (area, event->x, event->y, (GdkEvent *)event);
+
+ return FALSE;
+}
+
+static gboolean
+foo_scroll_area_motion (GtkWidget *widget,
+ GdkEventMotion *event)
+{
+ FooScrollArea *area = FOO_SCROLL_AREA (widget);
+
+ process_gdk_event (area, event->x, event->y, (GdkEvent *)event);
+ return TRUE;
+}
+
+void
+foo_scroll_area_set_size_fixed_y (FooScrollArea *scroll_area,
+ int width,
+ int height,
+ int old_y,
+ int new_y)
+{
+ scroll_area->priv->width = width;
+ scroll_area->priv->height = height;
+
+#if 0
+ g_print ("diff: %d\n", new_y - old_y);
+#endif
+ g_object_thaw_notify (G_OBJECT (scroll_area->priv->vadj));
+ gtk_adjustment_set_value (scroll_area->priv->vadj, new_y);
+
+ set_adjustment_values (scroll_area);
+ g_object_thaw_notify (G_OBJECT (scroll_area->priv->vadj));
+}
+
+void
+foo_scroll_area_set_size (FooScrollArea *scroll_area,
+ int width,
+ int height)
+{
+ g_return_if_fail (FOO_IS_SCROLL_AREA (scroll_area));
+
+ /* FIXME: Default scroll algorithm should probably be to
+ * keep the same *area* outside the screen as before.
+ *
+ * For wrapper widgets that will do something roughly
+ * right. For widgets that don't change size, it
+ * will do the right thing. Except for idle-layouting
+ * widgets.
+ *
+ * Maybe there should be some generic support for those
+ * widgets. Can that even be done?
+ *
+ * Should we have a version of this function using
+ * fixed points?
+ */
+
+ scroll_area->priv->width = width;
+ scroll_area->priv->height = height;
+
+ set_adjustment_values (scroll_area);
+}
+
+static void
+foo_scroll_area_size_request (GtkWidget *widget,
+ GtkRequisition *requisition)
+{
+ FooScrollArea *scroll_area = FOO_SCROLL_AREA (widget);
+
+ requisition->width = scroll_area->priv->min_width;
+ requisition->height = scroll_area->priv->min_height;
+
+#if 0
+ g_print ("request %d %d\n", requisition->width, requisition->height);
+#endif
+}
+
+#if 0
+static void
+translate_point (double *x, double *y, gpointer data)
+{
+ int *translation = data;
+
+ *x += translation[0];
+ *y += translation[1];
+}
+#endif
+
+#if 0
+static void
+path_translate (cairo_path_t *path,
+ int dx,
+ int dy)
+{
+ int translation[2] = {dx, dy};
+
+ path_foreach_point (path, translate_point, translation);
+}
+#endif
+
+static void
+translate_input_regions (FooScrollArea *scroll_area,
+ int dx,
+ int dy)
+{
+#if 0
+ int i;
+
+ for (i = 0; i < scroll_area->priv->input_regions->len; ++i)
+ {
+ InputRegion *region = scroll_area->priv->input_regions->pdata[i];
+ InputPath *path;
+
+ gdk_region_offset (region->region, dx, dy);
+
+ path = region->paths;
+ while (path != NULL)
+ {
+ path_translate (path->path, dx, dy);
+ path = path->next;
+ }
+ }
+#endif
+}
+
+#if 0
+static void
+paint_region (FooScrollArea *area, GdkRegion *region)
+{
+ int n_rects;
+ GdkRectangle *rects;
+ region = gdk_region_copy (region);
+
+ gdk_region_get_rectangles (region, &rects, &n_rects);
+
+ gdk_region_offset (region,
+ GTK_WIDGET (area)->allocation.x,
+ GTK_WIDGET (area)->allocation.y);
+
+ GdkGC *gc = gdk_gc_new (GTK_WIDGET (area)->window);
+ gdk_gc_set_clip_region (gc, region);
+ gdk_draw_rectangle (GTK_WIDGET (area)->window, gc, TRUE, 0, 0, -1, -1);
+ g_object_unref (gc);
+ g_free (rects);
+}
+#endif
+
+static void
+foo_scroll_area_scroll (FooScrollArea *area,
+ gint dx,
+ gint dy)
+{
+ GdkRectangle allocation;
+ GdkRectangle src_area;
+ GdkRectangle move_area;
+ GdkRegion *invalid_region;
+
+ gtk_widget_get_allocation (GTK_WIDGET (area), &allocation);
+ allocation.x = 0;
+ allocation.y = 0;
+
+ src_area = allocation;
+ src_area.x -= dx;
+ src_area.y -= dy;
+
+ invalid_region = gdk_region_rectangle (&allocation);
+
+ if (gdk_rectangle_intersect (&allocation, &src_area, &move_area))
+ {
+ GdkRegion *move_region;
+
+#if 0
+ g_print ("scrolling %d %d %d %d (%d %d)\n",
+ move_area.x, move_area.y,
+ move_area.width, move_area.height,
+ dx, dy);
+#endif
+
+ simple_draw_drawable (area->priv->pixmap, area->priv->pixmap,
+ move_area.x, move_area.y,
+ move_area.x + dx, move_area.y + dy,
+ move_area.width, move_area.height);
+ gtk_widget_queue_draw (GTK_WIDGET (area));
+
+ move_region = gdk_region_rectangle (&move_area);
+ gdk_region_offset (move_region, dx, dy);
+ gdk_region_subtract (invalid_region, move_region);
+ gdk_region_destroy (move_region);
+ }
+
+#if 0
+ paint_region (area, invalid_region);
+#endif
+
+ allocation_to_canvas_region (area, invalid_region);
+
+ foo_scroll_area_invalidate_region (area, invalid_region);
+
+ gdk_region_destroy (invalid_region);
+}
+
+static void
+foo_scrollbar_adjustment_changed (GtkAdjustment *adj,
+ FooScrollArea *scroll_area)
+{
+ GtkWidget *widget = GTK_WIDGET (scroll_area);
+ gint dx = 0;
+ gint dy = 0;
+ GdkRectangle old_viewport, new_viewport;
+
+ get_viewport (scroll_area, &old_viewport);
+
+ if (adj == scroll_area->priv->hadj)
+ {
+ /* FIXME: do we treat the offset as int or double, and,
+ * if int, how do we round?
+ */
+ dx = (int)gtk_adjustment_get_value (adj) - scroll_area->priv->x_offset;
+ scroll_area->priv->x_offset = gtk_adjustment_get_value (adj);
+ }
+ else if (adj == scroll_area->priv->vadj)
+ {
+ dy = (int)gtk_adjustment_get_value (adj) - scroll_area->priv->y_offset;
+ scroll_area->priv->y_offset = gtk_adjustment_get_value (adj);
+ }
+ else
+ {
+ g_assert_not_reached ();
+ }
+
+ if (gtk_widget_get_realized (widget))
+ {
+ foo_scroll_area_scroll (scroll_area, -dx, -dy);
+
+#if 0
+ window_scroll_area (widget->window, &widget->allocation, -dx, -dy);
+#endif
+ translate_input_regions (scroll_area, -dx, -dy);
+
+#if 0
+ gdk_window_process_updates (widget->window, TRUE);
+#endif
+ }
+
+ get_viewport (scroll_area, &new_viewport);
+
+ emit_viewport_changed (scroll_area, &new_viewport, &old_viewport);
+}
+
+static void
+set_one_adjustment (FooScrollArea *scroll_area,
+ GtkAdjustment *adjustment,
+ GtkAdjustment **location)
+{
+ g_return_if_fail (location != NULL);
+
+ if (adjustment == *location)
+ return;
+
+ if (!adjustment)
+ adjustment = new_adjustment ();
+
+ g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
+
+ if (*location)
+ {
+ g_signal_handlers_disconnect_by_func (
+ *location, foo_scrollbar_adjustment_changed, scroll_area);
+
+ g_object_unref (*location);
+ }
+
+ *location = adjustment;
+
+ g_object_ref_sink (*location);
+
+ g_signal_connect (*location, "value_changed",
+ G_CALLBACK (foo_scrollbar_adjustment_changed),
+ scroll_area);
+}
+
+static void
+foo_scroll_area_set_scroll_adjustments (FooScrollArea *scroll_area,
+ GtkAdjustment *hadjustment,
+ GtkAdjustment *vadjustment)
+{
+ set_one_adjustment (scroll_area, hadjustment, &scroll_area->priv->hadj);
+ set_one_adjustment (scroll_area, vadjustment, &scroll_area->priv->vadj);
+
+ set_adjustment_values (scroll_area);
+}
+
+FooScrollArea *
+foo_scroll_area_new (void)
+{
+ return g_object_new (FOO_TYPE_SCROLL_AREA, NULL);
+}
+
+void
+foo_scroll_area_set_min_size (FooScrollArea *scroll_area,
+ int min_width,
+ int min_height)
+{
+ scroll_area->priv->min_width = min_width;
+ scroll_area->priv->min_height = min_height;
+
+ /* FIXME: think through invalidation.
+ *
+ * Goals: - no repainting everything on size_allocate(),
+ * - make sure input boxes are invalidated when
+ * needed
+ */
+ gtk_widget_queue_resize (GTK_WIDGET (scroll_area));
+}
+
+#if 0
+static void
+warn_about_adding_input_outside_expose (const char *func)
+{
+ static gboolean warned = FALSE;
+
+ if (!warned)
+ {
+ g_warning ("%s() can only be called "
+ "from the paint handler for the FooScrollArea\n", func);
+
+ warned = TRUE;
+ }
+}
+#endif
+
+static void
+user_to_device (double *x, double *y,
+ gpointer data)
+{
+ cairo_t *cr = data;
+
+ cairo_user_to_device (cr, x, y);
+}
+
+static InputPath *
+make_path (FooScrollArea *area,
+ cairo_t *cr,
+ gboolean is_stroke,
+ FooScrollAreaEventFunc func,
+ gpointer data)
+{
+ InputPath *path = g_new0 (InputPath, 1);
+
+ path->is_stroke = is_stroke;
+ path->fill_rule = cairo_get_fill_rule (cr);
+ path->line_width = cairo_get_line_width (cr);
+ path->path = cairo_copy_path (cr);
+ path_foreach_point (path->path, user_to_device, cr);
+ path->func = func;
+ path->data = data;
+ path->next = area->priv->current_input->paths;
+ area->priv->current_input->paths = path;
+ return path;
+}
+
+/* FIXME: we probably really want a
+ *
+ * foo_scroll_area_add_input_from_fill (area, cr, ...);
+ * and
+ * foo_scroll_area_add_input_from_stroke (area, cr, ...);
+ * as well.
+ */
+void
+foo_scroll_area_add_input_from_fill (FooScrollArea *scroll_area,
+ cairo_t *cr,
+ FooScrollAreaEventFunc func,
+ gpointer data)
+{
+ g_return_if_fail (FOO_IS_SCROLL_AREA (scroll_area));
+ g_return_if_fail (cr != NULL);
+ g_return_if_fail (scroll_area->priv->current_input);
+
+ make_path (scroll_area, cr, FALSE, func, data);
+}
+
+void
+foo_scroll_area_add_input_from_stroke (FooScrollArea *scroll_area,
+ cairo_t *cr,
+ FooScrollAreaEventFunc func,
+ gpointer data)
+{
+ g_return_if_fail (FOO_IS_SCROLL_AREA (scroll_area));
+ g_return_if_fail (cr != NULL);
+ g_return_if_fail (scroll_area->priv->current_input);
+
+ make_path (scroll_area, cr, TRUE, func, data);
+}
+
+void
+foo_scroll_area_invalidate (FooScrollArea *scroll_area)
+{
+ GtkAllocation allocation;
+ GtkWidget *widget = GTK_WIDGET (scroll_area);
+
+ gtk_widget_get_allocation (widget, &allocation);
+ foo_scroll_area_invalidate_rect (scroll_area,
+ scroll_area->priv->x_offset, scroll_area->priv->y_offset,
+ allocation.width,
+ allocation.height);
+}
+
+static void
+canvas_to_window (FooScrollArea *area,
+ GdkRegion *region)
+{
+ GtkAllocation allocation;
+ GtkWidget *widget = GTK_WIDGET (area);
+
+ gtk_widget_get_allocation (widget, &allocation);
+ gdk_region_offset (region,
+ -area->priv->x_offset + allocation.x,
+ -area->priv->y_offset + allocation.y);
+}
+
+static void
+window_to_canvas (FooScrollArea *area,
+ GdkRegion *region)
+{
+ GtkAllocation allocation;
+ GtkWidget *widget = GTK_WIDGET (area);
+
+ gtk_widget_get_allocation (widget, &allocation);
+ gdk_region_offset (region,
+ area->priv->x_offset - allocation.x,
+ area->priv->y_offset - allocation.y);
+}
+
+void
+foo_scroll_area_invalidate_region (FooScrollArea *area,
+ GdkRegion *region)
+{
+ GtkWidget *widget;
+
+ g_return_if_fail (FOO_IS_SCROLL_AREA (area));
+
+ widget = GTK_WIDGET (area);
+
+ gdk_region_union (area->priv->update_region, region);
+
+ if (gtk_widget_get_realized (widget))
+ {
+ canvas_to_window (area, region);
+
+ gdk_window_invalidate_region (gtk_widget_get_window (widget),
+ region, TRUE);
+
+ window_to_canvas (area, region);
+ }
+}
+
+void
+foo_scroll_area_invalidate_rect (FooScrollArea *scroll_area,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ GdkRectangle rect = { x, y, width, height };
+ GdkRegion *region;
+
+ g_return_if_fail (FOO_IS_SCROLL_AREA (scroll_area));
+
+ region = gdk_region_rectangle (&rect);
+
+ foo_scroll_area_invalidate_region (scroll_area, region);
+
+ gdk_region_destroy (region);
+}
+
+void
+foo_scroll_area_begin_grab (FooScrollArea *scroll_area,
+ FooScrollAreaEventFunc func,
+ gpointer input_data)
+{
+ g_return_if_fail (FOO_IS_SCROLL_AREA (scroll_area));
+ g_return_if_fail (!scroll_area->priv->grabbed);
+
+ scroll_area->priv->grabbed = TRUE;
+ scroll_area->priv->grab_func = func;
+ scroll_area->priv->grab_data = input_data;
+
+ /* FIXME: we should probably take a server grab */
+ /* Also, maybe there should be support for setting the grab cursor */
+}
+
+void
+foo_scroll_area_end_grab (FooScrollArea *scroll_area)
+{
+ g_return_if_fail (FOO_IS_SCROLL_AREA (scroll_area));
+
+ scroll_area->priv->grabbed = FALSE;
+ scroll_area->priv->grab_func = NULL;
+ scroll_area->priv->grab_data = NULL;
+}
+
+gboolean
+foo_scroll_area_is_grabbed (FooScrollArea *scroll_area)
+{
+ return scroll_area->priv->grabbed;
+}
+
+void
+foo_scroll_area_set_viewport_pos (FooScrollArea *scroll_area,
+ int x,
+ int y)
+{
+ g_object_freeze_notify (G_OBJECT (scroll_area->priv->hadj));
+ g_object_freeze_notify (G_OBJECT (scroll_area->priv->vadj));
+ gtk_adjustment_set_value (scroll_area->priv->hadj, x);
+ gtk_adjustment_set_value (scroll_area->priv->vadj, y);
+
+ set_adjustment_values (scroll_area);
+ g_object_thaw_notify (G_OBJECT (scroll_area->priv->hadj));
+ g_object_thaw_notify (G_OBJECT (scroll_area->priv->vadj));
+}
+
+static gboolean
+rect_contains (const GdkRectangle *rect, int x, int y)
+{
+ return (x >= rect->x &&
+ y >= rect->y &&
+ x < rect->x + rect->width &&
+ y < rect->y + rect->height);
+}
+
+static void
+stop_scrolling (FooScrollArea *area)
+{
+#if 0
+ g_print ("stop scrolling\n");
+#endif
+ if (area->priv->auto_scroll_info)
+ {
+ g_source_remove (area->priv->auto_scroll_info->timeout_id);
+ g_timer_destroy (area->priv->auto_scroll_info->timer);
+ g_free (area->priv->auto_scroll_info);
+
+ area->priv->auto_scroll_info = NULL;
+ }
+}
+
+static gboolean
+scroll_idle (gpointer data)
+{
+ GdkRectangle viewport, new_viewport;
+ FooScrollArea *area = data;
+ AutoScrollInfo *info = area->priv->auto_scroll_info;
+#if 0
+ int dx, dy;
+#endif
+ int new_x, new_y;
+ double elapsed;
+
+ get_viewport (area, &viewport);
+
+#if 0
+ g_print ("old info: %d %d\n", info->dx, info->dy);
+
+ g_print ("timeout (%d %d)\n", dx, dy);
+#endif
+
+#if 0
+ viewport.x += info->dx;
+ viewport.y += info->dy;
+#endif
+
+#if 0
+ g_print ("new info %d %d\n", info->dx, info->dy);
+#endif
+
+ elapsed = g_timer_elapsed (info->timer, NULL);
+
+ info->res_x = elapsed * info->dx / 0.2;
+ info->res_y = elapsed * info->dy / 0.2;
+
+#if 0
+ g_print ("%f %f\n", info->res_x, info->res_y);
+#endif
+
+ new_x = viewport.x + info->res_x;
+ new_y = viewport.y + info->res_y;
+
+#if 0
+ g_print ("%f\n", elapsed * (info->dx / 0.2));
+#endif
+
+#if 0
+ g_print ("new_x, new_y\n: %d %d\n", new_x, new_y);
+#endif
+
+ foo_scroll_area_set_viewport_pos (area, new_x, new_y);
+#if 0
+ viewport.x + info->dx,
+ viewport.y + info->dy);
+#endif
+
+ get_viewport (area, &new_viewport);
+
+ if (viewport.x == new_viewport.x &&
+ viewport.y == new_viewport.y &&
+ (info->res_x > 1.0 ||
+ info->res_y > 1.0 ||
+ info->res_x < -1.0 ||
+ info->res_y < -1.0))
+ {
+ stop_scrolling (area);
+
+ /* stop scrolling if it didn't have an effect */
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+ensure_scrolling (FooScrollArea *area,
+ int dx,
+ int dy)
+{
+ if (!area->priv->auto_scroll_info)
+ {
+#if 0
+ g_print ("start scrolling\n");
+#endif
+ area->priv->auto_scroll_info = g_new0 (AutoScrollInfo, 1);
+ area->priv->auto_scroll_info->timeout_id =
+ g_idle_add (scroll_idle, area);
+ area->priv->auto_scroll_info->timer = g_timer_new ();
+ }
+
+#if 0
+ g_print ("setting scrolling to %d %d\n", dx, dy);
+#endif
+
+#if 0
+ g_print ("dx, dy: %d %d\n", dx, dy);
+#endif
+
+ area->priv->auto_scroll_info->dx = dx;
+ area->priv->auto_scroll_info->dy = dy;
+}
+
+void
+foo_scroll_area_auto_scroll (FooScrollArea *scroll_area,
+ FooScrollAreaEvent *event)
+{
+ GdkRectangle viewport;
+
+ get_viewport (scroll_area, &viewport);
+
+ if (rect_contains (&viewport, event->x, event->y))
+ {
+ stop_scrolling (scroll_area);
+ }
+ else
+ {
+ int dx, dy;
+
+ dx = dy = 0;
+
+ if (event->y < viewport.y)
+ {
+ dy = event->y - viewport.y;
+ dy = MIN (dy + 2, 0);
+ }
+ else if (event->y >= viewport.y + viewport.height)
+ {
+ dy = event->y - (viewport.y + viewport.height - 1);
+ dy = MAX (dy - 2, 0);
+ }
+
+ if (event->x < viewport.x)
+ {
+ dx = event->x - viewport.x;
+ dx = MIN (dx + 2, 0);
+ }
+ else if (event->x >= viewport.x + viewport.width)
+ {
+ dx = event->x - (viewport.x + viewport.width - 1);
+ dx = MAX (dx - 2, 0);
+ }
+
+#if 0
+ g_print ("dx, dy: %d %d\n", dx, dy);
+#endif
+
+ ensure_scrolling (scroll_area, dx, dy);
+ }
+}
+
+void
+foo_scroll_area_begin_auto_scroll (FooScrollArea *scroll_area)
+{
+ /* noop for now */
+}
+
+void
+foo_scroll_area_end_auto_scroll (FooScrollArea *scroll_area)
+{
+ stop_scrolling (scroll_area);
+}
+
+
+
+#if 0
+/*
+ * Backing Store
+ */
+struct BackingStore
+{
+ GdkPixmap *pixmap;
+ GdkRegion *update_region;
+ int width;
+ int height;
+};
+
+static BackingStore *
+backing_store_new (GdkWindow *window,
+ int width, int height)
+{
+ BackingStore *store = g_new0 (BackingStore, 1);
+ GdkRectangle rect = { 0, 0, width, height };
+
+ store->pixmap = gdk_pixmap_new (window, width, height, -1);
+ store->update_region = gdk_region_rectangle (&rect);
+ store->width = width;
+ store->height = height;
+
+ return store;
+}
+
+static void
+backing_store_free (BackingStore *store)
+{
+ g_object_unref (store->pixmap);
+ gdk_region_destroy (store->update_region);
+ g_free (store);
+}
+
+static void
+backing_store_draw (BackingStore *store,
+ GdkDrawable *dest,
+ GdkRegion *clip,
+ int x,
+ int y)
+{
+ GdkGC *gc = gdk_gc_new (dest);
+
+ gdk_gc_set_clip_region (gc, clip);
+
+ gdk_draw_drawable (dest, gc, store->pixmap,
+ 0, 0, x, y, store->width, store->height);
+
+ g_object_unref (gc);
+}
+
+static void
+backing_store_scroll (BackingStore *store,
+ int dx,
+ int dy)
+{
+ GdkGC *gc = gdk_gc_new (store->pixmap);
+ GdkRectangle rect;
+
+ gdk_draw_drawable (store->pixmap, gc, store->pixmap,
+ 0, 0, dx, dy,
+ store->width, store->height);
+
+ /* Invalidate vertically */
+ rect.x = 0;
+ rect.width = store->width;
+
+ if (dy > 0)
+ {
+ rect.y = 0;
+ rect.height = dy;
+ }
+ else
+ {
+ rect.y = store->height + dy;
+ rect.y = -dy;
+ }
+
+ gdk_region_union_with_rect (store->update_region, &rect);
+
+ /* Invalidate horizontally */
+ rect.y = 0;
+ rect.height = store->height;
+
+ if (dx > 0)
+ {
+ rect.x = 0;
+ rect.width = dx;
+ }
+ else
+ {
+ rect.x = store->width + dx;
+ rect.width = -dx;
+ }
+
+ gdk_region_union_with_rect (store->update_region, &rect);
+}
+
+static void
+backing_store_invalidate_rect (BackingStore *store,
+ GdkRectangle *rect)
+{
+ gdk_region_union_with_rect (store->update_region, rect);
+}
+
+static void
+backing_store_invalidate_region (BackingStore *store,
+ GdkRegion *region)
+{
+ gdk_region_union (store->update_region, region);
+}
+
+static void
+backing_store_invalidate_all (BackingStore *store)
+{
+ GdkRectangle rect = { 0, 0, store->width, store->height };
+ gdk_region_destroy (store->update_region);
+ store->update_region = gdk_region_rectangle (&rect);
+}
+
+static void
+backing_store_resize (BackingStore *store,
+ int width,
+ int height)
+{
+ GdkPixmap *pixmap = gdk_pixmap_new (store->pixmap, width, height, -1);
+
+ /* Unfortunately we don't know in which direction we were resized,
+ * so we just assume we were dragged from the south-east corner.
+ *
+ * Although, maybe we could get the root coordinates of the input-window?
+ * That might just work, actually. We need to make sure marco uses
+ * static gravity for the window before this will be useful.
+ */
+ simple_draw_drawable (pixmap, store->pixmap, 0, 0, 0, 0, -1, -1);
+
+ g_object_unref (store->pixmap);
+
+ store->pixmap = pixmap;
+
+ /* FIXME: invalidate uncovered strip only */
+
+ backing_store_invalidate_all (store);
+}
+
+static void
+cclip_to_region (cairo_t *cr, GdkRegion *region)
+{
+ int n_rects;
+ GdkRectangle *rects;
+
+ gdk_region_get_rectangles (region, &rects, &n_rects);
+
+ cairo_new_path (cr);
+ while (n_rects--)
+ {
+ GdkRectangle *rect = &(rects[n_rects]);
+
+ cairo_rectangle (cr, rect->x, rect->y, rect->width, rect->height);
+ }
+ cairo_clip (cr);
+
+ g_free (rects);
+}
+
+static void
+backing_store_process_updates (BackingStore *store,
+ ExposeFunc func,
+ gpointer data)
+{
+ cairo_t *cr = gdk_cairo_create (store->pixmap);
+ GdkRegion *region = store->update_region;
+ store->update_region = gdk_region_new ();
+
+ cclip_to_region (cr, store->update_region);
+
+ func (cr, store->update_region, data);
+
+ gdk_region_destroy (region);
+ cairo_destroy (cr);
+}
+
+#endif
diff --git a/capplets/display/scrollarea.h b/capplets/display/scrollarea.h
new file mode 100644
index 00000000..d1695fad
--- /dev/null
+++ b/capplets/display/scrollarea.h
@@ -0,0 +1,124 @@
+/* Copyright 2006, 2007, 2008, Soren Sandmann <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#include <cairo.h>
+#include <gtk/gtk.h>
+
+#define FOO_TYPE_SCROLL_AREA (foo_scroll_area_get_type ())
+#define FOO_SCROLL_AREA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), FOO_TYPE_SCROLL_AREA, FooScrollArea))
+#define FOO_SCROLL_AREA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), FOO_TYPE_SCROLL_AREA, FooScrollAreaClass))
+#define FOO_IS_SCROLL_AREA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), FOO_TYPE_SCROLL_AREA))
+#define FOO_IS_SCROLL_AREA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), FOO_TYPE_SCROLL_AREA))
+#define FOO_SCROLL_AREA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), FOO_TYPE_SCROLL_AREA, FooScrollAreaClass))
+
+typedef struct FooScrollArea FooScrollArea;
+typedef struct FooScrollAreaClass FooScrollAreaClass;
+typedef struct FooScrollAreaPrivate FooScrollAreaPrivate;
+typedef struct FooScrollAreaEvent FooScrollAreaEvent;
+
+typedef enum
+{
+ FOO_BUTTON_PRESS,
+ FOO_BUTTON_RELEASE,
+ FOO_MOTION
+} FooScrollAreaEventType;
+
+struct FooScrollAreaEvent
+{
+ FooScrollAreaEventType type;
+ int x;
+ int y;
+};
+
+typedef void (* FooScrollAreaEventFunc) (FooScrollArea *area,
+ FooScrollAreaEvent *event,
+ gpointer data);
+
+struct FooScrollArea
+{
+ GtkContainer parent_instance;
+
+ FooScrollAreaPrivate *priv;
+};
+
+struct FooScrollAreaClass
+{
+ GtkContainerClass parent_class;
+
+ void (*set_scroll_adjustments) (FooScrollArea *scroll_area,
+ GtkAdjustment *hadjustment,
+ GtkAdjustment *vadjustment);
+
+ void (*viewport_changed) (FooScrollArea *scroll_area,
+ GdkRectangle *old_viewport,
+ GdkRectangle *new_viewport);
+
+ void (*paint) (FooScrollArea *scroll_area,
+ cairo_t *cr,
+ GdkRectangle *extents,
+ GdkRegion *region);
+};
+
+GType foo_scroll_area_get_type (void);
+
+FooScrollArea *foo_scroll_area_new (void);
+
+/* Set the requisition for the widget. */
+void foo_scroll_area_set_min_size (FooScrollArea *scroll_area,
+ int min_width,
+ int min_height);
+
+/* Set how much of the canvas can be scrolled into view */
+void foo_scroll_area_set_size (FooScrollArea *scroll_area,
+ int width,
+ int height);
+void foo_scroll_area_set_size_fixed_y (FooScrollArea *scroll_area,
+ int width,
+ int height,
+ int old_y,
+ int new_y);
+void foo_scroll_area_set_viewport_pos (FooScrollArea *scroll_area,
+ int x,
+ int y);
+void foo_scroll_area_get_viewport (FooScrollArea *scroll_area,
+ GdkRectangle *viewport);
+void foo_scroll_area_add_input_from_stroke (FooScrollArea *scroll_area,
+ cairo_t *cr,
+ FooScrollAreaEventFunc func,
+ gpointer data);
+void foo_scroll_area_add_input_from_fill (FooScrollArea *scroll_area,
+ cairo_t *cr,
+ FooScrollAreaEventFunc func,
+ gpointer data);
+void foo_scroll_area_invalidate_region (FooScrollArea *area,
+ GdkRegion *region);
+void foo_scroll_area_invalidate (FooScrollArea *scroll_area);
+void foo_scroll_area_invalidate_rect (FooScrollArea *scroll_area,
+ int x,
+ int y,
+ int width,
+ int height);
+void foo_scroll_area_begin_grab (FooScrollArea *scroll_area,
+ FooScrollAreaEventFunc func,
+ gpointer input_data);
+void foo_scroll_area_end_grab (FooScrollArea *scroll_area);
+gboolean foo_scroll_area_is_grabbed (FooScrollArea *scroll_area);
+
+void foo_scroll_area_begin_auto_scroll (FooScrollArea *scroll_area);
+void foo_scroll_area_auto_scroll (FooScrollArea *scroll_area,
+ FooScrollAreaEvent *event);
+void foo_scroll_area_end_auto_scroll (FooScrollArea *scroll_area);
diff --git a/capplets/display/xrandr-capplet.c b/capplets/display/xrandr-capplet.c
new file mode 100644
index 00000000..94de7771
--- /dev/null
+++ b/capplets/display/xrandr-capplet.c
@@ -0,0 +1,2571 @@
+/* Monitor Settings. A preference panel for configuring monitors
+ *
+ * Copyright (C) 2007, 2008 Red Hat, Inc.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Soren Sandmann <[email protected]>
+ */
+
+#include <config.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+
+#include <gtk/gtk.h>
+#include "scrollarea.h"
+#define MATE_DESKTOP_USE_UNSTABLE_API
+#include <libmateui/mate-rr.h>
+#include <libmateui/mate-rr-config.h>
+#include <libmateui/mate-rr-labeler.h>
+#include <gdk/gdkx.h>
+#include <X11/Xlib.h>
+#include <glib/gi18n.h>
+#include <mateconf/mateconf-client.h>
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-bindings.h>
+
+typedef struct App App;
+typedef struct GrabInfo GrabInfo;
+
+struct App
+{
+ MateRRScreen *screen;
+ MateRRConfig *current_configuration;
+ MateRRLabeler *labeler;
+ MateOutputInfo *current_output;
+
+ GtkWidget *dialog;
+ GtkWidget *current_monitor_event_box;
+ GtkWidget *current_monitor_label;
+ GtkWidget *monitor_on_radio;
+ GtkWidget *monitor_off_radio;
+ GtkListStore *resolution_store;
+ GtkWidget *resolution_combo;
+ GtkWidget *refresh_combo;
+ GtkWidget *rotation_combo;
+ GtkWidget *panel_checkbox;
+ GtkWidget *clone_checkbox;
+ GtkWidget *show_icon_checkbox;
+
+ /* We store the event timestamp when the Apply button is clicked */
+ GtkWidget *apply_button;
+ guint32 apply_button_clicked_timestamp;
+
+ GtkWidget *area;
+ gboolean ignore_gui_changes;
+ MateConfClient *client;
+
+ /* These are used while we are waiting for the ApplyConfiguration method to be executed over D-bus */
+ DBusGConnection *connection;
+ DBusGProxy *proxy;
+ DBusGProxyCall *proxy_call;
+
+ enum {
+ APPLYING_VERSION_1,
+ APPLYING_VERSION_2
+ } apply_configuration_state;
+};
+
+/* Response codes for custom buttons in the main dialog */
+enum {
+ RESPONSE_MAKE_DEFAULT = 1
+};
+
+static void rebuild_gui (App *app);
+static void on_clone_changed (GtkWidget *box, gpointer data);
+static void on_rate_changed (GtkComboBox *box, gpointer data);
+static gboolean output_overlaps (MateOutputInfo *output, MateRRConfig *config);
+static void select_current_output_from_dialog_position (App *app);
+static void monitor_on_off_toggled_cb (GtkToggleButton *toggle, gpointer data);
+static void get_geometry (MateOutputInfo *output, int *w, int *h);
+static void apply_configuration_returned_cb (DBusGProxy *proxy, DBusGProxyCall *call_id, void *data);
+static gboolean get_clone_size (MateRRScreen *screen, int *width, int *height);
+static gboolean output_info_supports_mode (App *app, MateOutputInfo *info, int width, int height);
+
+static void
+error_message (App *app, const char *primary_text, const char *secondary_text)
+{
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new ((app && app->dialog) ? GTK_WINDOW (app->dialog) : NULL,
+ GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ "%s", primary_text);
+
+ if (secondary_text)
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", secondary_text);
+
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+}
+
+static gboolean
+do_free (gpointer data)
+{
+ g_free (data);
+ return FALSE;
+}
+
+static gchar *
+idle_free (gchar *s)
+{
+ g_idle_add (do_free, s);
+
+ return s;
+}
+
+static void
+on_screen_changed (MateRRScreen *scr,
+ gpointer data)
+{
+ MateRRConfig *current;
+ App *app = data;
+
+ current = mate_rr_config_new_current (app->screen);
+
+ if (app->current_configuration)
+ mate_rr_config_free (app->current_configuration);
+
+ app->current_configuration = current;
+ app->current_output = NULL;
+
+ if (app->labeler) {
+ mate_rr_labeler_hide (app->labeler);
+ g_object_unref (app->labeler);
+ }
+
+ app->labeler = mate_rr_labeler_new (app->current_configuration);
+
+ select_current_output_from_dialog_position (app);
+}
+
+static void
+on_viewport_changed (FooScrollArea *scroll_area,
+ GdkRectangle *old_viewport,
+ GdkRectangle *new_viewport)
+{
+ foo_scroll_area_set_size (scroll_area,
+ new_viewport->width,
+ new_viewport->height);
+
+ foo_scroll_area_invalidate (scroll_area);
+}
+
+static void
+layout_set_font (PangoLayout *layout, const char *font)
+{
+ PangoFontDescription *desc =
+ pango_font_description_from_string (font);
+
+ if (desc)
+ {
+ pango_layout_set_font_description (layout, desc);
+
+ pango_font_description_free (desc);
+ }
+}
+
+static void
+clear_combo (GtkWidget *widget)
+{
+ GtkComboBox *box = GTK_COMBO_BOX (widget);
+ GtkTreeModel *model = gtk_combo_box_get_model (box);
+ GtkListStore *store = GTK_LIST_STORE (model);
+
+ gtk_list_store_clear (store);
+}
+
+typedef struct
+{
+ const char *text;
+ gboolean found;
+ GtkTreeIter iter;
+} ForeachInfo;
+
+static gboolean
+foreach (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ ForeachInfo *info = data;
+ char *text = NULL;
+
+ gtk_tree_model_get (model, iter, 0, &text, -1);
+
+ g_assert (text != NULL);
+
+ if (strcmp (info->text, text) == 0)
+ {
+ info->found = TRUE;
+ info->iter = *iter;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+add_key (GtkWidget *widget,
+ const char *text,
+ int width, int height, int rate,
+ MateRRRotation rotation)
+{
+ ForeachInfo info;
+ GtkComboBox *box = GTK_COMBO_BOX (widget);
+ GtkTreeModel *model = gtk_combo_box_get_model (box);
+ GtkListStore *store = GTK_LIST_STORE (model);
+ gboolean retval;
+
+ info.text = text;
+ info.found = FALSE;
+
+ gtk_tree_model_foreach (model, foreach, &info);
+
+ if (!info.found)
+ {
+ GtkTreeIter iter;
+ gtk_list_store_insert_with_values (store, &iter, -1,
+ 0, text,
+ 1, width,
+ 2, height,
+ 3, rate,
+ 4, width * height,
+ 5, rotation,
+ -1);
+
+ retval = TRUE;
+ }
+ else
+ {
+ retval = FALSE;
+ }
+}
+
+static gboolean
+combo_select (GtkWidget *widget, const char *text)
+{
+ GtkComboBox *box = GTK_COMBO_BOX (widget);
+ GtkTreeModel *model = gtk_combo_box_get_model (box);
+ ForeachInfo info;
+
+ info.text = text;
+ info.found = FALSE;
+
+ gtk_tree_model_foreach (model, foreach, &info);
+
+ if (!info.found)
+ return FALSE;
+
+ gtk_combo_box_set_active_iter (box, &info.iter);
+ return TRUE;
+}
+
+static MateRRMode **
+get_current_modes (App *app)
+{
+ MateRROutput *output;
+
+ if (app->current_configuration->clone)
+ {
+ return mate_rr_screen_list_clone_modes (app->screen);
+ }
+ else
+ {
+ if (!app->current_output)
+ return NULL;
+
+ output = mate_rr_screen_get_output_by_name (
+ app->screen, app->current_output->name);
+
+ if (!output)
+ return NULL;
+
+ return mate_rr_output_list_modes (output);
+ }
+}
+
+static void
+rebuild_rotation_combo (App *app)
+{
+ typedef struct
+ {
+ MateRRRotation rotation;
+ const char * name;
+ } RotationInfo;
+ static const RotationInfo rotations[] = {
+ { MATE_RR_ROTATION_0, N_("Normal") },
+ { MATE_RR_ROTATION_90, N_("Left") },
+ { MATE_RR_ROTATION_270, N_("Right") },
+ { MATE_RR_ROTATION_180, N_("Upside Down") },
+ };
+ const char *selection;
+ MateRRRotation current;
+ int i;
+
+ clear_combo (app->rotation_combo);
+
+ gtk_widget_set_sensitive (
+ app->rotation_combo, app->current_output && app->current_output->on);
+
+ if (!app->current_output)
+ return;
+
+ current = app->current_output->rotation;
+
+ selection = NULL;
+ for (i = 0; i < G_N_ELEMENTS (rotations); ++i)
+ {
+ const RotationInfo *info = &(rotations[i]);
+
+ app->current_output->rotation = info->rotation;
+
+ /* NULL-GError --- FIXME: we should say why this rotation is not available! */
+ if (mate_rr_config_applicable (app->current_configuration, app->screen, NULL))
+ {
+ add_key (app->rotation_combo, _(info->name), 0, 0, 0, info->rotation);
+
+ if (info->rotation == current)
+ selection = _(info->name);
+ }
+ }
+
+ app->current_output->rotation = current;
+
+ if (!(selection && combo_select (app->rotation_combo, selection)))
+ combo_select (app->rotation_combo, _("Normal"));
+}
+
+static char *
+make_rate_string (int hz)
+{
+ return g_strdup_printf (_("%d Hz"), hz);
+}
+
+static void
+rebuild_rate_combo (App *app)
+{
+ GHashTable *rates;
+ MateRRMode **modes;
+ int best;
+ int i;
+
+ clear_combo (app->refresh_combo);
+
+ gtk_widget_set_sensitive (
+ app->refresh_combo, app->current_output && app->current_output->on);
+
+ if (!app->current_output
+ || !(modes = get_current_modes (app)))
+ return;
+
+ rates = g_hash_table_new_full (
+ g_str_hash, g_str_equal, (GFreeFunc) g_free, NULL);
+
+ best = -1;
+ for (i = 0; modes[i] != NULL; ++i)
+ {
+ MateRRMode *mode = modes[i];
+ int width, height, rate;
+
+ width = mate_rr_mode_get_width (mode);
+ height = mate_rr_mode_get_height (mode);
+ rate = mate_rr_mode_get_freq (mode);
+
+ if (width == app->current_output->width &&
+ height == app->current_output->height)
+ {
+ add_key (app->refresh_combo,
+ idle_free (make_rate_string (rate)),
+ 0, 0, rate, -1);
+
+ if (rate > best)
+ best = rate;
+ }
+ }
+
+ if (!combo_select (app->refresh_combo, idle_free (make_rate_string (app->current_output->rate))))
+ combo_select (app->refresh_combo, idle_free (make_rate_string (best)));
+}
+
+static int
+count_active_outputs (App *app)
+{
+ int i, count = 0;
+
+ for (i = 0; app->current_configuration->outputs[i] != NULL; ++i)
+ {
+ MateOutputInfo *output = app->current_configuration->outputs[i];
+ if (output->on)
+ count++;
+ }
+
+ return count;
+}
+
+#if 0
+static int
+count_all_outputs (MateRRConfig *config)
+{
+ int i;
+
+ for (i = 0; config->outputs[i] != NULL; i++)
+ ;
+
+ return i;
+}
+#endif
+
+/* Computes whether "Mirror Screens" (clone mode) is supported based on these criteria:
+ *
+ * 1. There is an available size for cloning.
+ *
+ * 2. There are 2 or more connected outputs that support that size.
+ */
+static gboolean
+mirror_screens_is_supported (App *app)
+{
+ int clone_width, clone_height;
+ gboolean have_clone_size;
+ gboolean mirror_is_supported;
+
+ mirror_is_supported = FALSE;
+
+ have_clone_size = get_clone_size (app->screen, &clone_width, &clone_height);
+
+ if (have_clone_size) {
+ int i;
+ int num_outputs_with_clone_size;
+
+ num_outputs_with_clone_size = 0;
+
+ for (i = 0; app->current_configuration->outputs[i] != NULL; i++)
+ {
+ MateOutputInfo *output = app->current_configuration->outputs[i];
+
+ /* We count the connected outputs that support the clone size. It
+ * doesn't matter if those outputs aren't actually On currently; we
+ * will turn them on in on_clone_changed().
+ */
+ if (output->connected && output_info_supports_mode (app, output, clone_width, clone_height))
+ num_outputs_with_clone_size++;
+ }
+
+ if (num_outputs_with_clone_size >= 2)
+ mirror_is_supported = TRUE;
+ }
+
+ return mirror_is_supported;
+}
+
+static void
+rebuild_mirror_screens (App *app)
+{
+ gboolean mirror_is_active;
+ gboolean mirror_is_supported;
+
+ g_signal_handlers_block_by_func (app->clone_checkbox, G_CALLBACK (on_clone_changed), app);
+
+ mirror_is_active = app->current_configuration && app->current_configuration->clone;
+
+ /* If mirror_is_active, then it *must* be possible to turn mirroring off */
+ mirror_is_supported = mirror_is_active || mirror_screens_is_supported (app);
+
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (app->clone_checkbox), mirror_is_active);
+ gtk_widget_set_sensitive (app->clone_checkbox, mirror_is_supported);
+
+ g_signal_handlers_unblock_by_func (app->clone_checkbox, G_CALLBACK (on_clone_changed), app);
+}
+
+static void
+rebuild_current_monitor_label (App *app)
+{
+ char *str, *tmp;
+ GdkColor color;
+ gboolean use_color;
+
+ if (app->current_output)
+ {
+ if (app->current_configuration->clone)
+ tmp = g_strdup (_("Mirror Screens"));
+ else
+ tmp = g_strdup_printf (_("Monitor: %s"), app->current_output->display_name);
+
+ str = g_strdup_printf ("<b>%s</b>", tmp);
+ mate_rr_labeler_get_color_for_output (app->labeler, app->current_output, &color);
+ use_color = TRUE;
+ g_free (tmp);
+ }
+ else
+ {
+ str = g_strdup_printf ("<b>%s</b>", _("Monitor"));
+ use_color = FALSE;
+ }
+
+ gtk_label_set_markup (GTK_LABEL (app->current_monitor_label), str);
+ g_free (str);
+
+ if (use_color)
+ {
+ GdkColor black = { 0, 0, 0, 0 };
+
+ gtk_widget_modify_bg (app->current_monitor_event_box, gtk_widget_get_state (app->current_monitor_event_box), &color);
+
+ /* Make the label explicitly black. We don't want it to follow the
+ * theme's colors, since the label is always shown against a light
+ * pastel background. See bgo#556050
+ */
+ gtk_widget_modify_fg (app->current_monitor_label, gtk_widget_get_state (app->current_monitor_label), &black);
+ }
+ else
+ {
+ /* Remove any modifications we did on the label's color */
+ GtkRcStyle *reset_rc_style;
+
+ reset_rc_style = gtk_rc_style_new ();
+ gtk_widget_modify_style (app->current_monitor_label, reset_rc_style); /* takes ownership of, and destroys, the rc style */
+ }
+
+ gtk_event_box_set_visible_window (GTK_EVENT_BOX (app->current_monitor_event_box), use_color);
+}
+
+static void
+rebuild_on_off_radios (App *app)
+{
+ gboolean sensitive;
+ gboolean on_active;
+ gboolean off_active;
+
+ g_signal_handlers_block_by_func (app->monitor_on_radio, G_CALLBACK (monitor_on_off_toggled_cb), app);
+ g_signal_handlers_block_by_func (app->monitor_off_radio, G_CALLBACK (monitor_on_off_toggled_cb), app);
+
+ sensitive = FALSE;
+ on_active = FALSE;
+ off_active = FALSE;
+
+ if (!app->current_configuration->clone && app->current_output)
+ {
+ if (count_active_outputs (app) > 1 || !app->current_output->on)
+ sensitive = TRUE;
+ else
+ sensitive = FALSE;
+
+ on_active = app->current_output->on;
+ off_active = !on_active;
+ }
+
+ gtk_widget_set_sensitive (app->monitor_on_radio, sensitive);
+ gtk_widget_set_sensitive (app->monitor_off_radio, sensitive);
+
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (app->monitor_on_radio), on_active);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (app->monitor_off_radio), off_active);
+
+ g_signal_handlers_unblock_by_func (app->monitor_on_radio, G_CALLBACK (monitor_on_off_toggled_cb), app);
+ g_signal_handlers_unblock_by_func (app->monitor_off_radio, G_CALLBACK (monitor_on_off_toggled_cb), app);
+}
+
+static char *
+make_resolution_string (int width, int height)
+{
+ return g_strdup_printf (_("%d x %d"), width, height);
+}
+
+static void
+find_best_mode (MateRRMode **modes, int *out_width, int *out_height)
+{
+ int i;
+
+ *out_width = 0;
+ *out_height = 0;
+
+ for (i = 0; modes[i] != NULL; i++)
+ {
+ int w, h;
+
+ w = mate_rr_mode_get_width (modes[i]);
+ h = mate_rr_mode_get_height (modes[i]);
+
+ if (w * h > *out_width * *out_height)
+ {
+ *out_width = w;
+ *out_height = h;
+ }
+ }
+}
+
+static void
+rebuild_resolution_combo (App *app)
+{
+ int i;
+ MateRRMode **modes;
+ const char *current;
+
+ clear_combo (app->resolution_combo);
+
+ if (!(modes = get_current_modes (app))
+ || !app->current_output
+ || !app->current_output->on)
+ {
+ gtk_widget_set_sensitive (app->resolution_combo, FALSE);
+ return;
+ }
+
+ g_assert (app->current_output != NULL);
+ g_assert (app->current_output->width != 0 && app->current_output->height != 0);
+
+ gtk_widget_set_sensitive (app->resolution_combo, TRUE);
+
+ for (i = 0; modes[i] != NULL; ++i)
+ {
+ int width, height;
+
+ width = mate_rr_mode_get_width (modes[i]);
+ height = mate_rr_mode_get_height (modes[i]);
+
+ add_key (app->resolution_combo,
+ idle_free (make_resolution_string (width, height)),
+ width, height, 0, -1);
+ }
+
+ current = idle_free (make_resolution_string (app->current_output->width, app->current_output->height));
+
+ if (!combo_select (app->resolution_combo, current))
+ {
+ int best_w, best_h;
+
+ find_best_mode (modes, &best_w, &best_h);
+ combo_select (app->resolution_combo, idle_free (make_resolution_string (best_w, best_h)));
+ }
+}
+
+static void
+rebuild_gui (App *app)
+{
+ gboolean sensitive;
+
+ /* We would break spectacularly if we recursed, so
+ * just assert if that happens
+ */
+ g_assert (app->ignore_gui_changes == FALSE);
+
+ app->ignore_gui_changes = TRUE;
+
+ sensitive = app->current_output ? TRUE : FALSE;
+
+#if 0
+ g_debug ("rebuild gui, is on: %d", app->current_output->on);
+#endif
+
+ rebuild_mirror_screens (app);
+ rebuild_current_monitor_label (app);
+ rebuild_on_off_radios (app);
+ rebuild_resolution_combo (app);
+ rebuild_rate_combo (app);
+ rebuild_rotation_combo (app);
+
+#if 0
+ g_debug ("sensitive: %d, on: %d", sensitive, app->current_output->on);
+#endif
+ gtk_widget_set_sensitive (app->panel_checkbox, sensitive);
+
+ app->ignore_gui_changes = FALSE;
+}
+
+static gboolean
+get_mode (GtkWidget *widget, int *width, int *height, int *freq, MateRRRotation *rot)
+{
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+ GtkComboBox *box = GTK_COMBO_BOX (widget);
+ int dummy;
+
+ if (!gtk_combo_box_get_active_iter (box, &iter))
+ return FALSE;
+
+ if (!width)
+ width = &dummy;
+
+ if (!height)
+ height = &dummy;
+
+ if (!freq)
+ freq = &dummy;
+
+ if (!rot)
+ rot = (MateRRRotation *)&dummy;
+
+ model = gtk_combo_box_get_model (box);
+ gtk_tree_model_get (model, &iter,
+ 1, width,
+ 2, height,
+ 3, freq,
+ 5, rot,
+ -1);
+
+ return TRUE;
+
+}
+
+static void
+on_rotation_changed (GtkComboBox *box, gpointer data)
+{
+ App *app = data;
+ MateRRRotation rotation;
+
+ if (!app->current_output)
+ return;
+
+ if (get_mode (app->rotation_combo, NULL, NULL, NULL, &rotation))
+ app->current_output->rotation = rotation;
+
+ foo_scroll_area_invalidate (FOO_SCROLL_AREA (app->area));
+}
+
+static void
+on_rate_changed (GtkComboBox *box, gpointer data)
+{
+ App *app = data;
+ int rate;
+
+ if (!app->current_output)
+ return;
+
+ if (get_mode (app->refresh_combo, NULL, NULL, &rate, NULL))
+ app->current_output->rate = rate;
+
+ foo_scroll_area_invalidate (FOO_SCROLL_AREA (app->area));
+}
+
+static void
+select_resolution_for_current_output (App *app)
+{
+ MateRRMode **modes;
+ int width, height;
+
+ if (app->current_output->pref_width != 0 && app->current_output->pref_height != 0)
+ {
+ app->current_output->width = app->current_output->pref_width;
+ app->current_output->height = app->current_output->pref_height;
+ return;
+ }
+
+ modes = get_current_modes (app);
+ if (!modes)
+ return;
+
+ find_best_mode (modes, &width, &height);
+
+ app->current_output->width = width;
+ app->current_output->height = height;
+}
+
+static void
+monitor_on_off_toggled_cb (GtkToggleButton *toggle, gpointer data)
+{
+ App *app = data;
+ gboolean is_on;
+
+ if (!app->current_output)
+ return;
+
+ if (!gtk_toggle_button_get_active (toggle))
+ return;
+
+ if (GTK_WIDGET (toggle) == app->monitor_on_radio)
+ is_on = TRUE;
+ else if (GTK_WIDGET (toggle) == app->monitor_off_radio)
+ is_on = FALSE;
+ else
+ {
+ g_assert_not_reached ();
+ return;
+ }
+
+ app->current_output->on = is_on;
+
+ if (is_on)
+ select_resolution_for_current_output (app); /* The refresh rate will be picked in rebuild_rate_combo() */
+
+ rebuild_gui (app);
+ foo_scroll_area_invalidate (FOO_SCROLL_AREA (app->area));
+}
+
+static void
+realign_outputs_after_resolution_change (App *app, MateOutputInfo *output_that_changed, int old_width, int old_height)
+{
+ /* We find the outputs that were below or to the right of the output that
+ * changed, and realign them; we also do that for outputs that shared the
+ * right/bottom edges with the output that changed. The outputs that are
+ * above or to the left of that output don't need to change.
+ */
+
+ int i;
+ int old_right_edge, old_bottom_edge;
+ int dx, dy;
+
+ g_assert (app->current_configuration != NULL);
+
+ if (output_that_changed->width == old_width && output_that_changed->height == old_height)
+ return;
+
+ old_right_edge = output_that_changed->x + old_width;
+ old_bottom_edge = output_that_changed->y + old_height;
+
+ dx = output_that_changed->width - old_width;
+ dy = output_that_changed->height - old_height;
+
+ for (i = 0; app->current_configuration->outputs[i] != NULL; i++) {
+ MateOutputInfo *output;
+ int output_width, output_height;
+
+ output = app->current_configuration->outputs[i];
+
+ if (output == output_that_changed || !output->connected)
+ continue;
+
+ get_geometry (output, &output_width, &output_height);
+
+ if (output->x >= old_right_edge)
+ output->x += dx;
+ else if (output->x + output_width == old_right_edge)
+ output->x = output_that_changed->x + output_that_changed->width - output_width;
+
+ if (output->y >= old_bottom_edge)
+ output->y += dy;
+ else if (output->y + output_height == old_bottom_edge)
+ output->y = output_that_changed->y + output_that_changed->height - output_height;
+ }
+}
+
+static void
+on_resolution_changed (GtkComboBox *box, gpointer data)
+{
+ App *app = data;
+ int old_width, old_height;
+ int width;
+ int height;
+
+ if (!app->current_output)
+ return;
+
+ old_width = app->current_output->width;
+ old_height = app->current_output->height;
+
+ if (get_mode (app->resolution_combo, &width, &height, NULL, NULL))
+ {
+ app->current_output->width = width;
+ app->current_output->height = height;
+
+ if (width == 0 || height == 0)
+ app->current_output->on = FALSE;
+ else
+ app->current_output->on = TRUE;
+ }
+
+ realign_outputs_after_resolution_change (app, app->current_output, old_width, old_height);
+
+ rebuild_rate_combo (app);
+ rebuild_rotation_combo (app);
+
+ foo_scroll_area_invalidate (FOO_SCROLL_AREA (app->area));
+}
+
+static void
+lay_out_outputs_horizontally (App *app)
+{
+ int i;
+ int x;
+
+ /* Lay out all the monitors horizontally when "mirror screens" is turned
+ * off, to avoid having all of them overlapped initially. We put the
+ * outputs turned off on the right-hand side.
+ */
+
+ x = 0;
+
+ /* First pass, all "on" outputs */
+
+ for (i = 0; app->current_configuration->outputs[i]; ++i)
+ {
+ MateOutputInfo *output;
+
+ output = app->current_configuration->outputs[i];
+ if (output->connected && output->on) {
+ output->x = x;
+ output->y = 0;
+ x += output->width;
+ }
+ }
+
+ /* Second pass, all the black screens */
+
+ for (i = 0; app->current_configuration->outputs[i]; ++i)
+ {
+ MateOutputInfo *output;
+
+ output = app->current_configuration->outputs[i];
+ if (!(output->connected && output->on)) {
+ output->x = x;
+ output->y = 0;
+ x += output->width;
+ }
+ }
+
+}
+
+/* FIXME: this function is copied from mate-settings-daemon/plugins/xrandr/gsd-xrandr-manager.c.
+ * Do we need to put this function in mate-desktop for public use?
+ */
+static gboolean
+get_clone_size (MateRRScreen *screen, int *width, int *height)
+{
+ MateRRMode **modes = mate_rr_screen_list_clone_modes (screen);
+ int best_w, best_h;
+ int i;
+
+ best_w = 0;
+ best_h = 0;
+
+ for (i = 0; modes[i] != NULL; ++i) {
+ MateRRMode *mode = modes[i];
+ int w, h;
+
+ w = mate_rr_mode_get_width (mode);
+ h = mate_rr_mode_get_height (mode);
+
+ if (w * h > best_w * best_h) {
+ best_w = w;
+ best_h = h;
+ }
+ }
+
+ if (best_w > 0 && best_h > 0) {
+ if (width)
+ *width = best_w;
+ if (height)
+ *height = best_h;
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+output_info_supports_mode (App *app, MateOutputInfo *info, int width, int height)
+{
+ MateRROutput *output;
+ MateRRMode **modes;
+ int i;
+
+ if (!info->connected)
+ return FALSE;
+
+ output = mate_rr_screen_get_output_by_name (app->screen, info->name);
+ if (!output)
+ return FALSE;
+
+ modes = mate_rr_output_list_modes (output);
+
+ for (i = 0; modes[i]; i++) {
+ if (mate_rr_mode_get_width (modes[i]) == width
+ && mate_rr_mode_get_height (modes[i]) == height)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+on_clone_changed (GtkWidget *box, gpointer data)
+{
+ App *app = data;
+
+ app->current_configuration->clone =
+ gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (app->clone_checkbox));
+
+ if (app->current_configuration->clone)
+ {
+ int i;
+ int width, height;
+
+ for (i = 0; app->current_configuration->outputs[i]; ++i)
+ {
+ if (app->current_configuration->outputs[i]->connected)
+ {
+ app->current_output = app->current_configuration->outputs[i];
+ break;
+ }
+ }
+
+ /* Turn on all the connected screens that support the best clone mode.
+ * The user may hit "Mirror Screens", but he shouldn't have to turn on
+ * all the required outputs as well.
+ */
+
+ get_clone_size (app->screen, &width, &height);
+
+ for (i = 0; app->current_configuration->outputs[i]; i++) {
+ if (output_info_supports_mode (app, app->current_configuration->outputs[i], width, height)) {
+ app->current_configuration->outputs[i]->on = TRUE;
+ app->current_configuration->outputs[i]->width = width;
+ app->current_configuration->outputs[i]->height = height;
+ }
+ }
+ }
+ else
+ {
+ if (output_overlaps (app->current_output, app->current_configuration))
+ lay_out_outputs_horizontally (app);
+ }
+
+ rebuild_gui (app);
+}
+
+static void
+get_geometry (MateOutputInfo *output, int *w, int *h)
+{
+ if (output->on)
+ {
+ *h = output->height;
+ *w = output->width;
+ }
+ else
+ {
+ *h = output->pref_height;
+ *w = output->pref_width;
+ }
+ if ((output->rotation & MATE_RR_ROTATION_90) || (output->rotation & MATE_RR_ROTATION_270))
+ {
+ int tmp;
+ tmp = *h;
+ *h = *w;
+ *w = tmp;
+ }
+}
+
+#define SPACE 15
+#define MARGIN 15
+
+static GList *
+list_connected_outputs (App *app, int *total_w, int *total_h)
+{
+ int i, dummy;
+ GList *result = NULL;
+
+ if (!total_w)
+ total_w = &dummy;
+ if (!total_h)
+ total_h = &dummy;
+
+ *total_w = 0;
+ *total_h = 0;
+ for (i = 0; app->current_configuration->outputs[i] != NULL; ++i)
+ {
+ MateOutputInfo *output = app->current_configuration->outputs[i];
+
+ if (output->connected)
+ {
+ int w, h;
+
+ result = g_list_prepend (result, output);
+
+ get_geometry (output, &w, &h);
+
+ *total_w += w;
+ *total_h += h;
+ }
+ }
+
+ return g_list_reverse (result);
+}
+
+static int
+get_n_connected (App *app)
+{
+ GList *connected_outputs = list_connected_outputs (app, NULL, NULL);
+ int n = g_list_length (connected_outputs);
+
+ g_list_free (connected_outputs);
+
+ return n;
+}
+
+static double
+compute_scale (App *app)
+{
+ int available_w, available_h;
+ int total_w, total_h;
+ int n_monitors;
+ GdkRectangle viewport;
+ GList *connected_outputs;
+
+ foo_scroll_area_get_viewport (FOO_SCROLL_AREA (app->area), &viewport);
+
+ connected_outputs = list_connected_outputs (app, &total_w, &total_h);
+
+ n_monitors = g_list_length (connected_outputs);
+
+ g_list_free (connected_outputs);
+
+ available_w = viewport.width - 2 * MARGIN - (n_monitors - 1) * SPACE;
+ available_h = viewport.height - 2 * MARGIN - (n_monitors - 1) * SPACE;
+
+ return MIN ((double)available_w / total_w, (double)available_h / total_h);
+}
+
+typedef struct Edge
+{
+ MateOutputInfo *output;
+ int x1, y1;
+ int x2, y2;
+} Edge;
+
+typedef struct Snap
+{
+ Edge *snapper; /* Edge that should be snapped */
+ Edge *snappee;
+ int dy, dx;
+} Snap;
+
+static void
+add_edge (MateOutputInfo *output, int x1, int y1, int x2, int y2, GArray *edges)
+{
+ Edge e;
+
+ e.x1 = x1;
+ e.x2 = x2;
+ e.y1 = y1;
+ e.y2 = y2;
+ e.output = output;
+
+ g_array_append_val (edges, e);
+}
+
+static void
+list_edges_for_output (MateOutputInfo *output, GArray *edges)
+{
+ int x, y, w, h;
+
+ x = output->x;
+ y = output->y;
+ get_geometry (output, &w, &h);
+
+ /* Top, Bottom, Left, Right */
+ add_edge (output, x, y, x + w, y, edges);
+ add_edge (output, x, y + h, x + w, y + h, edges);
+ add_edge (output, x, y, x, y + h, edges);
+ add_edge (output, x + w, y, x + w, y + h, edges);
+}
+
+static void
+list_edges (MateRRConfig *config, GArray *edges)
+{
+ int i;
+
+ for (i = 0; config->outputs[i]; ++i)
+ {
+ MateOutputInfo *output = config->outputs[i];
+
+ if (output->connected)
+ list_edges_for_output (output, edges);
+ }
+}
+
+static gboolean
+overlap (int s1, int e1, int s2, int e2)
+{
+ return (!(e1 < s2 || s1 >= e2));
+}
+
+static gboolean
+horizontal_overlap (Edge *snapper, Edge *snappee)
+{
+ if (snapper->y1 != snapper->y2 || snappee->y1 != snappee->y2)
+ return FALSE;
+
+ return overlap (snapper->x1, snapper->x2, snappee->x1, snappee->x2);
+}
+
+static gboolean
+vertical_overlap (Edge *snapper, Edge *snappee)
+{
+ if (snapper->x1 != snapper->x2 || snappee->x1 != snappee->x2)
+ return FALSE;
+
+ return overlap (snapper->y1, snapper->y2, snappee->y1, snappee->y2);
+}
+
+static void
+add_snap (GArray *snaps, Snap snap)
+{
+ if (ABS (snap.dx) <= 200 || ABS (snap.dy) <= 200)
+ g_array_append_val (snaps, snap);
+}
+
+static void
+add_edge_snaps (Edge *snapper, Edge *snappee, GArray *snaps)
+{
+ Snap snap;
+
+ snap.snapper = snapper;
+ snap.snappee = snappee;
+
+ if (horizontal_overlap (snapper, snappee))
+ {
+ snap.dx = 0;
+ snap.dy = snappee->y1 - snapper->y1;
+
+ add_snap (snaps, snap);
+ }
+ else if (vertical_overlap (snapper, snappee))
+ {
+ snap.dy = 0;
+ snap.dx = snappee->x1 - snapper->x1;
+
+ add_snap (snaps, snap);
+ }
+
+ /* Corner snaps */
+ /* 1->1 */
+ snap.dx = snappee->x1 - snapper->x1;
+ snap.dy = snappee->y1 - snapper->y1;
+
+ add_snap (snaps, snap);
+
+ /* 1->2 */
+ snap.dx = snappee->x2 - snapper->x1;
+ snap.dy = snappee->y2 - snapper->y1;
+
+ add_snap (snaps, snap);
+
+ /* 2->2 */
+ snap.dx = snappee->x2 - snapper->x2;
+ snap.dy = snappee->y2 - snapper->y2;
+
+ add_snap (snaps, snap);
+
+ /* 2->1 */
+ snap.dx = snappee->x1 - snapper->x2;
+ snap.dy = snappee->y1 - snapper->y2;
+
+ add_snap (snaps, snap);
+}
+
+static void
+list_snaps (MateOutputInfo *output, GArray *edges, GArray *snaps)
+{
+ int i;
+
+ for (i = 0; i < edges->len; ++i)
+ {
+ Edge *output_edge = &(g_array_index (edges, Edge, i));
+
+ if (output_edge->output == output)
+ {
+ int j;
+
+ for (j = 0; j < edges->len; ++j)
+ {
+ Edge *edge = &(g_array_index (edges, Edge, j));
+
+ if (edge->output != output)
+ add_edge_snaps (output_edge, edge, snaps);
+ }
+ }
+ }
+}
+
+#if 0
+static void
+print_edge (Edge *edge)
+{
+ g_debug ("(%d %d %d %d)", edge->x1, edge->y1, edge->x2, edge->y2);
+}
+#endif
+
+static gboolean
+corner_on_edge (int x, int y, Edge *e)
+{
+ if (x == e->x1 && x == e->x2 && y >= e->y1 && y <= e->y2)
+ return TRUE;
+
+ if (y == e->y1 && y == e->y2 && x >= e->x1 && x <= e->x2)
+ return TRUE;
+
+ return FALSE;
+}
+
+static gboolean
+edges_align (Edge *e1, Edge *e2)
+{
+ if (corner_on_edge (e1->x1, e1->y1, e2))
+ return TRUE;
+
+ if (corner_on_edge (e2->x1, e2->y1, e1))
+ return TRUE;
+
+ return FALSE;
+}
+
+static gboolean
+output_is_aligned (MateOutputInfo *output, GArray *edges)
+{
+ gboolean result = FALSE;
+ int i;
+
+ for (i = 0; i < edges->len; ++i)
+ {
+ Edge *output_edge = &(g_array_index (edges, Edge, i));
+
+ if (output_edge->output == output)
+ {
+ int j;
+
+ for (j = 0; j < edges->len; ++j)
+ {
+ Edge *edge = &(g_array_index (edges, Edge, j));
+
+ /* We are aligned if an output edge matches
+ * an edge of another output
+ */
+ if (edge->output != output_edge->output)
+ {
+ if (edges_align (output_edge, edge))
+ {
+ result = TRUE;
+ goto done;
+ }
+ }
+ }
+ }
+ }
+done:
+
+ return result;
+}
+
+static void
+get_output_rect (MateOutputInfo *output, GdkRectangle *rect)
+{
+ int w, h;
+
+ get_geometry (output, &w, &h);
+
+ rect->width = w;
+ rect->height = h;
+ rect->x = output->x;
+ rect->y = output->y;
+}
+
+static gboolean
+output_overlaps (MateOutputInfo *output, MateRRConfig *config)
+{
+ int i;
+ GdkRectangle output_rect;
+
+ get_output_rect (output, &output_rect);
+
+ for (i = 0; config->outputs[i]; ++i)
+ {
+ MateOutputInfo *other = config->outputs[i];
+
+ if (other != output && other->connected)
+ {
+ GdkRectangle other_rect;
+
+ get_output_rect (other, &other_rect);
+ if (gdk_rectangle_intersect (&output_rect, &other_rect, NULL))
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static gboolean
+mate_rr_config_is_aligned (MateRRConfig *config, GArray *edges)
+{
+ int i;
+ gboolean result = TRUE;
+
+ for (i = 0; config->outputs[i]; ++i)
+ {
+ MateOutputInfo *output = config->outputs[i];
+
+ if (output->connected)
+ {
+ if (!output_is_aligned (output, edges))
+ return FALSE;
+
+ if (output_overlaps (output, config))
+ return FALSE;
+ }
+ }
+
+ return result;
+}
+
+struct GrabInfo
+{
+ int grab_x;
+ int grab_y;
+ int output_x;
+ int output_y;
+};
+
+static gboolean
+is_corner_snap (const Snap *s)
+{
+ return s->dx != 0 && s->dy != 0;
+}
+
+static int
+compare_snaps (gconstpointer v1, gconstpointer v2)
+{
+ const Snap *s1 = v1;
+ const Snap *s2 = v2;
+ int sv1 = MAX (ABS (s1->dx), ABS (s1->dy));
+ int sv2 = MAX (ABS (s2->dx), ABS (s2->dy));
+ int d;
+
+ d = sv1 - sv2;
+
+ /* This snapping algorithm is good enough for rock'n'roll, but
+ * this is probably a better:
+ *
+ * First do a horizontal/vertical snap, then
+ * with the new coordinates from that snap,
+ * do a corner snap.
+ *
+ * Right now, it's confusing that corner snapping
+ * depends on the distance in an axis that you can't actually see.
+ *
+ */
+ if (d == 0)
+ {
+ if (is_corner_snap (s1) && !is_corner_snap (s2))
+ return -1;
+ else if (is_corner_snap (s2) && !is_corner_snap (s1))
+ return 1;
+ else
+ return 0;
+ }
+ else
+ {
+ return d;
+ }
+}
+
+/* Sets a mouse cursor for a widget's window. As a hack, you can pass
+ * GDK_BLANK_CURSOR to mean "set the cursor to NULL" (i.e. reset the widget's
+ * window's cursor to its default).
+ */
+static void
+set_cursor (GtkWidget *widget, GdkCursorType type)
+{
+ GdkCursor *cursor;
+ GdkWindow *window;
+
+ if (type == GDK_BLANK_CURSOR)
+ cursor = NULL;
+ else
+ cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget), type);
+
+ window = gtk_widget_get_window (widget);
+
+ if (window)
+ gdk_window_set_cursor (window, cursor);
+
+ if (cursor)
+ gdk_cursor_unref (cursor);
+}
+
+static void
+set_monitors_tooltip (App *app, gboolean is_dragging)
+{
+ const char *text;
+
+ if (is_dragging)
+ text = NULL;
+ else
+ text = _("Select a monitor to change its properties; drag it to rearrange its placement.");
+
+ gtk_widget_set_tooltip_text (app->area, text);
+}
+
+static void
+on_output_event (FooScrollArea *area,
+ FooScrollAreaEvent *event,
+ gpointer data)
+{
+ MateOutputInfo *output = data;
+ App *app = g_object_get_data (G_OBJECT (area), "app");
+
+ /* If the mouse is inside the outputs, set the cursor to "you can move me". See
+ * on_canvas_event() for where we reset the cursor to the default if it
+ * exits the outputs' area.
+ */
+ if (!app->current_configuration->clone && get_n_connected (app) > 1)
+ set_cursor (GTK_WIDGET (area), GDK_FLEUR);
+
+ if (event->type == FOO_BUTTON_PRESS)
+ {
+ GrabInfo *info;
+
+ app->current_output = output;
+
+ rebuild_gui (app);
+ set_monitors_tooltip (app, TRUE);
+
+ if (!app->current_configuration->clone && get_n_connected (app) > 1)
+ {
+ foo_scroll_area_begin_grab (area, on_output_event, data);
+
+ info = g_new0 (GrabInfo, 1);
+ info->grab_x = event->x;
+ info->grab_y = event->y;
+ info->output_x = output->x;
+ info->output_y = output->y;
+
+ output->user_data = info;
+ }
+
+ foo_scroll_area_invalidate (area);
+ }
+ else
+ {
+ if (foo_scroll_area_is_grabbed (area))
+ {
+ GrabInfo *info = output->user_data;
+ double scale = compute_scale (app);
+ int old_x, old_y;
+ int new_x, new_y;
+ int i;
+ GArray *edges, *snaps, *new_edges;
+
+ old_x = output->x;
+ old_y = output->y;
+ new_x = info->output_x + (event->x - info->grab_x) / scale;
+ new_y = info->output_y + (event->y - info->grab_y) / scale;
+
+ output->x = new_x;
+ output->y = new_y;
+
+ edges = g_array_new (TRUE, TRUE, sizeof (Edge));
+ snaps = g_array_new (TRUE, TRUE, sizeof (Snap));
+ new_edges = g_array_new (TRUE, TRUE, sizeof (Edge));
+
+ list_edges (app->current_configuration, edges);
+ list_snaps (output, edges, snaps);
+
+ g_array_sort (snaps, compare_snaps);
+
+ output->x = info->output_x;
+ output->y = info->output_y;
+
+ for (i = 0; i < snaps->len; ++i)
+ {
+ Snap *snap = &(g_array_index (snaps, Snap, i));
+ GArray *new_edges = g_array_new (TRUE, TRUE, sizeof (Edge));
+
+ output->x = new_x + snap->dx;
+ output->y = new_y + snap->dy;
+
+ g_array_set_size (new_edges, 0);
+ list_edges (app->current_configuration, new_edges);
+
+ if (mate_rr_config_is_aligned (app->current_configuration, new_edges))
+ {
+ g_array_free (new_edges, TRUE);
+ break;
+ }
+ else
+ {
+ output->x = info->output_x;
+ output->y = info->output_y;
+ }
+ }
+
+ g_array_free (new_edges, TRUE);
+ g_array_free (snaps, TRUE);
+ g_array_free (edges, TRUE);
+
+ if (event->type == FOO_BUTTON_RELEASE)
+ {
+ foo_scroll_area_end_grab (area);
+ set_monitors_tooltip (app, FALSE);
+
+ g_free (output->user_data);
+ output->user_data = NULL;
+
+#if 0
+ g_debug ("new position: %d %d %d %d", output->x, output->y, output->width, output->height);
+#endif
+ }
+
+ foo_scroll_area_invalidate (area);
+ }
+ }
+}
+
+static void
+on_canvas_event (FooScrollArea *area,
+ FooScrollAreaEvent *event,
+ gpointer data)
+{
+ /* If the mouse exits the outputs, reset the cursor to the default. See
+ * on_output_event() for where we set the cursor to the movement cursor if
+ * it is over one of the outputs.
+ */
+ set_cursor (GTK_WIDGET (area), GDK_BLANK_CURSOR);
+}
+
+static PangoLayout *
+get_display_name (App *app,
+ MateOutputInfo *output)
+{
+ const char *text;
+
+ if (app->current_configuration->clone) {
+ /* Translators: this is the feature where what you see on your laptop's
+ * screen is the same as your external monitor. Here, "Mirror" is being
+ * used as an adjective, not as a verb. For example, the Spanish
+ * translation could be "Pantallas en Espejo", *not* "Espejar Pantallas".
+ */
+ text = _("Mirror Screens");
+ } else
+ text = output->display_name;
+
+ return gtk_widget_create_pango_layout (
+ GTK_WIDGET (app->area), text);
+}
+
+static void
+paint_background (FooScrollArea *area,
+ cairo_t *cr)
+{
+ GdkRectangle viewport;
+ GtkWidget *widget;
+ GtkStyle *widget_style;
+
+ widget = GTK_WIDGET (area);
+
+ foo_scroll_area_get_viewport (area, &viewport);
+ widget_style = gtk_widget_get_style (widget);
+
+ cairo_set_source_rgb (cr,
+ widget_style->base[GTK_STATE_SELECTED].red / 65535.0,
+ widget_style->base[GTK_STATE_SELECTED].green / 65535.0,
+ widget_style->base[GTK_STATE_SELECTED].blue / 65535.0);
+
+ cairo_rectangle (cr,
+ viewport.x, viewport.y,
+ viewport.width, viewport.height);
+
+ cairo_fill_preserve (cr);
+
+ foo_scroll_area_add_input_from_fill (area, cr, on_canvas_event, NULL);
+
+ cairo_set_source_rgb (cr,
+ widget_style->dark[GTK_STATE_SELECTED].red / 65535.0,
+ widget_style->dark[GTK_STATE_SELECTED].green / 65535.0,
+ widget_style->dark[GTK_STATE_SELECTED].blue / 65535.0);
+
+ cairo_stroke (cr);
+}
+
+static void
+paint_output (App *app, cairo_t *cr, int i)
+{
+ int w, h;
+ double scale = compute_scale (app);
+ double x, y;
+ int total_w, total_h;
+ GList *connected_outputs = list_connected_outputs (app, &total_w, &total_h);
+ MateOutputInfo *output = g_list_nth (connected_outputs, i)->data;
+ PangoLayout *layout = get_display_name (app, output);
+ PangoRectangle ink_extent, log_extent;
+ GdkRectangle viewport;
+ GdkColor output_color;
+ double r, g, b;
+ double available_w;
+ double factor;
+
+ cairo_save (cr);
+
+ foo_scroll_area_get_viewport (FOO_SCROLL_AREA (app->area), &viewport);
+
+ get_geometry (output, &w, &h);
+
+#if 0
+ g_debug ("%s (%p) geometry %d %d %d", output->name, output,
+ w, h, output->rate);
+#endif
+
+ viewport.height -= 2 * MARGIN;
+ viewport.width -= 2 * MARGIN;
+
+ x = output->x * scale + MARGIN + (viewport.width - total_w * scale) / 2.0;
+ y = output->y * scale + MARGIN + (viewport.height - total_h * scale) / 2.0;
+
+#if 0
+ g_debug ("scaled: %f %f", x, y);
+
+ g_debug ("scale: %f", scale);
+
+ g_debug ("%f %f %f %f", x, y, w * scale + 0.5, h * scale + 0.5);
+#endif
+
+ cairo_save (cr);
+
+ cairo_translate (cr,
+ x + (w * scale + 0.5) / 2,
+ y + (h * scale + 0.5) / 2);
+
+ /* rotation is already applied in get_geometry */
+
+ if (output->rotation & MATE_RR_REFLECT_X)
+ cairo_scale (cr, -1, 1);
+
+ if (output->rotation & MATE_RR_REFLECT_Y)
+ cairo_scale (cr, 1, -1);
+
+ cairo_translate (cr,
+ - x - (w * scale + 0.5) / 2,
+ - y - (h * scale + 0.5) / 2);
+
+
+ cairo_rectangle (cr, x, y, w * scale + 0.5, h * scale + 0.5);
+ cairo_clip_preserve (cr);
+
+ mate_rr_labeler_get_color_for_output (app->labeler, output, &output_color);
+ r = output_color.red / 65535.0;
+ g = output_color.green / 65535.0;
+ b = output_color.blue / 65535.0;
+
+ if (!output->on)
+ {
+ /* If the output is turned off, just darken the selected color */
+ r *= 0.2;
+ g *= 0.2;
+ b *= 0.2;
+ }
+
+ cairo_set_source_rgba (cr, r, g, b, 1.0);
+
+ foo_scroll_area_add_input_from_fill (FOO_SCROLL_AREA (app->area),
+ cr, on_output_event, output);
+ cairo_fill (cr);
+
+ if (output == app->current_output)
+ {
+ cairo_rectangle (cr, x + 2, y + 2, w * scale + 0.5 - 4, h * scale + 0.5 - 4);
+
+ cairo_set_line_width (cr, 4);
+ cairo_set_source_rgba (cr, 0.33, 0.43, 0.57, 1.0);
+ cairo_stroke (cr);
+ }
+
+ cairo_rectangle (cr, x + 0.5, y + 0.5, w * scale + 0.5 - 1, h * scale + 0.5 - 1);
+
+ cairo_set_line_width (cr, 1);
+ cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 1.0);
+
+ cairo_stroke (cr);
+ cairo_set_line_width (cr, 2);
+
+ layout_set_font (layout, "Sans Bold 12");
+ pango_layout_get_pixel_extents (layout, &ink_extent, &log_extent);
+
+ available_w = w * scale + 0.5 - 6; /* Same as the inner rectangle's width, minus 1 pixel of padding on each side */
+ if (available_w < ink_extent.width)
+ factor = available_w / ink_extent.width;
+ else
+ factor = 1.0;
+
+ cairo_move_to (cr,
+ x + ((w * scale + 0.5) - factor * log_extent.width) / 2,
+ y + ((h * scale + 0.5) - factor * log_extent.height) / 2);
+
+ cairo_scale (cr, factor, factor);
+
+ if (output->on)
+ cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
+ else
+ cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
+
+ pango_cairo_show_layout (cr, layout);
+
+ cairo_restore (cr);
+
+ g_object_unref (layout);
+}
+
+static void
+on_area_paint (FooScrollArea *area,
+ cairo_t *cr,
+ GdkRectangle *extent,
+ GdkRegion *region,
+ gpointer data)
+{
+ App *app = data;
+ double scale;
+ GList *connected_outputs = NULL;
+ GList *list;
+
+ paint_background (area, cr);
+
+ if (!app->current_configuration)
+ return;
+
+ scale = compute_scale (app);
+ connected_outputs = list_connected_outputs (app, NULL, NULL);
+
+#if 0
+ g_debug ("scale: %f", scale);
+#endif
+
+ for (list = connected_outputs; list != NULL; list = list->next)
+ {
+ paint_output (app, cr, g_list_position (connected_outputs, list));
+
+ if (app->current_configuration->clone)
+ break;
+ }
+}
+
+static void
+make_text_combo (GtkWidget *widget, int sort_column)
+{
+ GtkComboBox *box = GTK_COMBO_BOX (widget);
+ GtkListStore *store = gtk_list_store_new (
+ 6,
+ G_TYPE_STRING, /* Text */
+ G_TYPE_INT, /* Width */
+ G_TYPE_INT, /* Height */
+ G_TYPE_INT, /* Frequency */
+ G_TYPE_INT, /* Width * Height */
+ G_TYPE_INT); /* Rotation */
+
+ GtkCellRenderer *cell;
+
+ gtk_cell_layout_clear (GTK_CELL_LAYOUT (widget));
+
+ gtk_combo_box_set_model (box, GTK_TREE_MODEL (store));
+
+ cell = gtk_cell_renderer_text_new ();
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (box), cell, TRUE);
+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (box), cell,
+ "text", 0,
+ NULL);
+
+ if (sort_column != -1)
+ {
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
+ sort_column,
+ GTK_SORT_DESCENDING);
+ }
+}
+
+static void
+compute_virtual_size_for_configuration (MateRRConfig *config, int *ret_width, int *ret_height)
+{
+ int i;
+ int width, height;
+
+ width = height = 0;
+
+ for (i = 0; config->outputs[i] != NULL; i++)
+ {
+ MateOutputInfo *output;
+
+ output = config->outputs[i];
+
+ if (output->on)
+ {
+ width = MAX (width, output->x + output->width);
+ height = MAX (height, output->y + output->height);
+ }
+ }
+
+ *ret_width = width;
+ *ret_height = height;
+}
+
+static void
+check_required_virtual_size (App *app)
+{
+ int req_width, req_height;
+ int min_width, max_width;
+ int min_height, max_height;
+
+ compute_virtual_size_for_configuration (app->current_configuration, &req_width, &req_height);
+
+ mate_rr_screen_get_ranges (app->screen, &min_width, &max_width, &min_height, &max_height);
+
+#if 0
+ g_debug ("X Server supports:");
+ g_debug ("min_width = %d, max_width = %d", min_width, max_width);
+ g_debug ("min_height = %d, max_height = %d", min_height, max_height);
+
+ g_debug ("Requesting size of %dx%d", req_width, req_height);
+#endif
+
+ if (!(min_width <= req_width && req_width <= max_width
+ && min_height <= req_height && req_height <= max_height))
+ {
+ /* FIXME: present a useful dialog, maybe even before the user tries to Apply */
+#if 0
+ g_debug ("Your X server needs a larger Virtual size!");
+#endif
+ }
+}
+
+static void
+begin_version2_apply_configuration (App *app, GdkWindow *parent_window, guint32 timestamp)
+{
+ XID parent_window_xid;
+
+ parent_window_xid = GDK_WINDOW_XID (parent_window);
+
+ app->proxy = dbus_g_proxy_new_for_name (app->connection,
+ "org.mate.SettingsDaemon",
+ "/org/mate/SettingsDaemon/XRANDR",
+ "org.mate.SettingsDaemon.XRANDR_2");
+ g_assert (app->proxy != NULL); /* that call does not fail unless we pass bogus names */
+
+ app->apply_configuration_state = APPLYING_VERSION_2;
+ app->proxy_call = dbus_g_proxy_begin_call (app->proxy, "ApplyConfiguration",
+ apply_configuration_returned_cb, app,
+ NULL,
+ G_TYPE_INT64, (gint64) parent_window_xid,
+ G_TYPE_INT64, (gint64) timestamp,
+ G_TYPE_INVALID,
+ G_TYPE_INVALID);
+ /* FIXME: we don't check for app->proxy_call == NULL, which could happen if
+ * the connection was disconnected. This is left as an exercise for the
+ * reader.
+ */
+}
+
+static void
+begin_version1_apply_configuration (App *app)
+{
+ app->proxy = dbus_g_proxy_new_for_name (app->connection,
+ "org.mate.SettingsDaemon",
+ "/org/mate/SettingsDaemon/XRANDR",
+ "org.mate.SettingsDaemon.XRANDR");
+ g_assert (app->proxy != NULL); /* that call does not fail unless we pass bogus names */
+
+ app->apply_configuration_state = APPLYING_VERSION_1;
+ app->proxy_call = dbus_g_proxy_begin_call (app->proxy, "ApplyConfiguration",
+ apply_configuration_returned_cb, app,
+ NULL,
+ G_TYPE_INVALID,
+ G_TYPE_INVALID);
+ /* FIXME: we don't check for app->proxy_call == NULL, which could happen if
+ * the connection was disconnected. This is left as an exercise for the
+ * reader.
+ */
+}
+
+static void
+ensure_current_configuration_is_saved (void)
+{
+ MateRRScreen *rr_screen;
+ MateRRConfig *rr_config;
+
+ /* Normally, mate_rr_config_save() creates a backup file based on the
+ * old monitors.xml. However, if *that* file didn't exist, there is
+ * nothing from which to create a backup. So, here we'll save the
+ * current/unchanged configuration and then let our caller call
+ * mate_rr_config_save() again with the new/changed configuration, so
+ * that there *will* be a backup file in the end.
+ */
+
+ rr_screen = mate_rr_screen_new (gdk_screen_get_default (), NULL, NULL, NULL); /* NULL-GError */
+ if (!rr_screen)
+ return;
+
+ rr_config = mate_rr_config_new_current (rr_screen);
+ mate_rr_config_save (rr_config, NULL); /* NULL-GError */
+
+ mate_rr_config_free (rr_config);
+ mate_rr_screen_destroy (rr_screen);
+}
+
+/* Callback for dbus_g_proxy_begin_call() */
+static void
+apply_configuration_returned_cb (DBusGProxy *proxy,
+ DBusGProxyCall *call_id,
+ void *data)
+{
+ App *app = data;
+ gboolean success;
+ GError *error;
+
+ g_assert (call_id == app->proxy_call);
+
+ error = NULL;
+ success = dbus_g_proxy_end_call (proxy, call_id, &error, G_TYPE_INVALID);
+
+ if (!success) {
+ if (app->apply_configuration_state == APPLYING_VERSION_2
+ && g_error_matches (error, DBUS_GERROR, DBUS_GERROR_UNKNOWN_METHOD)) {
+ g_error_free (error);
+
+ g_object_unref (app->proxy);
+ app->proxy = NULL;
+
+ begin_version1_apply_configuration (app);
+ return;
+ } else {
+ /* We don't pop up an error message; mate-settings-daemon already does that
+ * in case the selected RANDR configuration could not be applied.
+ */
+ g_error_free (error);
+ }
+ }
+
+ g_object_unref (app->proxy);
+ app->proxy = NULL;
+
+ dbus_g_connection_unref (app->connection);
+ app->connection = NULL;
+ app->proxy_call = NULL;
+
+ gtk_widget_set_sensitive (app->dialog, TRUE);
+}
+
+static gboolean
+sanitize_and_save_configuration (App *app)
+{
+ GError *error;
+
+ mate_rr_config_sanitize (app->current_configuration);
+
+ check_required_virtual_size (app);
+
+ foo_scroll_area_invalidate (FOO_SCROLL_AREA (app->area));
+
+ ensure_current_configuration_is_saved ();
+
+ error = NULL;
+ if (!mate_rr_config_save (app->current_configuration, &error))
+ {
+ error_message (app, _("Could not save the monitor configuration"), error->message);
+ g_error_free (error);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+apply (App *app)
+{
+ GError *error = NULL;
+
+ if (!sanitize_and_save_configuration (app))
+ return;
+
+ g_assert (app->connection == NULL);
+ g_assert (app->proxy == NULL);
+ g_assert (app->proxy_call == NULL);
+
+ app->connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+ if (app->connection == NULL) {
+ error_message (app, _("Could not get session bus while applying display configuration"), error->message);
+ g_error_free (error);
+ return;
+ }
+
+ gtk_widget_set_sensitive (app->dialog, FALSE);
+
+ begin_version2_apply_configuration (app, gtk_widget_get_window (app->dialog), app->apply_button_clicked_timestamp);
+}
+
+#if 0
+/* Returns whether the graphics driver doesn't advertise RANDR 1.2 features, and just 1.0 */
+static gboolean
+driver_is_randr_10 (MateRRConfig *config)
+{
+ /* In the Xorg code, see xserver/randr/rrinfo.c:RRScanOldConfig(). It gets
+ * called when the graphics driver doesn't support RANDR 1.2 yet, just 1.0.
+ * In that case, the X server's base code (which supports RANDR 1.2) will
+ * simulate having a single output called "default". For drivers that *do*
+ * support RANDR 1.2, the separate outputs will be named differently, we
+ * hope.
+ *
+ * This heuristic is courtesy of Dirk Mueller <[email protected]>
+ *
+ * FIXME: however, we don't even check for XRRQueryVersion() returning 1.2, neither
+ * here nor in mate-desktop/libmatedesktop*.c. Do we need to check for that,
+ * or is mate_rr_screen_new()'s return value sufficient?
+ */
+
+ return (count_all_outputs (config) == 1 && strcmp (config->outputs[0]->name, "default") == 0);
+}
+#endif
+
+static void
+on_detect_displays (GtkWidget *widget, gpointer data)
+{
+ App *app = data;
+ GError *error;
+
+ error = NULL;
+ if (!mate_rr_screen_refresh (app->screen, &error)) {
+ if (error) {
+ error_message (app, _("Could not detect displays"), error->message);
+ g_error_free (error);
+ }
+ }
+}
+
+#define SHOW_ICON_KEY "/apps/mate_settings_daemon/xrandr/show_notification_icon"
+
+
+static void
+on_show_icon_toggled (GtkWidget *widget, gpointer data)
+{
+ GtkToggleButton *tb = GTK_TOGGLE_BUTTON (widget);
+ App *app = data;
+
+ mateconf_client_set_bool (app->client, SHOW_ICON_KEY,
+ gtk_toggle_button_get_active (tb), NULL);
+}
+
+static MateOutputInfo *
+get_nearest_output (MateRRConfig *configuration, int x, int y)
+{
+ int i;
+ int nearest_index;
+ int nearest_dist;
+
+ nearest_index = -1;
+ nearest_dist = G_MAXINT;
+
+ for (i = 0; configuration->outputs[i] != NULL; i++)
+ {
+ MateOutputInfo *output;
+ int dist_x, dist_y;
+
+ output = configuration->outputs[i];
+
+ if (!(output->connected && output->on))
+ continue;
+
+ if (x < output->x)
+ dist_x = output->x - x;
+ else if (x >= output->x + output->width)
+ dist_x = x - (output->x + output->width) + 1;
+ else
+ dist_x = 0;
+
+ if (y < output->y)
+ dist_y = output->y - y;
+ else if (y >= output->y + output->height)
+ dist_y = y - (output->y + output->height) + 1;
+ else
+ dist_y = 0;
+
+ if (MIN (dist_x, dist_y) < nearest_dist)
+ {
+ nearest_dist = MIN (dist_x, dist_y);
+ nearest_index = i;
+ }
+ }
+
+ if (nearest_index != -1)
+ return configuration->outputs[nearest_index];
+ else
+ return NULL;
+
+}
+
+/* Gets the output that contains the largest intersection with the window.
+ * Logic stolen from gdk_screen_get_monitor_at_window().
+ */
+static MateOutputInfo *
+get_output_for_window (MateRRConfig *configuration, GdkWindow *window)
+{
+ GdkRectangle win_rect;
+ int i;
+ int largest_area;
+ int largest_index;
+
+ gdk_window_get_geometry (window, &win_rect.x, &win_rect.y, &win_rect.width, &win_rect.height, NULL);
+ gdk_window_get_origin (window, &win_rect.x, &win_rect.y);
+
+ largest_area = 0;
+ largest_index = -1;
+
+ for (i = 0; configuration->outputs[i] != NULL; i++)
+ {
+ MateOutputInfo *output;
+ GdkRectangle output_rect, intersection;
+
+ output = configuration->outputs[i];
+
+ output_rect.x = output->x;
+ output_rect.y = output->y;
+ output_rect.width = output->width;
+ output_rect.height = output->height;
+
+ if (output->connected && gdk_rectangle_intersect (&win_rect, &output_rect, &intersection))
+ {
+ int area;
+
+ area = intersection.width * intersection.height;
+ if (area > largest_area)
+ {
+ largest_area = area;
+ largest_index = i;
+ }
+ }
+ }
+
+ if (largest_index != -1)
+ return configuration->outputs[largest_index];
+ else
+ return get_nearest_output (configuration,
+ win_rect.x + win_rect.width / 2,
+ win_rect.y + win_rect.height / 2);
+}
+
+/* We select the current output, i.e. select the one being edited, based on
+ * which output is showing the configuration dialog.
+ */
+static void
+select_current_output_from_dialog_position (App *app)
+{
+ if (gtk_widget_get_realized (app->dialog))
+ app->current_output = get_output_for_window (app->current_configuration, gtk_widget_get_window (app->dialog));
+ else
+ app->current_output = NULL;
+
+ rebuild_gui (app);
+}
+
+/* This is a GtkWidget::map-event handler. We wait for the display-properties
+ * dialog to be mapped, and then we select the output which corresponds to the
+ * monitor on which the dialog is being shown.
+ */
+static gboolean
+dialog_map_event_cb (GtkWidget *widget, GdkEventAny *event, gpointer data)
+{
+ App *app = data;
+
+ select_current_output_from_dialog_position (app);
+ return FALSE;
+}
+
+static void
+hide_help_button (App *app)
+{
+ GtkWidget *action_area;
+ GList *children;
+ GList *l;
+
+ action_area = gtk_dialog_get_action_area (GTK_DIALOG (app->dialog));
+ children = gtk_container_get_children (GTK_CONTAINER (action_area));
+
+ for (l = children; l; l = l->next)
+ {
+ GtkWidget *child;
+ int response;
+
+ child = GTK_WIDGET (l->data);
+
+ response = gtk_dialog_get_response_for_widget (GTK_DIALOG (app->dialog), child);
+ if (response == GTK_RESPONSE_HELP)
+ {
+ gtk_widget_hide (child);
+ return;
+ }
+ }
+}
+
+static void
+apply_button_clicked_cb (GtkButton *button, gpointer data)
+{
+ App *app = data;
+
+ /* We simply store the timestamp at which the Apply button was clicked.
+ * We'll just wait for the dialog to return from gtk_dialog_run(), and
+ * *then* use the timestamp when applying the RANDR configuration.
+ */
+
+ app->apply_button_clicked_timestamp = gtk_get_current_event_time ();
+}
+
+static void
+success_dialog_for_make_default (App *app)
+{
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new (GTK_WINDOW (app->dialog),
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_INFO,
+ GTK_BUTTONS_OK,
+ _("The monitor configuration has been saved"));
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ _("This configuration will be used the next time someone logs in."));
+
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+}
+
+static void
+error_dialog_for_make_default (App *app, const char *error_text)
+{
+ error_message (app, _("Could not set the default configuration for monitors"), error_text);
+}
+
+static void
+make_default (App *app)
+{
+ char *command_line;
+ char *source_filename;
+ char *dest_filename;
+ char *dest_basename;
+ char *std_error;
+ gint exit_status;
+ GError *error;
+
+ if (!sanitize_and_save_configuration (app))
+ return;
+
+ dest_filename = mateconf_client_get_string (app->client, "/apps/mate_settings_daemon/xrandr/default_configuration_file", NULL);
+ if (!dest_filename)
+ return; /* FIXME: present an error? */
+
+ dest_basename = g_path_get_basename (dest_filename);
+
+ source_filename = mate_rr_config_get_intended_filename ();
+
+ command_line = g_strdup_printf ("pkexec %s/mate-display-properties-install-systemwide %s %s",
+ SBINDIR,
+ source_filename,
+ dest_basename);
+
+ error = NULL;
+ if (!g_spawn_command_line_sync (command_line, NULL, &std_error, &exit_status, &error))
+ {
+ error_dialog_for_make_default (app, error->message);
+ g_error_free (error);
+ }
+ else if (!WIFEXITED (exit_status) || WEXITSTATUS (exit_status) != 0)
+ {
+ error_dialog_for_make_default (app, std_error);
+ }
+ else
+ {
+ success_dialog_for_make_default (app);
+ }
+
+ g_free (std_error);
+ g_free (dest_filename);
+ g_free (dest_basename);
+ g_free (source_filename);
+ g_free (command_line);
+}
+
+static GtkWidget*
+_gtk_builder_get_widget (GtkBuilder *builder, const gchar *name)
+{
+ return GTK_WIDGET (gtk_builder_get_object (builder, name));
+}
+
+static void
+run_application (App *app)
+{
+#ifndef UIDIR
+#define UIDIR "."
+#endif
+#define UI_FILE UIDIR "/display-capplet.ui"
+ GtkBuilder *builder;
+ GtkWidget *align;
+ GError *error;
+
+ error = NULL;
+ builder = gtk_builder_new ();
+
+ if (gtk_builder_add_from_file (builder, UI_FILE, &error) == 0)
+ {
+ g_warning ("Could not parse UI definition: %s", error->message);
+ g_error_free (error);
+ g_object_unref (builder);
+ return;
+ }
+
+ app->screen = mate_rr_screen_new (gdk_screen_get_default (),
+ on_screen_changed, app, &error);
+ if (!app->screen)
+ {
+ error_message (NULL, _("Could not get screen information"), error->message);
+ g_error_free (error);
+ g_object_unref (builder);
+ return;
+ }
+
+ app->client = mateconf_client_get_default ();
+
+ app->dialog = _gtk_builder_get_widget (builder, "dialog");
+ g_signal_connect_after (app->dialog, "map-event",
+ G_CALLBACK (dialog_map_event_cb), app);
+
+ gtk_window_set_default_icon_name ("mate-preferences-desktop-display");
+ gtk_window_set_icon_name (GTK_WINDOW (app->dialog),
+ "mate-preferences-desktop-display");
+
+ app->current_monitor_event_box = _gtk_builder_get_widget (builder,
+ "current_monitor_event_box");
+ app->current_monitor_label = _gtk_builder_get_widget (builder,
+ "current_monitor_label");
+
+ app->monitor_on_radio = _gtk_builder_get_widget (builder,
+ "monitor_on_radio");
+ app->monitor_off_radio = _gtk_builder_get_widget (builder,
+ "monitor_off_radio");
+ g_signal_connect (app->monitor_on_radio, "toggled",
+ G_CALLBACK (monitor_on_off_toggled_cb), app);
+ g_signal_connect (app->monitor_off_radio, "toggled",
+ G_CALLBACK (monitor_on_off_toggled_cb), app);
+
+ app->resolution_combo = _gtk_builder_get_widget (builder,
+ "resolution_combo");
+ g_signal_connect (app->resolution_combo, "changed",
+ G_CALLBACK (on_resolution_changed), app);
+
+ app->refresh_combo = _gtk_builder_get_widget (builder, "refresh_combo");
+ g_signal_connect (app->refresh_combo, "changed",
+ G_CALLBACK (on_rate_changed), app);
+
+ app->rotation_combo = _gtk_builder_get_widget (builder, "rotation_combo");
+ g_signal_connect (app->rotation_combo, "changed",
+ G_CALLBACK (on_rotation_changed), app);
+
+ app->clone_checkbox = _gtk_builder_get_widget (builder, "clone_checkbox");
+ g_signal_connect (app->clone_checkbox, "toggled",
+ G_CALLBACK (on_clone_changed), app);
+
+ g_signal_connect (_gtk_builder_get_widget (builder, "detect_displays_button"),
+ "clicked", G_CALLBACK (on_detect_displays), app);
+
+ app->show_icon_checkbox = _gtk_builder_get_widget (builder,
+ "show_notification_icon");
+
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (app->show_icon_checkbox),
+ mateconf_client_get_bool (app->client, SHOW_ICON_KEY, NULL));
+
+ g_signal_connect (app->show_icon_checkbox, "toggled", G_CALLBACK (on_show_icon_toggled), app);
+
+ app->panel_checkbox = _gtk_builder_get_widget (builder, "panel_checkbox");
+
+ make_text_combo (app->resolution_combo, 4);
+ make_text_combo (app->refresh_combo, 3);
+ make_text_combo (app->rotation_combo, -1);
+
+ g_assert (app->panel_checkbox);
+
+ /* Scroll Area */
+ app->area = (GtkWidget *)foo_scroll_area_new ();
+
+ g_object_set_data (G_OBJECT (app->area), "app", app);
+
+ set_monitors_tooltip (app, FALSE);
+
+ /* FIXME: this should be computed dynamically */
+ foo_scroll_area_set_min_size (FOO_SCROLL_AREA (app->area), -1, 200);
+ gtk_widget_show (app->area);
+ g_signal_connect (app->area, "paint",
+ G_CALLBACK (on_area_paint), app);
+ g_signal_connect (app->area, "viewport_changed",
+ G_CALLBACK (on_viewport_changed), app);
+
+ align = _gtk_builder_get_widget (builder, "align");
+
+ gtk_container_add (GTK_CONTAINER (align), app->area);
+
+ /* Until we have help to show, we'll just hide the Help button */
+ hide_help_button (app);
+
+ app->apply_button = _gtk_builder_get_widget (builder, "apply_button");
+ g_signal_connect (app->apply_button, "clicked",
+ G_CALLBACK (apply_button_clicked_cb), app);
+
+ on_screen_changed (app->screen, app);
+
+ g_object_unref (builder);
+
+restart:
+ switch (gtk_dialog_run (GTK_DIALOG (app->dialog)))
+ {
+ default:
+ /* Fall Through */
+ case GTK_RESPONSE_DELETE_EVENT:
+ case GTK_RESPONSE_CLOSE:
+#if 0
+ g_debug ("Close");
+#endif
+ break;
+
+ case GTK_RESPONSE_HELP:
+#if 0
+ g_debug ("Help");
+#endif
+ goto restart;
+ break;
+
+ case GTK_RESPONSE_APPLY:
+ apply (app);
+ goto restart;
+ break;
+
+ case RESPONSE_MAKE_DEFAULT:
+ make_default (app);
+ goto restart;
+ break;
+ }
+
+ gtk_widget_destroy (app->dialog);
+ mate_rr_screen_destroy (app->screen);
+ g_object_unref (app->client);
+}
+
+int
+main (int argc, char **argv)
+{
+ App *app;
+
+ bindtextdomain (GETTEXT_PACKAGE, MATELOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+ textdomain (GETTEXT_PACKAGE);
+
+ gtk_init (&argc, &argv);
+
+ app = g_new0 (App, 1);
+
+ run_application (app);
+
+ g_free (app);
+
+ return 0;
+}
diff --git a/capplets/keybindings/00-multimedia-key.xml.in b/capplets/keybindings/00-multimedia-key.xml.in
new file mode 100644
index 00000000..cd8263a1
--- /dev/null
+++ b/capplets/keybindings/00-multimedia-key.xml.in
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<KeyListEntries _name="Sound">
+
+ <KeyListEntry
+ name="/apps/mate_settings_daemon/keybindings/volume_mute" />
+
+ <KeyListEntry
+ name="/apps/mate_settings_daemon/keybindings/volume_down" />
+
+ <KeyListEntry
+ name="/apps/mate_settings_daemon/keybindings/volume_up" />
+
+ <KeyListEntry
+ name="/apps/mate_settings_daemon/keybindings/media" />
+
+ <KeyListEntry
+ name="/apps/mate_settings_daemon/keybindings/play" />
+
+ <KeyListEntry
+ name="/apps/mate_settings_daemon/keybindings/pause" />
+
+ <KeyListEntry
+ name="/apps/mate_settings_daemon/keybindings/stop" />
+
+ <KeyListEntry
+ name="/apps/mate_settings_daemon/keybindings/previous" />
+
+ <KeyListEntry
+ name="/apps/mate_settings_daemon/keybindings/next" />
+
+ <KeyListEntry
+ name="/apps/mate_settings_daemon/keybindings/eject" />
+
+</KeyListEntries>
+
diff --git a/capplets/keybindings/01-desktop-key.xml.in b/capplets/keybindings/01-desktop-key.xml.in
new file mode 100644
index 00000000..dc0234bb
--- /dev/null
+++ b/capplets/keybindings/01-desktop-key.xml.in
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<KeyListEntries _name="Desktop">
+
+ <KeyListEntry
+ name="/apps/mate_settings_daemon/keybindings/help" />
+
+ <KeyListEntry
+ name="/apps/mate_settings_daemon/keybindings/calculator" />
+
+ <KeyListEntry
+ name="/apps/mate_settings_daemon/keybindings/email" />
+
+ <KeyListEntry
+ name="/apps/mate_settings_daemon/keybindings/www" />
+
+ <KeyListEntry
+ name="/apps/mate_settings_daemon/keybindings/power" />
+
+ <KeyListEntry
+ name="/apps/mate_settings_daemon/keybindings/screensaver" />
+
+ <KeyListEntry
+ name="/apps/mate_settings_daemon/keybindings/home" />
+
+ <KeyListEntry
+ name="/apps/mate_settings_daemon/keybindings/search" />
+
+</KeyListEntries>
+
diff --git a/capplets/keybindings/Makefile.am b/capplets/keybindings/Makefile.am
new file mode 100644
index 00000000..ed97253f
--- /dev/null
+++ b/capplets/keybindings/Makefile.am
@@ -0,0 +1,46 @@
+# This is used in MATECC_CAPPLETS_CFLAGS
+cappletname = keybinding
+
+bin_PROGRAMS = mate-keybinding-properties
+
+mate_keybinding_properties_LDADD = $(MATECC_CAPPLETS_LIBS)
+mate_keybinding_properties_SOURCES = \
+ mate-keybinding-properties.c \
+ eggcellrendererkeys.c \
+ eggcellrendererkeys.h \
+ eggaccelerators.c \
+ eggaccelerators.h
+
+@INTLTOOL_DESKTOP_RULE@
+
+uidir = $(pkgdatadir)/ui
+ui_DATA = mate-keybinding-properties.ui
+
+desktopdir = $(datadir)/applications
+Desktop_in_files = mate-keybinding.desktop.in
+desktop_DATA = $(Desktop_in_files:.desktop.in=.desktop)
+
+@INTLTOOL_XML_NOMERGE_RULE@
+
+xmldir = $(pkgdatadir)/keybindings
+xml_in_files = 00-multimedia-key.xml.in 01-desktop-key.xml.in
+xml_DATA = $(xml_in_files:.xml.in=.xml)
+
+pkgconfigdir = $(datadir)/pkgconfig
+pkgconfig_DATA = mate-keybindings.pc
+
+INCLUDES = \
+ $(MATECC_CAPPLETS_CFLAGS) \
+ -DMATELOCALEDIR="\"$(datadir)/locale\"" \
+ -DMATECC_DATA_DIR="\"$(pkgdatadir)\"" \
+ -DMATECC_UI_DIR="\"$(uidir)\"" \
+ -DMATECC_KEYBINDINGS_DIR="\"$(pkgdatadir)/keybindings\""
+CLEANFILES = \
+ $(MATECC_CAPPLETS_CLEANFILES) \
+ $(Desktop_in_files) \
+ $(desktop_DATA) \
+ $(xml_DATA)
+EXTRA_DIST = $(ui_DATA) $(xml_in_files) mate-keybindings.pc.in
+
+
+-include $(top_srcdir)/git.mk
diff --git a/capplets/keybindings/eggaccelerators.c b/capplets/keybindings/eggaccelerators.c
new file mode 100644
index 00000000..0728229d
--- /dev/null
+++ b/capplets/keybindings/eggaccelerators.c
@@ -0,0 +1,632 @@
+/* eggaccelerators.c
+ * Copyright (C) 2002 Red Hat, Inc.; Copyright 1998, 2001 Tim Janik
+ * Developed by Havoc Pennington, Tim Janik
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "eggaccelerators.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <gdk/gdkx.h>
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtk.h>
+
+enum
+{
+ EGG_MODMAP_ENTRY_SHIFT = 0,
+ EGG_MODMAP_ENTRY_LOCK = 1,
+ EGG_MODMAP_ENTRY_CONTROL = 2,
+ EGG_MODMAP_ENTRY_MOD1 = 3,
+ EGG_MODMAP_ENTRY_MOD2 = 4,
+ EGG_MODMAP_ENTRY_MOD3 = 5,
+ EGG_MODMAP_ENTRY_MOD4 = 6,
+ EGG_MODMAP_ENTRY_MOD5 = 7,
+ EGG_MODMAP_ENTRY_LAST = 8
+};
+
+#define MODMAP_ENTRY_TO_MODIFIER(x) (1 << (x))
+
+typedef struct
+{
+ EggVirtualModifierType mapping[EGG_MODMAP_ENTRY_LAST];
+
+} EggModmap;
+
+const EggModmap* egg_keymap_get_modmap (GdkKeymap *keymap);
+
+static inline gboolean
+is_alt (const gchar *string)
+{
+ return ((string[0] == '<') &&
+ (string[1] == 'a' || string[1] == 'A') &&
+ (string[2] == 'l' || string[2] == 'L') &&
+ (string[3] == 't' || string[3] == 'T') &&
+ (string[4] == '>'));
+}
+
+static inline gboolean
+is_ctl (const gchar *string)
+{
+ return ((string[0] == '<') &&
+ (string[1] == 'c' || string[1] == 'C') &&
+ (string[2] == 't' || string[2] == 'T') &&
+ (string[3] == 'l' || string[3] == 'L') &&
+ (string[4] == '>'));
+}
+
+static inline gboolean
+is_modx (const gchar *string)
+{
+ return ((string[0] == '<') &&
+ (string[1] == 'm' || string[1] == 'M') &&
+ (string[2] == 'o' || string[2] == 'O') &&
+ (string[3] == 'd' || string[3] == 'D') &&
+ (string[4] >= '1' && string[4] <= '5') &&
+ (string[5] == '>'));
+}
+
+static inline gboolean
+is_ctrl (const gchar *string)
+{
+ return ((string[0] == '<') &&
+ (string[1] == 'c' || string[1] == 'C') &&
+ (string[2] == 't' || string[2] == 'T') &&
+ (string[3] == 'r' || string[3] == 'R') &&
+ (string[4] == 'l' || string[4] == 'L') &&
+ (string[5] == '>'));
+}
+
+static inline gboolean
+is_shft (const gchar *string)
+{
+ return ((string[0] == '<') &&
+ (string[1] == 's' || string[1] == 'S') &&
+ (string[2] == 'h' || string[2] == 'H') &&
+ (string[3] == 'f' || string[3] == 'F') &&
+ (string[4] == 't' || string[4] == 'T') &&
+ (string[5] == '>'));
+}
+
+static inline gboolean
+is_shift (const gchar *string)
+{
+ return ((string[0] == '<') &&
+ (string[1] == 's' || string[1] == 'S') &&
+ (string[2] == 'h' || string[2] == 'H') &&
+ (string[3] == 'i' || string[3] == 'I') &&
+ (string[4] == 'f' || string[4] == 'F') &&
+ (string[5] == 't' || string[5] == 'T') &&
+ (string[6] == '>'));
+}
+
+static inline gboolean
+is_control (const gchar *string)
+{
+ return ((string[0] == '<') &&
+ (string[1] == 'c' || string[1] == 'C') &&
+ (string[2] == 'o' || string[2] == 'O') &&
+ (string[3] == 'n' || string[3] == 'N') &&
+ (string[4] == 't' || string[4] == 'T') &&
+ (string[5] == 'r' || string[5] == 'R') &&
+ (string[6] == 'o' || string[6] == 'O') &&
+ (string[7] == 'l' || string[7] == 'L') &&
+ (string[8] == '>'));
+}
+
+static inline gboolean
+is_release (const gchar *string)
+{
+ return ((string[0] == '<') &&
+ (string[1] == 'r' || string[1] == 'R') &&
+ (string[2] == 'e' || string[2] == 'E') &&
+ (string[3] == 'l' || string[3] == 'L') &&
+ (string[4] == 'e' || string[4] == 'E') &&
+ (string[5] == 'a' || string[5] == 'A') &&
+ (string[6] == 's' || string[6] == 'S') &&
+ (string[7] == 'e' || string[7] == 'E') &&
+ (string[8] == '>'));
+}
+
+static inline gboolean
+is_meta (const gchar *string)
+{
+ return ((string[0] == '<') &&
+ (string[1] == 'm' || string[1] == 'M') &&
+ (string[2] == 'e' || string[2] == 'E') &&
+ (string[3] == 't' || string[3] == 'T') &&
+ (string[4] == 'a' || string[4] == 'A') &&
+ (string[5] == '>'));
+}
+
+static inline gboolean
+is_super (const gchar *string)
+{
+ return ((string[0] == '<') &&
+ (string[1] == 's' || string[1] == 'S') &&
+ (string[2] == 'u' || string[2] == 'U') &&
+ (string[3] == 'p' || string[3] == 'P') &&
+ (string[4] == 'e' || string[4] == 'E') &&
+ (string[5] == 'r' || string[5] == 'R') &&
+ (string[6] == '>'));
+}
+
+static inline gboolean
+is_hyper (const gchar *string)
+{
+ return ((string[0] == '<') &&
+ (string[1] == 'h' || string[1] == 'H') &&
+ (string[2] == 'y' || string[2] == 'Y') &&
+ (string[3] == 'p' || string[3] == 'P') &&
+ (string[4] == 'e' || string[4] == 'E') &&
+ (string[5] == 'r' || string[5] == 'R') &&
+ (string[6] == '>'));
+}
+
+static inline gboolean
+is_keycode (const gchar *string)
+{
+ return ((string[0] == '0') &&
+ (string[1] == 'x'));
+}
+
+/**
+ * egg_accelerator_parse_virtual:
+ * @accelerator: string representing an accelerator
+ * @accelerator_key: return location for accelerator keyval
+ * @accelerator_mods: return location for accelerator modifier mask
+ *
+ * Parses a string representing a virtual accelerator. The format
+ * looks like "&lt;Control&gt;a" or "&lt;Shift&gt;&lt;Alt&gt;F1" or
+ * "&lt;Release&gt;z" (the last one is for key release). The parser
+ * is fairly liberal and allows lower or upper case, and also
+ * abbreviations such as "&lt;Ctl&gt;" and "&lt;Ctrl&gt;".
+ *
+ * If the parse fails, @accelerator_key and @accelerator_mods will
+ * be set to 0 (zero) and %FALSE will be returned. If the string contains
+ * only modifiers, @accelerator_key will be set to 0 but %TRUE will be
+ * returned.
+ *
+ * The virtual vs. concrete accelerator distinction is a relic of
+ * how the X Window System works; there are modifiers Mod2-Mod5 that
+ * can represent various keyboard keys (numlock, meta, hyper, etc.),
+ * the virtual modifier represents the keyboard key, the concrete
+ * modifier the actual Mod2-Mod5 bits in the key press event.
+ *
+ * Returns: %TRUE on success.
+ */
+gboolean
+egg_accelerator_parse_virtual (const gchar *accelerator,
+ guint *accelerator_key,
+ guint *keycode,
+ EggVirtualModifierType *accelerator_mods)
+{
+ guint keyval;
+ GdkModifierType mods;
+ gint len;
+ gboolean bad_keyval;
+
+ if (accelerator_key)
+ *accelerator_key = 0;
+ if (accelerator_mods)
+ *accelerator_mods = 0;
+ if (keycode)
+ *keycode = 0;
+
+ g_return_val_if_fail (accelerator != NULL, FALSE);
+
+ bad_keyval = FALSE;
+
+ keyval = 0;
+ mods = 0;
+ len = strlen (accelerator);
+ while (len)
+ {
+ if (*accelerator == '<')
+ {
+ if (len >= 9 && is_release (accelerator))
+ {
+ accelerator += 9;
+ len -= 9;
+ mods |= EGG_VIRTUAL_RELEASE_MASK;
+ }
+ else if (len >= 9 && is_control (accelerator))
+ {
+ accelerator += 9;
+ len -= 9;
+ mods |= EGG_VIRTUAL_CONTROL_MASK;
+ }
+ else if (len >= 7 && is_shift (accelerator))
+ {
+ accelerator += 7;
+ len -= 7;
+ mods |= EGG_VIRTUAL_SHIFT_MASK;
+ }
+ else if (len >= 6 && is_shft (accelerator))
+ {
+ accelerator += 6;
+ len -= 6;
+ mods |= EGG_VIRTUAL_SHIFT_MASK;
+ }
+ else if (len >= 6 && is_ctrl (accelerator))
+ {
+ accelerator += 6;
+ len -= 6;
+ mods |= EGG_VIRTUAL_CONTROL_MASK;
+ }
+ else if (len >= 6 && is_modx (accelerator))
+ {
+ static const guint mod_vals[] = {
+ EGG_VIRTUAL_ALT_MASK, EGG_VIRTUAL_MOD2_MASK, EGG_VIRTUAL_MOD3_MASK,
+ EGG_VIRTUAL_MOD4_MASK, EGG_VIRTUAL_MOD5_MASK
+ };
+
+ len -= 6;
+ accelerator += 4;
+ mods |= mod_vals[*accelerator - '1'];
+ accelerator += 2;
+ }
+ else if (len >= 5 && is_ctl (accelerator))
+ {
+ accelerator += 5;
+ len -= 5;
+ mods |= EGG_VIRTUAL_CONTROL_MASK;
+ }
+ else if (len >= 5 && is_alt (accelerator))
+ {
+ accelerator += 5;
+ len -= 5;
+ mods |= EGG_VIRTUAL_ALT_MASK;
+ }
+ else if (len >= 6 && is_meta (accelerator))
+ {
+ accelerator += 6;
+ len -= 6;
+ mods |= EGG_VIRTUAL_META_MASK;
+ }
+ else if (len >= 7 && is_hyper (accelerator))
+ {
+ accelerator += 7;
+ len -= 7;
+ mods |= EGG_VIRTUAL_HYPER_MASK;
+ }
+ else if (len >= 7 && is_super (accelerator))
+ {
+ accelerator += 7;
+ len -= 7;
+ mods |= EGG_VIRTUAL_SUPER_MASK;
+ }
+ else
+ {
+ gchar last_ch;
+
+ last_ch = *accelerator;
+ while (last_ch && last_ch != '>')
+ {
+ last_ch = *accelerator;
+ accelerator += 1;
+ len -= 1;
+ }
+ }
+ }
+ else
+ {
+ keyval = gdk_keyval_from_name (accelerator);
+
+ if (keyval == 0)
+ {
+ /* If keyval is 0, then maybe it's a keycode. Check for 0x## */
+ if (len >= 4 && is_keycode (accelerator))
+ {
+ char keystring[5];
+ gchar *endptr;
+ gint tmp_keycode;
+
+ memcpy (keystring, accelerator, 4);
+ keystring [4] = '\000';
+
+ tmp_keycode = strtol (keystring, &endptr, 16);
+
+ if (endptr == NULL || *endptr != '\000')
+ {
+ bad_keyval = TRUE;
+ }
+ else if (keycode != NULL)
+ {
+ *keycode = tmp_keycode;
+ /* 0x00 is an invalid keycode too. */
+ if (*keycode == 0)
+ bad_keyval = TRUE;
+ }
+ }
+ }
+ else if (keycode != NULL)
+ {
+ *keycode = XKeysymToKeycode (GDK_DISPLAY(), keyval);
+ if (*keycode == 0)
+ bad_keyval = TRUE;
+ }
+
+ accelerator += len;
+ len -= len;
+ }
+ }
+
+ if (accelerator_key)
+ *accelerator_key = gdk_keyval_to_lower (keyval);
+ if (accelerator_mods)
+ *accelerator_mods = mods;
+
+ return !bad_keyval;
+}
+
+/**
+ * egg_virtual_accelerator_name:
+ * @accelerator_key: accelerator keyval
+ * @accelerator_mods: accelerator modifier mask
+ * @returns: a newly-allocated accelerator name
+ *
+ * Converts an accelerator keyval and modifier mask
+ * into a string parseable by egg_accelerator_parse_virtual().
+ * For example, if you pass in #GDK_q and #EGG_VIRTUAL_CONTROL_MASK,
+ * this function returns "&lt;Control&gt;q".
+ *
+ * The caller of this function must free the returned string.
+ */
+gchar*
+egg_virtual_accelerator_name (guint accelerator_key,
+ guint keycode,
+ EggVirtualModifierType accelerator_mods)
+{
+ gchar *gtk_name;
+ GdkModifierType gdkmods = 0;
+
+ egg_keymap_resolve_virtual_modifiers (NULL, accelerator_mods, &gdkmods);
+ gtk_name = gtk_accelerator_name (accelerator_key, gdkmods);
+
+ if (!accelerator_key)
+ {
+ gchar *name;
+ name = g_strdup_printf ("%s0x%02x", gtk_name, keycode);
+ g_free (gtk_name);
+ return name;
+ }
+
+ return gtk_name;
+}
+
+/**
+ * egg_virtual_accelerator_label:
+ * @accelerator_key: accelerator keyval
+ * @accelerator_mods: accelerator modifier mask
+ * @returns: a newly-allocated accelerator label
+ *
+ * Converts an accelerator keyval and modifier mask
+ * into a (possibly translated) string that can be displayed to
+ * a user.
+ * For example, if you pass in #GDK_q and #EGG_VIRTUAL_CONTROL_MASK,
+ * and you use a German locale, this function returns "Strg+Q".
+ *
+ * The caller of this function must free the returned string.
+ */
+gchar*
+egg_virtual_accelerator_label (guint accelerator_key,
+ guint keycode,
+ EggVirtualModifierType accelerator_mods)
+{
+ gchar *gtk_label;
+ GdkModifierType gdkmods = 0;
+
+ egg_keymap_resolve_virtual_modifiers (NULL, accelerator_mods, &gdkmods);
+ gtk_label = gtk_accelerator_get_label (accelerator_key, gdkmods);
+
+ if (!accelerator_key)
+ {
+ gchar *label;
+ label = g_strdup_printf ("%s0x%02x", gtk_label, keycode);
+ g_free (gtk_label);
+ return label;
+ }
+
+ return gtk_label;
+}
+
+void
+egg_keymap_resolve_virtual_modifiers (GdkKeymap *keymap,
+ EggVirtualModifierType virtual_mods,
+ GdkModifierType *concrete_mods)
+{
+ GdkModifierType concrete;
+ int i;
+ const EggModmap *modmap;
+
+ g_return_if_fail (concrete_mods != NULL);
+ g_return_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap));
+
+ modmap = egg_keymap_get_modmap (keymap);
+
+ /* Not so sure about this algorithm. */
+
+ concrete = 0;
+ for (i = 0; i < EGG_MODMAP_ENTRY_LAST; ++i)
+ {
+ if (modmap->mapping[i] & virtual_mods)
+ concrete |= MODMAP_ENTRY_TO_MODIFIER (i);
+ }
+
+ *concrete_mods = concrete;
+}
+
+void
+egg_keymap_virtualize_modifiers (GdkKeymap *keymap,
+ GdkModifierType concrete_mods,
+ EggVirtualModifierType *virtual_mods)
+{
+ GdkModifierType virtual;
+ int i;
+ const EggModmap *modmap;
+
+ g_return_if_fail (virtual_mods != NULL);
+ g_return_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap));
+
+ modmap = egg_keymap_get_modmap (keymap);
+
+ /* Not so sure about this algorithm. */
+
+ virtual = 0;
+ for (i = 0; i < EGG_MODMAP_ENTRY_LAST; ++i)
+ {
+ if (MODMAP_ENTRY_TO_MODIFIER (i) & concrete_mods)
+ {
+ EggVirtualModifierType cleaned;
+
+ cleaned = modmap->mapping[i] & ~(EGG_VIRTUAL_MOD2_MASK |
+ EGG_VIRTUAL_MOD3_MASK |
+ EGG_VIRTUAL_MOD4_MASK |
+ EGG_VIRTUAL_MOD5_MASK);
+
+ if (cleaned != 0)
+ {
+ virtual |= cleaned;
+ }
+ else
+ {
+ /* Rather than dropping mod2->mod5 if not bound,
+ * go ahead and use the concrete names
+ */
+ virtual |= modmap->mapping[i];
+ }
+ }
+ }
+
+ *virtual_mods = virtual;
+}
+
+static void
+reload_modmap (GdkKeymap *keymap,
+ EggModmap *modmap)
+{
+ XModifierKeymap *xmodmap;
+ int map_size;
+ int i;
+
+ /* FIXME multihead */
+ xmodmap = XGetModifierMapping (gdk_x11_get_default_xdisplay ());
+
+ memset (modmap->mapping, 0, sizeof (modmap->mapping));
+
+ /* there are 8 modifiers in the order shift, shift lock,
+ * control, mod1-5 with up to max_keypermod bindings each
+ */
+ map_size = 8 * xmodmap->max_keypermod;
+ for (i = 3 * xmodmap->max_keypermod; i < map_size; ++i)
+ {
+ /* get the key code at this point in the map,
+ * see if its keysym is one we're interested in
+ */
+ int keycode = xmodmap->modifiermap[i];
+ GdkKeymapKey *keys;
+ guint *keyvals;
+ int n_entries;
+ int j;
+ EggVirtualModifierType mask;
+
+ keys = NULL;
+ keyvals = NULL;
+ n_entries = 0;
+
+ gdk_keymap_get_entries_for_keycode (keymap,
+ keycode,
+ &keys, &keyvals, &n_entries);
+
+ mask = 0;
+ for (j = 0; j < n_entries; ++j)
+ {
+ if (keyvals[j] == GDK_Num_Lock)
+ mask |= EGG_VIRTUAL_NUM_LOCK_MASK;
+ else if (keyvals[j] == GDK_Scroll_Lock)
+ mask |= EGG_VIRTUAL_SCROLL_LOCK_MASK;
+ else if (keyvals[j] == GDK_Meta_L ||
+ keyvals[j] == GDK_Meta_R)
+ mask |= EGG_VIRTUAL_META_MASK;
+ else if (keyvals[j] == GDK_Hyper_L ||
+ keyvals[j] == GDK_Hyper_R)
+ mask |= EGG_VIRTUAL_HYPER_MASK;
+ else if (keyvals[j] == GDK_Super_L ||
+ keyvals[j] == GDK_Super_R)
+ mask |= EGG_VIRTUAL_SUPER_MASK;
+ else if (keyvals[j] == GDK_Mode_switch)
+ mask |= EGG_VIRTUAL_MODE_SWITCH_MASK;
+ }
+
+ /* Mod1Mask is 1 << 3 for example, i.e. the
+ * fourth modifier, i / keyspermod is the modifier
+ * index
+ */
+ modmap->mapping[i/xmodmap->max_keypermod] |= mask;
+
+ g_free (keyvals);
+ g_free (keys);
+ }
+
+ /* Add in the not-really-virtual fixed entries */
+ modmap->mapping[EGG_MODMAP_ENTRY_SHIFT] |= EGG_VIRTUAL_SHIFT_MASK;
+ modmap->mapping[EGG_MODMAP_ENTRY_CONTROL] |= EGG_VIRTUAL_CONTROL_MASK;
+ modmap->mapping[EGG_MODMAP_ENTRY_LOCK] |= EGG_VIRTUAL_LOCK_MASK;
+ modmap->mapping[EGG_MODMAP_ENTRY_MOD1] |= EGG_VIRTUAL_ALT_MASK;
+ modmap->mapping[EGG_MODMAP_ENTRY_MOD2] |= EGG_VIRTUAL_MOD2_MASK;
+ modmap->mapping[EGG_MODMAP_ENTRY_MOD3] |= EGG_VIRTUAL_MOD3_MASK;
+ modmap->mapping[EGG_MODMAP_ENTRY_MOD4] |= EGG_VIRTUAL_MOD4_MASK;
+ modmap->mapping[EGG_MODMAP_ENTRY_MOD5] |= EGG_VIRTUAL_MOD5_MASK;
+
+ XFreeModifiermap (xmodmap);
+}
+
+const EggModmap*
+egg_keymap_get_modmap (GdkKeymap *keymap)
+{
+ EggModmap *modmap;
+
+ if (keymap == NULL)
+ keymap = gdk_keymap_get_default ();
+
+ /* This is all a hack, much simpler when we can just
+ * modify GDK directly.
+ */
+
+ modmap = g_object_get_data (G_OBJECT (keymap), "egg-modmap");
+
+ if (modmap == NULL)
+ {
+ modmap = g_new0 (EggModmap, 1);
+
+ /* FIXME modify keymap change events with an event filter
+ * and force a reload if we get one
+ */
+
+ reload_modmap (keymap, modmap);
+
+ g_object_set_data_full (G_OBJECT (keymap),
+ "egg-modmap",
+ modmap,
+ g_free);
+ }
+
+ g_assert (modmap != NULL);
+
+ return modmap;
+}
diff --git a/capplets/keybindings/eggaccelerators.h b/capplets/keybindings/eggaccelerators.h
new file mode 100644
index 00000000..660f5670
--- /dev/null
+++ b/capplets/keybindings/eggaccelerators.h
@@ -0,0 +1,99 @@
+/* eggaccelerators.h
+ * Copyright (C) 2002 Red Hat, Inc.
+ * Developed by Havoc Pennington
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __EGG_ACCELERATORS_H__
+#define __EGG_ACCELERATORS_H__
+
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Where a value is also in GdkModifierType we coincide,
+ * otherwise we don't overlap.
+ */
+typedef enum
+{
+ EGG_VIRTUAL_SHIFT_MASK = 1 << 0,
+ EGG_VIRTUAL_LOCK_MASK = 1 << 1,
+ EGG_VIRTUAL_CONTROL_MASK = 1 << 2,
+
+ EGG_VIRTUAL_ALT_MASK = 1 << 3, /* fixed as Mod1 */
+
+ EGG_VIRTUAL_MOD2_MASK = 1 << 4,
+ EGG_VIRTUAL_MOD3_MASK = 1 << 5,
+ EGG_VIRTUAL_MOD4_MASK = 1 << 6,
+ EGG_VIRTUAL_MOD5_MASK = 1 << 7,
+
+#if 0
+ GDK_BUTTON1_MASK = 1 << 8,
+ GDK_BUTTON2_MASK = 1 << 9,
+ GDK_BUTTON3_MASK = 1 << 10,
+ GDK_BUTTON4_MASK = 1 << 11,
+ GDK_BUTTON5_MASK = 1 << 12,
+ /* 13, 14 are used by Xkb for the keyboard group */
+#endif
+
+ EGG_VIRTUAL_MODE_SWITCH_MASK = 1 << 23,
+ EGG_VIRTUAL_NUM_LOCK_MASK = 1 << 24,
+ EGG_VIRTUAL_SCROLL_LOCK_MASK = 1 << 25,
+
+ /* Also in GdkModifierType */
+ EGG_VIRTUAL_SUPER_MASK = 1 << 26,
+ EGG_VIRTUAL_HYPER_MASK = 1 << 27,
+ EGG_VIRTUAL_META_MASK = 1 << 28,
+
+ /* Also in GdkModifierType */
+ EGG_VIRTUAL_RELEASE_MASK = 1 << 30,
+
+ /* 28-31 24-27 20-23 16-19 12-15 8-11 4-7 0-3
+ * 5 f 8 0 0 0 f f
+ */
+ EGG_VIRTUAL_MODIFIER_MASK = 0x5f8000ff
+
+} EggVirtualModifierType;
+
+gboolean egg_accelerator_parse_virtual (const gchar *accelerator,
+ guint *accelerator_key,
+ guint *keycode,
+ EggVirtualModifierType *accelerator_mods);
+void egg_keymap_resolve_virtual_modifiers (GdkKeymap *keymap,
+ EggVirtualModifierType virtual_mods,
+ GdkModifierType *concrete_mods);
+void egg_keymap_virtualize_modifiers (GdkKeymap *keymap,
+ GdkModifierType concrete_mods,
+ EggVirtualModifierType *virtual_mods);
+
+gchar* egg_virtual_accelerator_name (guint accelerator_key,
+ guint keycode,
+ EggVirtualModifierType accelerator_mods);
+
+gchar* egg_virtual_accelerator_label (guint accelerator_key,
+ guint keycode,
+ EggVirtualModifierType accelerator_mods);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* __EGG_ACCELERATORS_H__ */
diff --git a/capplets/keybindings/eggcellrendererkeys.c b/capplets/keybindings/eggcellrendererkeys.c
new file mode 100644
index 00000000..776a5391
--- /dev/null
+++ b/capplets/keybindings/eggcellrendererkeys.c
@@ -0,0 +1,695 @@
+#include <config.h>
+#include <libintl.h>
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+#include <gdk/gdkkeysyms.h>
+#include "eggcellrendererkeys.h"
+#include "eggaccelerators.h"
+
+#ifndef EGG_COMPILATION
+#ifndef _
+#define _(x) dgettext (GETTEXT_PACKAGE, x)
+#define N_(x) x
+#endif
+#else
+#define _(x) x
+#define N_(x) x
+#endif
+
+#define EGG_CELL_RENDERER_TEXT_PATH "egg-cell-renderer-text"
+
+#define TOOLTIP_TEXT _("New shortcut...")
+
+static void egg_cell_renderer_keys_finalize (GObject *object);
+static void egg_cell_renderer_keys_init (EggCellRendererKeys *cell_keys);
+static void egg_cell_renderer_keys_class_init (EggCellRendererKeysClass *cell_keys_class);
+static GtkCellEditable *egg_cell_renderer_keys_start_editing (GtkCellRenderer *cell,
+ GdkEvent *event,
+ GtkWidget *widget,
+ const gchar *path,
+ GdkRectangle *background_area,
+ GdkRectangle *cell_area,
+ GtkCellRendererState flags);
+
+
+static void egg_cell_renderer_keys_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void egg_cell_renderer_keys_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void egg_cell_renderer_keys_get_size (GtkCellRenderer *cell,
+ GtkWidget *widget,
+ GdkRectangle *cell_area,
+ gint *x_offset,
+ gint *y_offset,
+ gint *width,
+ gint *height);
+
+
+enum {
+ PROP_0,
+
+ PROP_ACCEL_KEY,
+ PROP_ACCEL_MASK,
+ PROP_KEYCODE,
+ PROP_ACCEL_MODE
+};
+
+static GtkCellRendererTextClass *parent_class = NULL;
+
+GType
+egg_cell_renderer_keys_get_type (void)
+{
+ static GType cell_keys_type = 0;
+
+ if (!cell_keys_type)
+ {
+ static const GTypeInfo cell_keys_info =
+ {
+ sizeof (EggCellRendererKeysClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc)egg_cell_renderer_keys_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (EggCellRendererKeys),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) egg_cell_renderer_keys_init
+ };
+
+ cell_keys_type = g_type_register_static (GTK_TYPE_CELL_RENDERER_TEXT, "EggCellRendererKeys", &cell_keys_info, 0);
+ }
+
+ return cell_keys_type;
+}
+
+static void
+egg_cell_renderer_keys_init (EggCellRendererKeys *cell_keys)
+{
+ cell_keys->accel_mode = EGG_CELL_RENDERER_KEYS_MODE_GTK;
+}
+
+/* FIXME setup stuff to generate this */
+/* VOID:STRING,UINT,FLAGS,UINT */
+static void
+marshal_VOID__STRING_UINT_FLAGS_UINT (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data)
+{
+ typedef void (*GMarshalFunc_VOID__STRING_UINT_FLAGS_UINT) (gpointer data1,
+ const char *arg_1,
+ guint arg_2,
+ int arg_3,
+ guint arg_4,
+ gpointer data2);
+ register GMarshalFunc_VOID__STRING_UINT_FLAGS_UINT callback;
+ register GCClosure *cc = (GCClosure*) closure;
+ register gpointer data1, data2;
+
+ g_return_if_fail (n_param_values == 5);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ }
+ else
+ {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+
+ callback = (GMarshalFunc_VOID__STRING_UINT_FLAGS_UINT) (marshal_data ? marshal_data : cc->callback);
+
+ callback (data1,
+ g_value_get_string (param_values + 1),
+ g_value_get_uint (param_values + 2),
+ g_value_get_flags (param_values + 3),
+ g_value_get_uint (param_values + 4),
+ data2);
+}
+
+static void
+egg_cell_renderer_keys_class_init (EggCellRendererKeysClass *cell_keys_class)
+{
+ GObjectClass *object_class;
+ GtkCellRendererClass *cell_renderer_class;
+
+ object_class = G_OBJECT_CLASS (cell_keys_class);
+ cell_renderer_class = GTK_CELL_RENDERER_CLASS (cell_keys_class);
+ parent_class = g_type_class_peek_parent (object_class);
+
+ GTK_CELL_RENDERER_CLASS (cell_keys_class)->start_editing = egg_cell_renderer_keys_start_editing;
+
+ object_class->set_property = egg_cell_renderer_keys_set_property;
+ object_class->get_property = egg_cell_renderer_keys_get_property;
+ cell_renderer_class->get_size = egg_cell_renderer_keys_get_size;
+
+ object_class->finalize = egg_cell_renderer_keys_finalize;
+
+ /* FIXME if this gets moved to a real library, rename the properties
+ * to match whatever the GTK convention is
+ */
+
+ g_object_class_install_property (object_class,
+ PROP_ACCEL_KEY,
+ g_param_spec_uint ("accel_key",
+ _("Accelerator key"),
+ _("Accelerator key"),
+ 0,
+ G_MAXINT,
+ 0,
+ G_PARAM_READABLE | G_PARAM_WRITABLE));
+
+ g_object_class_install_property (object_class,
+ PROP_ACCEL_MASK,
+ g_param_spec_flags ("accel_mask",
+ _("Accelerator modifiers"),
+ _("Accelerator modifiers"),
+ GDK_TYPE_MODIFIER_TYPE,
+ 0,
+ G_PARAM_READABLE | G_PARAM_WRITABLE));
+
+ g_object_class_install_property (object_class,
+ PROP_KEYCODE,
+ g_param_spec_uint ("keycode",
+ _("Accelerator keycode"),
+ _("Accelerator keycode"),
+ 0,
+ G_MAXINT,
+ 0,
+ G_PARAM_READABLE | G_PARAM_WRITABLE));
+
+ /* FIXME: Register the enum when moving to GTK+ */
+ g_object_class_install_property (object_class,
+ PROP_ACCEL_MODE,
+ g_param_spec_int ("accel_mode",
+ _("Accel Mode"),
+ _("The type of accelerator."),
+ 0,
+ 2,
+ 0,
+ G_PARAM_READABLE | G_PARAM_WRITABLE));
+
+ g_signal_new ("accel_edited",
+ EGG_TYPE_CELL_RENDERER_KEYS,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EggCellRendererKeysClass, accel_edited),
+ NULL, NULL,
+ marshal_VOID__STRING_UINT_FLAGS_UINT,
+ G_TYPE_NONE, 4,
+ G_TYPE_STRING,
+ G_TYPE_UINT,
+ GDK_TYPE_MODIFIER_TYPE,
+ G_TYPE_UINT);
+
+ g_signal_new ("accel_cleared",
+ EGG_TYPE_CELL_RENDERER_KEYS,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EggCellRendererKeysClass, accel_cleared),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE, 1,
+ G_TYPE_STRING);
+}
+
+
+GtkCellRenderer *
+egg_cell_renderer_keys_new (void)
+{
+ return GTK_CELL_RENDERER (g_object_new (EGG_TYPE_CELL_RENDERER_KEYS, NULL));
+}
+
+static void
+egg_cell_renderer_keys_finalize (GObject *object)
+{
+
+ (* G_OBJECT_CLASS (parent_class)->finalize) (object);
+}
+
+static gchar *
+convert_keysym_state_to_string (guint keysym,
+ guint keycode,
+ EggVirtualModifierType mask)
+{
+ if (keysym == 0 && keycode == 0)
+ return g_strdup (_("Disabled"));
+ else
+ return egg_virtual_accelerator_label (keysym, keycode, mask);
+}
+
+static void
+egg_cell_renderer_keys_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EggCellRendererKeys *keys;
+
+ g_return_if_fail (EGG_IS_CELL_RENDERER_KEYS (object));
+
+ keys = EGG_CELL_RENDERER_KEYS (object);
+
+ switch (param_id)
+ {
+ case PROP_ACCEL_KEY:
+ g_value_set_uint (value, keys->accel_key);
+ break;
+
+ case PROP_ACCEL_MASK:
+ g_value_set_flags (value, keys->accel_mask);
+ break;
+
+ case PROP_ACCEL_MODE:
+ g_value_set_int (value, keys->accel_mode);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ }
+}
+
+static void
+egg_cell_renderer_keys_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EggCellRendererKeys *keys;
+
+ g_return_if_fail (EGG_IS_CELL_RENDERER_KEYS (object));
+
+ keys = EGG_CELL_RENDERER_KEYS (object);
+
+ switch (param_id)
+ {
+ case PROP_ACCEL_KEY:
+ egg_cell_renderer_keys_set_accelerator (keys,
+ g_value_get_uint (value),
+ keys->keycode,
+ keys->accel_mask);
+ break;
+
+ case PROP_ACCEL_MASK:
+ egg_cell_renderer_keys_set_accelerator (keys,
+ keys->accel_key,
+ keys->keycode,
+ g_value_get_flags (value));
+ break;
+ case PROP_KEYCODE:
+ egg_cell_renderer_keys_set_accelerator (keys,
+ keys->accel_key,
+ g_value_get_uint (value),
+ keys->accel_mask);
+ break;
+
+ case PROP_ACCEL_MODE:
+ egg_cell_renderer_keys_set_accel_mode (keys, g_value_get_int (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ }
+}
+
+static gboolean
+is_modifier (guint keycode)
+{
+ gint i;
+ gint map_size;
+ XModifierKeymap *mod_keymap;
+ gboolean retval = FALSE;
+
+ mod_keymap = XGetModifierMapping (gdk_display);
+
+ map_size = 8 * mod_keymap->max_keypermod;
+ i = 0;
+ while (i < map_size)
+ {
+ if (keycode == mod_keymap->modifiermap[i])
+ {
+ retval = TRUE;
+ break;
+ }
+ ++i;
+ }
+
+ XFreeModifiermap (mod_keymap);
+
+ return retval;
+}
+
+static void
+egg_cell_renderer_keys_get_size (GtkCellRenderer *cell,
+ GtkWidget *widget,
+ GdkRectangle *cell_area,
+ gint *x_offset,
+ gint *y_offset,
+ gint *width,
+ gint *height)
+
+{
+ EggCellRendererKeys *keys = (EggCellRendererKeys *) cell;
+ GtkRequisition requisition;
+
+ if (keys->sizing_label == NULL)
+ keys->sizing_label = gtk_label_new (TOOLTIP_TEXT);
+
+ gtk_widget_size_request (keys->sizing_label, &requisition);
+ (* GTK_CELL_RENDERER_CLASS (parent_class)->get_size) (cell, widget, cell_area, x_offset, y_offset, width, height);
+ /* FIXME: need to take the cell_area et al. into account */
+ if (width)
+ *width = MAX (*width, requisition.width);
+ if (height)
+ *height = MAX (*height, requisition.height);
+}
+
+/* FIXME: Currently we don't differentiate between a 'bogus' key (like tab in
+ * GTK mode) and a removed key.
+ */
+
+static gboolean
+grab_key_callback (GtkWidget *widget,
+ GdkEventKey *event,
+ void *data)
+{
+ GdkModifierType accel_mods = 0;
+ guint accel_keyval;
+ EggCellRendererKeys *keys;
+ char *path;
+ gboolean edited;
+ gboolean cleared;
+ GdkModifierType consumed_modifiers;
+ guint upper;
+ GdkModifierType ignored_modifiers;
+
+ keys = EGG_CELL_RENDERER_KEYS (data);
+
+ if (is_modifier (event->hardware_keycode))
+ return TRUE;
+
+ edited = FALSE;
+ cleared = FALSE;
+
+ consumed_modifiers = 0;
+ gdk_keymap_translate_keyboard_state (gdk_keymap_get_default (),
+ event->hardware_keycode,
+ event->state,
+ event->group,
+ NULL, NULL, NULL, &consumed_modifiers);
+
+ upper = event->keyval;
+ accel_keyval = gdk_keyval_to_lower (upper);
+ if (accel_keyval == GDK_ISO_Left_Tab)
+ accel_keyval = GDK_Tab;
+
+
+
+ /* Put shift back if it changed the case of the key, not otherwise.
+ */
+ if (upper != accel_keyval &&
+ (consumed_modifiers & GDK_SHIFT_MASK))
+ {
+ consumed_modifiers &= ~(GDK_SHIFT_MASK);
+ }
+
+ egg_keymap_resolve_virtual_modifiers (gdk_keymap_get_default (),
+ EGG_VIRTUAL_NUM_LOCK_MASK |
+ EGG_VIRTUAL_SCROLL_LOCK_MASK |
+ EGG_VIRTUAL_LOCK_MASK,
+ &ignored_modifiers);
+
+ /* http://bugzilla.gnome.org/show_bug.cgi?id=139605
+ * mouse keys should effect keybindings */
+ ignored_modifiers |= GDK_BUTTON1_MASK |
+ GDK_BUTTON2_MASK |
+ GDK_BUTTON3_MASK |
+ GDK_BUTTON4_MASK |
+ GDK_BUTTON5_MASK;
+
+ /* filter consumed/ignored modifiers */
+
+ if (keys->accel_mode == EGG_CELL_RENDERER_KEYS_MODE_GTK)
+ accel_mods = event->state & GDK_MODIFIER_MASK & ~(consumed_modifiers | ignored_modifiers);
+ else if (keys->accel_mode == EGG_CELL_RENDERER_KEYS_MODE_X)
+ accel_mods = event->state & GDK_MODIFIER_MASK & ~(ignored_modifiers);
+ else
+ g_assert_not_reached ();
+
+ if (accel_mods == 0 && accel_keyval == GDK_Escape)
+ goto out; /* cancel */
+
+ /* clear the accelerator on Backspace */
+ if (accel_mods == 0 && accel_keyval == GDK_BackSpace)
+ {
+ cleared = TRUE;
+ goto out;
+ }
+
+ if (keys->accel_mode == EGG_CELL_RENDERER_KEYS_MODE_GTK)
+ {
+ if (!gtk_accelerator_valid (accel_keyval, accel_mods))
+ {
+ accel_keyval = 0;
+ accel_mods = 0;
+ }
+ }
+
+ edited = TRUE;
+ out:
+ gdk_keyboard_ungrab (event->time);
+ gdk_pointer_ungrab (event->time);
+
+ path = g_strdup (g_object_get_data (G_OBJECT (keys->edit_widget), EGG_CELL_RENDERER_TEXT_PATH));
+
+ gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (keys->edit_widget));
+ gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (keys->edit_widget));
+ keys->edit_widget = NULL;
+ keys->grab_widget = NULL;
+
+ if (edited)
+ {
+ g_signal_emit_by_name (G_OBJECT (keys), "accel_edited", path,
+ accel_keyval, accel_mods, event->hardware_keycode);
+ }
+ else if (cleared)
+ {
+ g_signal_emit_by_name (G_OBJECT (keys), "accel_cleared", path);
+ }
+
+ g_free (path);
+ return TRUE;
+}
+
+static void
+ungrab_stuff (GtkWidget *widget, gpointer data)
+{
+ EggCellRendererKeys *keys = EGG_CELL_RENDERER_KEYS (data);
+
+ gdk_keyboard_ungrab (GDK_CURRENT_TIME);
+ gdk_pointer_ungrab (GDK_CURRENT_TIME);
+
+ g_signal_handlers_disconnect_by_func (G_OBJECT (keys->grab_widget),
+ G_CALLBACK (grab_key_callback), data);
+}
+
+static void
+pointless_eventbox_start_editing (GtkCellEditable *cell_editable,
+ GdkEvent *event)
+{
+ /* do nothing, because we are pointless */
+}
+
+static void
+pointless_eventbox_cell_editable_init (GtkCellEditableIface *iface)
+{
+ iface->start_editing = pointless_eventbox_start_editing;
+}
+
+static GType
+pointless_eventbox_subclass_get_type (void)
+{
+ static GType eventbox_type = 0;
+
+ if (!eventbox_type)
+ {
+ static const GTypeInfo eventbox_info =
+ {
+ sizeof (GtkEventBoxClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ NULL,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (GtkEventBox),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) NULL,
+ };
+
+ static const GInterfaceInfo cell_editable_info = {
+ (GInterfaceInitFunc) pointless_eventbox_cell_editable_init,
+ NULL, NULL };
+
+ eventbox_type = g_type_register_static (GTK_TYPE_EVENT_BOX, "EggCellEditableEventBox", &eventbox_info, 0);
+
+ g_type_add_interface_static (eventbox_type,
+ GTK_TYPE_CELL_EDITABLE,
+ &cell_editable_info);
+ }
+
+ return eventbox_type;
+}
+
+static GtkCellEditable *
+egg_cell_renderer_keys_start_editing (GtkCellRenderer *cell,
+ GdkEvent *event,
+ GtkWidget *widget,
+ const gchar *path,
+ GdkRectangle *background_area,
+ GdkRectangle *cell_area,
+ GtkCellRendererState flags)
+{
+ GtkCellRendererText *celltext;
+ EggCellRendererKeys *keys;
+ GtkWidget *label;
+ GtkWidget *eventbox;
+ GValue celltext_editable = {0};
+
+ celltext = GTK_CELL_RENDERER_TEXT (cell);
+ keys = EGG_CELL_RENDERER_KEYS (cell);
+
+ /* If the cell isn't editable we return NULL. */
+ g_value_init (&celltext_editable, G_TYPE_BOOLEAN);
+ g_object_get_property (G_OBJECT (celltext), "editable", &celltext_editable);
+ if (g_value_get_boolean (&celltext_editable) == FALSE)
+ return NULL;
+ g_return_val_if_fail (gtk_widget_get_window (widget) != NULL, NULL);
+
+ if (gdk_keyboard_grab (gtk_widget_get_window (widget), FALSE,
+ gdk_event_get_time (event)) != GDK_GRAB_SUCCESS)
+ return NULL;
+
+ if (gdk_pointer_grab (gtk_widget_get_window (widget), FALSE,
+ GDK_BUTTON_PRESS_MASK,
+ NULL, NULL,
+ gdk_event_get_time (event)) != GDK_GRAB_SUCCESS)
+ {
+ gdk_keyboard_ungrab (gdk_event_get_time (event));
+ return NULL;
+ }
+
+ keys->grab_widget = widget;
+
+ g_signal_connect (G_OBJECT (widget), "key_press_event",
+ G_CALLBACK (grab_key_callback),
+ keys);
+
+ eventbox = g_object_new (pointless_eventbox_subclass_get_type (),
+ NULL);
+ keys->edit_widget = eventbox;
+ g_object_add_weak_pointer (G_OBJECT (keys->edit_widget),
+ (void**) &keys->edit_widget);
+
+ label = gtk_label_new (NULL);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+
+ gtk_widget_modify_bg (eventbox, GTK_STATE_NORMAL,
+ &gtk_widget_get_style (widget)->bg[GTK_STATE_SELECTED]);
+
+ gtk_widget_modify_fg (label, GTK_STATE_NORMAL,
+ &gtk_widget_get_style (widget)->fg[GTK_STATE_SELECTED]);
+
+ gtk_label_set_text (GTK_LABEL (label),
+ TOOLTIP_TEXT);
+
+ gtk_container_add (GTK_CONTAINER (eventbox), label);
+
+ g_object_set_data_full (G_OBJECT (keys->edit_widget), EGG_CELL_RENDERER_TEXT_PATH,
+ g_strdup (path), g_free);
+
+ gtk_widget_show_all (keys->edit_widget);
+
+ g_signal_connect (G_OBJECT (keys->edit_widget), "unrealize",
+ G_CALLBACK (ungrab_stuff), keys);
+
+ keys->edit_key = keys->accel_key;
+
+ return GTK_CELL_EDITABLE (keys->edit_widget);
+}
+
+void
+egg_cell_renderer_keys_set_accelerator (EggCellRendererKeys *keys,
+ guint keyval,
+ guint keycode,
+ EggVirtualModifierType mask)
+{
+ char *text;
+ gboolean changed;
+
+ g_return_if_fail (EGG_IS_CELL_RENDERER_KEYS (keys));
+
+ g_object_freeze_notify (G_OBJECT (keys));
+
+ changed = FALSE;
+
+ if (keyval != keys->accel_key)
+ {
+ keys->accel_key = keyval;
+ g_object_notify (G_OBJECT (keys), "accel_key");
+ changed = TRUE;
+ }
+
+ if (mask != keys->accel_mask)
+ {
+ keys->accel_mask = mask;
+
+ g_object_notify (G_OBJECT (keys), "accel_mask");
+ changed = TRUE;
+ }
+
+ if (keycode != keys->keycode)
+ {
+ keys->keycode = keycode;
+
+ g_object_notify (G_OBJECT (keys), "keycode");
+ changed = TRUE;
+ }
+ g_object_thaw_notify (G_OBJECT (keys));
+
+ if (changed)
+ {
+ /* sync string to the key values */
+ text = convert_keysym_state_to_string (keys->accel_key, keys->keycode, keys->accel_mask);
+ g_object_set (keys, "text", text, NULL);
+ g_free (text);
+ }
+}
+
+void
+egg_cell_renderer_keys_get_accelerator (EggCellRendererKeys *keys,
+ guint *keyval,
+ EggVirtualModifierType *mask)
+{
+ g_return_if_fail (EGG_IS_CELL_RENDERER_KEYS (keys));
+
+ if (keyval)
+ *keyval = keys->accel_key;
+
+ if (mask)
+ *mask = keys->accel_mask;
+}
+
+void
+egg_cell_renderer_keys_set_accel_mode (EggCellRendererKeys *keys,
+ EggCellRendererKeysMode accel_mode)
+{
+ g_return_if_fail (EGG_IS_CELL_RENDERER_KEYS (keys));
+ keys->accel_mode = accel_mode;
+ g_object_notify (G_OBJECT (keys), "accel_mode");
+}
diff --git a/capplets/keybindings/eggcellrendererkeys.h b/capplets/keybindings/eggcellrendererkeys.h
new file mode 100644
index 00000000..2fe515e1
--- /dev/null
+++ b/capplets/keybindings/eggcellrendererkeys.h
@@ -0,0 +1,93 @@
+/* gtkcellrendererkeybinding.h
+ * Copyright (C) 2000 Red Hat, Inc., Jonathan Blandford <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __EGG_CELL_RENDERER_KEYS_H__
+#define __EGG_CELL_RENDERER_KEYS_H__
+
+#include <gtk/gtk.h>
+#include "eggaccelerators.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define EGG_TYPE_CELL_RENDERER_KEYS (egg_cell_renderer_keys_get_type ())
+#define EGG_CELL_RENDERER_KEYS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_CELL_RENDERER_KEYS, EggCellRendererKeys))
+#define EGG_CELL_RENDERER_KEYS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_CELL_RENDERER_KEYS, EggCellRendererKeysClass))
+#define EGG_IS_CELL_RENDERER_KEYS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_CELL_RENDERER_KEYS))
+#define EGG_IS_CELL_RENDERER_KEYS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_CELL_RENDERER_KEYS))
+#define EGG_CELL_RENDERER_KEYS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_CELL_RENDERER_KEYS, EggCellRendererKeysClass))
+
+typedef struct _EggCellRendererKeys EggCellRendererKeys;
+typedef struct _EggCellRendererKeysClass EggCellRendererKeysClass;
+
+
+typedef enum
+{
+ EGG_CELL_RENDERER_KEYS_MODE_GTK,
+ EGG_CELL_RENDERER_KEYS_MODE_X
+} EggCellRendererKeysMode;
+
+struct _EggCellRendererKeys
+{
+ GtkCellRendererText parent;
+ guint accel_key;
+ guint keycode;
+ EggVirtualModifierType accel_mask;
+ GtkWidget *edit_widget;
+ GtkWidget *grab_widget;
+ guint edit_key;
+ GtkWidget *sizing_label;
+ EggCellRendererKeysMode accel_mode;
+};
+
+struct _EggCellRendererKeysClass
+{
+ GtkCellRendererTextClass parent_class;
+
+ void (* accel_edited) (EggCellRendererKeys *keys,
+ const char *path_string,
+ guint keyval,
+ EggVirtualModifierType mask,
+ guint hardware_keycode);
+
+ void (* accel_cleared) (EggCellRendererKeys *keys,
+ const char *path_string);
+};
+
+GType egg_cell_renderer_keys_get_type (void);
+GtkCellRenderer *egg_cell_renderer_keys_new (void);
+
+void egg_cell_renderer_keys_set_accelerator (EggCellRendererKeys *keys,
+ guint keyval,
+ guint keycode,
+ EggVirtualModifierType mask);
+void egg_cell_renderer_keys_get_accelerator (EggCellRendererKeys *keys,
+ guint *keyval,
+ EggVirtualModifierType *mask);
+void egg_cell_renderer_keys_set_accel_mode (EggCellRendererKeys *keys,
+ EggCellRendererKeysMode accel_mode);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* __GTK_CELL_RENDERER_KEYS_H__ */
diff --git a/capplets/keybindings/mate-keybinding-properties.c b/capplets/keybindings/mate-keybinding-properties.c
new file mode 100644
index 00000000..fb6c8785
--- /dev/null
+++ b/capplets/keybindings/mate-keybinding-properties.c
@@ -0,0 +1,1948 @@
+/* This program was written with lots of love under the GPL by Jonathan
+ * Blandford <[email protected]>
+ */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <gtk/gtk.h>
+#include <mateconf/mateconf-client.h>
+#include <gdk/gdkx.h>
+#include <X11/Xatom.h>
+#include <glib/gi18n.h>
+#include <gdk/gdkkeysyms.h>
+
+#include "wm-common.h"
+#include "capplet-util.h"
+#include "eggcellrendererkeys.h"
+#include "activate-settings-daemon.h"
+
+#define MATECONF_BINDING_DIR "/desktop/mate/keybindings"
+#define MAX_ELEMENTS_BEFORE_SCROLLING 10
+#define MAX_CUSTOM_SHORTCUTS 1000
+#define RESPONSE_ADD 0
+#define RESPONSE_REMOVE 1
+
+typedef struct {
+ char *name;
+ /* The gettext package to use to translate the section title */
+ char *package;
+ /* Name of the window manager the keys would apply to */
+ char *wm_name;
+ /* an array of KeyListEntry */
+ GArray *entries;
+} KeyList;
+
+typedef enum {
+ COMPARISON_NONE = 0,
+ COMPARISON_GT,
+ COMPARISON_LT,
+ COMPARISON_EQ
+} Comparison;
+
+typedef struct
+{
+ char *name;
+ int value;
+ char *key;
+ char *description_name;
+ char *cmd_name;
+ Comparison comparison;
+} KeyListEntry;
+
+enum
+{
+ DESCRIPTION_COLUMN,
+ KEYENTRY_COLUMN,
+ N_COLUMNS
+};
+
+typedef struct
+{
+ char *mateconf_key;
+ guint keyval;
+ guint keycode;
+ EggVirtualModifierType mask;
+ gboolean editable;
+ GtkTreeModel *model;
+ char *description;
+ char *desc_mateconf_key;
+ gboolean desc_editable;
+ char *command;
+ char *cmd_mateconf_key;
+ gboolean cmd_editable;
+ guint mateconf_cnxn;
+ guint mateconf_cnxn_desc;
+ guint mateconf_cnxn_cmd;
+} KeyEntry;
+
+static gboolean block_accels = FALSE;
+static GtkWidget *custom_shortcut_dialog = NULL;
+static GtkWidget *custom_shortcut_name_entry = NULL;
+static GtkWidget *custom_shortcut_command_entry = NULL;
+
+static GtkWidget*
+_gtk_builder_get_widget (GtkBuilder *builder, const gchar *name)
+{
+ return GTK_WIDGET (gtk_builder_get_object (builder, name));
+}
+
+static GtkBuilder *
+create_builder (void)
+{
+ GtkBuilder *builder = gtk_builder_new();
+ GError *error = NULL;
+ static const gchar *uifile = MATECC_UI_DIR "/mate-keybinding-properties.ui";
+
+ if (gtk_builder_add_from_file (builder, uifile, &error) == 0) {
+ g_warning ("Could not load UI: %s", error->message);
+ g_error_free (error);
+ g_object_unref (builder);
+ builder = NULL;
+ }
+
+ return builder;
+}
+
+static char*
+binding_name (guint keyval,
+ guint keycode,
+ EggVirtualModifierType mask,
+ gboolean translate)
+{
+ if (keyval != 0 || keycode != 0)
+ return translate ?
+ egg_virtual_accelerator_label (keyval, keycode, mask) :
+ egg_virtual_accelerator_name (keyval, keycode, mask);
+ else
+ return g_strdup (translate ? _("Disabled") : "");
+}
+
+static gboolean
+binding_from_string (const char *str,
+ guint *accelerator_key,
+ guint *keycode,
+ EggVirtualModifierType *accelerator_mods)
+{
+ g_return_val_if_fail (accelerator_key != NULL, FALSE);
+
+ if (str == NULL || strcmp (str, "disabled") == 0)
+ {
+ *accelerator_key = 0;
+ *keycode = 0;
+ *accelerator_mods = 0;
+ return TRUE;
+ }
+
+ egg_accelerator_parse_virtual (str, accelerator_key, keycode, accelerator_mods);
+
+ if (*accelerator_key == 0)
+ return FALSE;
+ else
+ return TRUE;
+}
+
+static void
+accel_set_func (GtkTreeViewColumn *tree_column,
+ GtkCellRenderer *cell,
+ GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ KeyEntry *key_entry;
+
+ gtk_tree_model_get (model, iter,
+ KEYENTRY_COLUMN, &key_entry,
+ -1);
+
+ if (key_entry == NULL)
+ g_object_set (cell,
+ "visible", FALSE,
+ NULL);
+ else if (! key_entry->editable)
+ g_object_set (cell,
+ "visible", TRUE,
+ "editable", FALSE,
+ "accel_key", key_entry->keyval,
+ "accel_mask", key_entry->mask,
+ "keycode", key_entry->keycode,
+ "style", PANGO_STYLE_ITALIC,
+ NULL);
+ else
+ g_object_set (cell,
+ "visible", TRUE,
+ "editable", TRUE,
+ "accel_key", key_entry->keyval,
+ "accel_mask", key_entry->mask,
+ "keycode", key_entry->keycode,
+ "style", PANGO_STYLE_NORMAL,
+ NULL);
+}
+
+static void
+description_set_func (GtkTreeViewColumn *tree_column,
+ GtkCellRenderer *cell,
+ GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ KeyEntry *key_entry;
+
+ gtk_tree_model_get (model, iter,
+ KEYENTRY_COLUMN, &key_entry,
+ -1);
+
+ if (key_entry != NULL)
+ g_object_set (cell,
+ "editable", FALSE,
+ "text", key_entry->description != NULL ?
+ key_entry->description : _("<Unknown Action>"),
+ NULL);
+ else
+ g_object_set (cell,
+ "editable", FALSE, NULL);
+}
+
+static gboolean
+keybinding_key_changed_foreach (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer user_data)
+{
+ KeyEntry *key_entry;
+ KeyEntry *tmp_key_entry;
+
+ key_entry = (KeyEntry *)user_data;
+ gtk_tree_model_get (key_entry->model, iter,
+ KEYENTRY_COLUMN, &tmp_key_entry,
+ -1);
+
+ if (key_entry == tmp_key_entry)
+ {
+ gtk_tree_model_row_changed (key_entry->model, path, iter);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static void
+keybinding_key_changed (MateConfClient *client,
+ guint cnxn_id,
+ MateConfEntry *entry,
+ gpointer user_data)
+{
+ KeyEntry *key_entry;
+ const gchar *key_value;
+
+ key_entry = (KeyEntry *) user_data;
+ key_value = entry->value ? mateconf_value_get_string (entry->value) : NULL;
+
+ binding_from_string (key_value, &key_entry->keyval, &key_entry->keycode, &key_entry->mask);
+ key_entry->editable = mateconf_entry_get_is_writable (entry);
+
+ /* update the model */
+ gtk_tree_model_foreach (key_entry->model, keybinding_key_changed_foreach, key_entry);
+}
+
+static void
+keybinding_description_changed (MateConfClient *client,
+ guint cnxn_id,
+ MateConfEntry *entry,
+ gpointer user_data)
+{
+ KeyEntry *key_entry;
+ const gchar *key_value;
+
+ key_entry = (KeyEntry *) user_data;
+ key_value = entry->value ? mateconf_value_get_string (entry->value) : NULL;
+
+ g_free (key_entry->description);
+ key_entry->description = key_value ? g_strdup (key_value) : NULL;
+ key_entry->desc_editable = mateconf_entry_get_is_writable (entry);
+
+ /* update the model */
+ gtk_tree_model_foreach (key_entry->model, keybinding_key_changed_foreach, key_entry);
+}
+
+static void
+keybinding_command_changed (MateConfClient *client,
+ guint cnxn_id,
+ MateConfEntry *entry,
+ gpointer user_data)
+{
+ KeyEntry *key_entry;
+ const gchar *key_value;
+
+ key_entry = (KeyEntry *) user_data;
+ key_value = entry->value ? mateconf_value_get_string (entry->value) : NULL;
+
+ g_free (key_entry->command);
+ key_entry->command = key_value ? g_strdup (key_value) : NULL;
+ key_entry->cmd_editable = mateconf_entry_get_is_writable (entry);
+
+ /* update the model */
+ gtk_tree_model_foreach (key_entry->model, keybinding_key_changed_foreach, key_entry);
+}
+
+static int
+keyentry_sort_func (GtkTreeModel *model,
+ GtkTreeIter *a,
+ GtkTreeIter *b,
+ gpointer user_data)
+{
+ KeyEntry *key_entry_a;
+ KeyEntry *key_entry_b;
+ int retval;
+
+ key_entry_a = NULL;
+ gtk_tree_model_get (model, a,
+ KEYENTRY_COLUMN, &key_entry_a,
+ -1);
+
+ key_entry_b = NULL;
+ gtk_tree_model_get (model, b,
+ KEYENTRY_COLUMN, &key_entry_b,
+ -1);
+
+ if (key_entry_a && key_entry_b)
+ {
+ if ((key_entry_a->keyval || key_entry_a->keycode) &&
+ (key_entry_b->keyval || key_entry_b->keycode))
+ {
+ gchar *name_a, *name_b;
+
+ name_a = binding_name (key_entry_a->keyval,
+ key_entry_a->keycode,
+ key_entry_a->mask,
+ TRUE);
+
+ name_b = binding_name (key_entry_b->keyval,
+ key_entry_b->keycode,
+ key_entry_b->mask,
+ TRUE);
+
+ retval = g_utf8_collate (name_a, name_b);
+
+ g_free (name_a);
+ g_free (name_b);
+ }
+ else if (key_entry_a->keyval || key_entry_a->keycode)
+ retval = -1;
+ else if (key_entry_b->keyval || key_entry_b->keycode)
+ retval = 1;
+ else
+ retval = 0;
+ }
+ else if (key_entry_a)
+ retval = -1;
+ else if (key_entry_b)
+ retval = 1;
+ else
+ retval = 0;
+
+ return retval;
+}
+
+static void
+clear_old_model (GtkBuilder *builder)
+{
+ GtkWidget *tree_view;
+ GtkWidget *actions_swindow;
+ GtkTreeModel *model;
+
+ tree_view = _gtk_builder_get_widget (builder, "shortcut_treeview");
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view));
+
+ if (model == NULL)
+ {
+ /* create a new model */
+ model = (GtkTreeModel *) gtk_tree_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_POINTER);
+
+ gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (model),
+ KEYENTRY_COLUMN,
+ keyentry_sort_func,
+ NULL, NULL);
+
+ gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), model);
+
+ g_object_unref (model);
+ }
+ else
+ {
+ /* clear the existing model */
+ MateConfClient *client;
+ gboolean valid;
+ GtkTreeIter iter;
+ KeyEntry *key_entry;
+
+ client = mateconf_client_get_default ();
+ /* we need the schema name below;
+ * cached values do not have that set, though */
+ mateconf_client_clear_cache (client);
+
+ for (valid = gtk_tree_model_get_iter_first (model, &iter);
+ valid;
+ valid = gtk_tree_model_iter_next (model, &iter))
+ {
+ gtk_tree_model_get (model, &iter,
+ KEYENTRY_COLUMN, &key_entry,
+ -1);
+
+ if (key_entry != NULL)
+ {
+ mateconf_client_remove_dir (client, key_entry->mateconf_key, NULL);
+ mateconf_client_notify_remove (client, key_entry->mateconf_cnxn);
+ if (key_entry->mateconf_cnxn_desc != 0)
+ mateconf_client_notify_remove (client, key_entry->mateconf_cnxn_desc);
+ if (key_entry->mateconf_cnxn_cmd != 0)
+ mateconf_client_notify_remove (client, key_entry->mateconf_cnxn_cmd);
+ g_free (key_entry->mateconf_key);
+ g_free (key_entry->description);
+ g_free (key_entry->desc_mateconf_key);
+ g_free (key_entry->command);
+ g_free (key_entry->cmd_mateconf_key);
+ g_free (key_entry);
+ }
+ }
+
+ gtk_tree_store_clear (GTK_TREE_STORE (model));
+ g_object_unref (client);
+ }
+
+ actions_swindow = _gtk_builder_get_widget (builder, "actions_swindow");
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (actions_swindow),
+ GTK_POLICY_NEVER, GTK_POLICY_NEVER);
+ gtk_widget_set_size_request (actions_swindow, -1, -1);
+}
+
+typedef struct {
+ const char *key;
+ gboolean found;
+} KeyMatchData;
+
+static gboolean
+key_match (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
+{
+ KeyMatchData *match_data = data;
+ KeyEntry *element;
+
+ gtk_tree_model_get (model, iter,
+ KEYENTRY_COLUMN, &element,
+ -1);
+
+ if (element && g_strcmp0 (element->mateconf_key, match_data->key) == 0)
+ {
+ match_data->found = TRUE;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+key_is_already_shown (GtkTreeModel *model, const KeyListEntry *entry)
+{
+ KeyMatchData data;
+
+ data.key = entry->name;
+ data.found = FALSE;
+ gtk_tree_model_foreach (model, key_match, &data);
+
+ return data.found;
+}
+
+static gboolean
+should_show_key (const KeyListEntry *entry)
+{
+ int value;
+ MateConfClient *client;
+
+ if (entry->comparison == COMPARISON_NONE)
+ return TRUE;
+
+ g_return_val_if_fail (entry->key != NULL, FALSE);
+
+ client = mateconf_client_get_default();
+ value = mateconf_client_get_int (client, entry->key, NULL);
+ g_object_unref (client);
+
+ switch (entry->comparison) {
+ case COMPARISON_NONE:
+ /* For compiler warnings */
+ g_assert_not_reached ();
+ return FALSE;
+ case COMPARISON_GT:
+ if (value > entry->value)
+ return TRUE;
+ break;
+ case COMPARISON_LT:
+ if (value < entry->value)
+ return TRUE;
+ break;
+ case COMPARISON_EQ:
+ if (value == entry->value)
+ return TRUE;
+ break;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+count_rows_foreach (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
+{
+ gint *rows = data;
+
+ (*rows)++;
+
+ return FALSE;
+}
+
+static void
+ensure_scrollbar (GtkBuilder *builder, int i)
+{
+ if (i == MAX_ELEMENTS_BEFORE_SCROLLING)
+ {
+ GtkRequisition rectangle;
+ GObject *actions_swindow = gtk_builder_get_object (builder,
+ "actions_swindow");
+ GtkWidget *treeview = _gtk_builder_get_widget (builder,
+ "shortcut_treeview");
+ gtk_widget_ensure_style (treeview);
+ gtk_widget_size_request (treeview, &rectangle);
+ gtk_widget_set_size_request (treeview, -1, rectangle.height);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (actions_swindow),
+ GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+ }
+}
+
+static void
+find_section (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ const char *title)
+{
+ gboolean success;
+
+ success = gtk_tree_model_get_iter_first (model, iter);
+ while (success)
+ {
+ char *description = NULL;
+
+ gtk_tree_model_get (model, iter,
+ DESCRIPTION_COLUMN, &description,
+ -1);
+
+ if (g_strcmp0 (description, title) == 0)
+ return;
+ success = gtk_tree_model_iter_next (model, iter);
+ }
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), iter, NULL);
+ gtk_tree_store_set (GTK_TREE_STORE (model), iter,
+ DESCRIPTION_COLUMN, title,
+ -1);
+}
+
+static void
+append_keys_to_tree (GtkBuilder *builder,
+ const gchar *title,
+ const KeyListEntry *keys_list)
+{
+ MateConfClient *client;
+ GtkTreeIter parent_iter, iter;
+ GtkTreeModel *model;
+ gint i, j;
+
+ client = mateconf_client_get_default ();
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (gtk_builder_get_object (builder, "shortcut_treeview")));
+
+ /* Try to find a section parent iter, if it already exists */
+ find_section (model, &iter, title);
+ parent_iter = iter;
+
+ i = 0;
+ gtk_tree_model_foreach (model, count_rows_foreach, &i);
+
+ /* If the header we just added is the MAX_ELEMENTS_BEFORE_SCROLLING th,
+ * then we need to scroll now */
+ ensure_scrollbar (builder, i - 1);
+
+ for (j = 0; keys_list[j].name != NULL; j++)
+ {
+ MateConfEntry *entry;
+ KeyEntry *key_entry;
+ const gchar *key_string;
+ gchar *key_value;
+ gchar *description;
+ gchar *command;
+
+ if (!should_show_key (&keys_list[j]))
+ continue;
+
+ if (key_is_already_shown (model, &keys_list[j]))
+ continue;
+
+ key_string = keys_list[j].name;
+
+ entry = mateconf_client_get_entry (client,
+ key_string,
+ NULL,
+ TRUE,
+ NULL);
+ if (entry == NULL)
+ {
+ /* We don't actually want to popup a dialog - just skip this one */
+ continue;
+ }
+
+ if (keys_list[j].description_name != NULL)
+ {
+ description = mateconf_client_get_string (client, keys_list[j].description_name, NULL);
+ }
+ else
+ {
+ description = NULL;
+
+ if (mateconf_entry_get_schema_name (entry))
+ {
+ MateConfSchema *schema;
+
+ schema = mateconf_client_get_schema (client,
+ mateconf_entry_get_schema_name (entry),
+ NULL);
+ if (schema != NULL)
+ {
+ description = g_strdup (mateconf_schema_get_short_desc (schema));
+ mateconf_schema_free (schema);
+ }
+ }
+ }
+
+ if (description == NULL)
+ {
+ /* Only print a warning for keys that should have a schema */
+ if (keys_list[j].description_name == NULL)
+ g_warning ("No description for key '%s'", key_string);
+ }
+
+ if (keys_list[j].cmd_name != NULL)
+ {
+ command = mateconf_client_get_string (client, keys_list[j].cmd_name, NULL);
+ }
+ else
+ {
+ command = NULL;
+ }
+
+ key_entry = g_new0 (KeyEntry, 1);
+ key_entry->mateconf_key = g_strdup (key_string);
+ key_entry->editable = mateconf_entry_get_is_writable (entry);
+ key_entry->model = model;
+ key_entry->description = description;
+ key_entry->command = command;
+ if (keys_list[j].description_name != NULL)
+ {
+ key_entry->desc_mateconf_key = g_strdup (keys_list[j].description_name);
+ key_entry->desc_editable = mateconf_client_key_is_writable (client, key_entry->desc_mateconf_key, NULL);
+ key_entry->mateconf_cnxn_desc = mateconf_client_notify_add (client,
+ key_entry->desc_mateconf_key,
+ (MateConfClientNotifyFunc) &keybinding_description_changed,
+ key_entry, NULL, NULL);
+ }
+ if (keys_list[j].cmd_name != NULL)
+ {
+ key_entry->cmd_mateconf_key = g_strdup (keys_list[j].cmd_name);
+ key_entry->cmd_editable = mateconf_client_key_is_writable (client, key_entry->cmd_mateconf_key, NULL);
+ key_entry->mateconf_cnxn_cmd = mateconf_client_notify_add (client,
+ key_entry->cmd_mateconf_key,
+ (MateConfClientNotifyFunc) &keybinding_command_changed,
+ key_entry, NULL, NULL);
+ }
+
+ mateconf_client_add_dir (client, key_string, MATECONF_CLIENT_PRELOAD_ONELEVEL, NULL);
+ key_entry->mateconf_cnxn = mateconf_client_notify_add (client,
+ key_string,
+ (MateConfClientNotifyFunc) &keybinding_key_changed,
+ key_entry, NULL, NULL);
+
+ key_value = mateconf_client_get_string (client, key_string, NULL);
+ binding_from_string (key_value, &key_entry->keyval, &key_entry->keycode, &key_entry->mask);
+ g_free (key_value);
+
+ mateconf_entry_free (entry);
+ ensure_scrollbar (builder, i);
+
+ ++i;
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, &parent_iter);
+ /* we use the DESCRIPTION_COLUMN only for the section headers */
+ gtk_tree_store_set (GTK_TREE_STORE (model), &iter,
+ KEYENTRY_COLUMN, key_entry,
+ -1);
+ gtk_tree_view_expand_all (GTK_TREE_VIEW (gtk_builder_get_object (builder, "shortcut_treeview")));
+ }
+
+ g_object_unref (client);
+
+ /* Don't show an empty section */
+ if (gtk_tree_model_iter_n_children (model, &parent_iter) == 0)
+ gtk_tree_store_remove (GTK_TREE_STORE (model), &parent_iter);
+
+ if (i == 0)
+ gtk_widget_hide (_gtk_builder_get_widget (builder, "shortcuts_vbox"));
+ else
+ gtk_widget_show (_gtk_builder_get_widget (builder, "shortcuts_vbox"));
+}
+
+static void
+parse_start_tag (GMarkupParseContext *ctx,
+ const gchar *element_name,
+ const gchar **attr_names,
+ const gchar **attr_values,
+ gpointer user_data,
+ GError **error)
+{
+ KeyList *keylist = (KeyList *) user_data;
+ KeyListEntry key;
+ const char *name, *mateconf_key;
+ int value;
+ Comparison comparison;
+
+ name = NULL;
+
+ /* The top-level element, names the section in the tree */
+ if (g_str_equal (element_name, "KeyListEntries"))
+ {
+ const char *wm_name = NULL;
+ const char *package = NULL;
+
+ while (*attr_names && *attr_values)
+ {
+ if (g_str_equal (*attr_names, "name"))
+ {
+ if (**attr_values)
+ name = *attr_values;
+ } else if (g_str_equal (*attr_names, "wm_name")) {
+ if (**attr_values)
+ wm_name = *attr_values;
+ } else if (g_str_equal (*attr_names, "package")) {
+ if (**attr_values)
+ package = *attr_values;
+ }
+ ++attr_names;
+ ++attr_values;
+ }
+
+ if (name)
+ {
+ if (keylist->name)
+ g_warning ("Duplicate section name");
+ g_free (keylist->name);
+ keylist->name = g_strdup (name);
+ }
+ if (wm_name)
+ {
+ if (keylist->wm_name)
+ g_warning ("Duplicate window manager name");
+ g_free (keylist->wm_name);
+ keylist->wm_name = g_strdup (wm_name);
+ }
+ if (package)
+ {
+ if (keylist->package)
+ g_warning ("Duplicate gettext package name");
+ g_free (keylist->package);
+ keylist->package = g_strdup (package);
+ }
+ return;
+ }
+
+ if (!g_str_equal (element_name, "KeyListEntry")
+ || attr_names == NULL
+ || attr_values == NULL)
+ return;
+
+ value = 0;
+ comparison = COMPARISON_NONE;
+ mateconf_key = NULL;
+
+ while (*attr_names && *attr_values)
+ {
+ if (g_str_equal (*attr_names, "name"))
+ {
+ /* skip if empty */
+ if (**attr_values)
+ name = *attr_values;
+ } else if (g_str_equal (*attr_names, "value")) {
+ if (**attr_values) {
+ value = (int) g_ascii_strtoull (*attr_values, NULL, 0);
+ }
+ } else if (g_str_equal (*attr_names, "key")) {
+ if (**attr_values) {
+ mateconf_key = *attr_values;
+ }
+ } else if (g_str_equal (*attr_names, "comparison")) {
+ if (**attr_values) {
+ if (g_str_equal (*attr_values, "gt")) {
+ comparison = COMPARISON_GT;
+ } else if (g_str_equal (*attr_values, "lt")) {
+ comparison = COMPARISON_LT;
+ } else if (g_str_equal (*attr_values, "eq")) {
+ comparison = COMPARISON_EQ;
+ }
+ }
+ }
+
+ ++attr_names;
+ ++attr_values;
+ }
+
+ if (name == NULL)
+ return;
+
+ key.name = g_strdup (name);
+ key.description_name = NULL;
+ key.value = value;
+ if (mateconf_key)
+ key.key = g_strdup (mateconf_key);
+ else
+ key.key = NULL;
+ key.comparison = comparison;
+ key.cmd_name = NULL;
+ g_array_append_val (keylist->entries, key);
+}
+
+static gboolean
+strv_contains (char **strv,
+ char *str)
+{
+ char **p = strv;
+ for (p = strv; *p; p++)
+ if (strcmp (*p, str) == 0)
+ return TRUE;
+
+ return FALSE;
+}
+
+static void
+append_keys_to_tree_from_file (GtkBuilder *builder,
+ const char *filename,
+ char **wm_keybindings)
+{
+ GMarkupParseContext *ctx;
+ GMarkupParser parser = { parse_start_tag, NULL, NULL, NULL, NULL };
+ KeyList *keylist;
+ KeyListEntry key, *keys;
+ GError *err = NULL;
+ char *buf;
+ const char *title;
+ gsize buf_len;
+ guint i;
+
+ if (!g_file_get_contents (filename, &buf, &buf_len, &err))
+ return;
+
+ keylist = g_new0 (KeyList, 1);
+ keylist->entries = g_array_new (FALSE, TRUE, sizeof (KeyListEntry));
+ ctx = g_markup_parse_context_new (&parser, 0, keylist, NULL);
+
+ if (!g_markup_parse_context_parse (ctx, buf, buf_len, &err))
+ {
+ g_warning ("Failed to parse '%s': '%s'", filename, err->message);
+ g_error_free (err);
+ g_free (keylist->name);
+ g_free (keylist->package);
+ g_free (keylist->wm_name);
+ for (i = 0; i < keylist->entries->len; i++)
+ g_free (((KeyListEntry *) &(keylist->entries->data[i]))->name);
+ g_array_free (keylist->entries, TRUE);
+ g_free (keylist);
+ keylist = NULL;
+ }
+ g_markup_parse_context_free (ctx);
+ g_free (buf);
+
+ if (keylist == NULL)
+ return;
+
+ /* If there's no keys to add, or the settings apply to a window manager
+ * that's not the one we're running */
+ if (keylist->entries->len == 0
+ || (keylist->wm_name != NULL && !strv_contains (wm_keybindings, keylist->wm_name))
+ || keylist->name == NULL)
+ {
+ g_free (keylist->name);
+ g_free (keylist->package);
+ g_free (keylist->wm_name);
+ g_array_free (keylist->entries, TRUE);
+ g_free (keylist);
+ return;
+ }
+
+ /* Empty KeyListEntry to end the array */
+ key.name = NULL;
+ key.description_name = NULL;
+ key.key = NULL;
+ key.value = 0;
+ key.comparison = COMPARISON_NONE;
+ g_array_append_val (keylist->entries, key);
+
+ keys = (KeyListEntry *) g_array_free (keylist->entries, FALSE);
+ if (keylist->package)
+ {
+ bind_textdomain_codeset (keylist->package, "UTF-8");
+ title = dgettext (keylist->package, keylist->name);
+ } else {
+ title = _(keylist->name);
+ }
+
+ append_keys_to_tree (builder, title, keys);
+
+ g_free (keylist->name);
+ g_free (keylist->package);
+ for (i = 0; keys[i].name != NULL; i++)
+ g_free (keys[i].name);
+ g_free (keylist);
+}
+
+static void
+append_keys_to_tree_from_mateconf (GtkBuilder *builder, const gchar *mateconf_path)
+{
+ MateConfClient *client;
+ GSList *custom_list, *l;
+ GArray *entries;
+ KeyListEntry key;
+
+ /* load custom shortcuts from MateConf */
+ entries = g_array_new (FALSE, TRUE, sizeof (KeyListEntry));
+
+ key.key = NULL;
+ key.value = 0;
+ key.comparison = COMPARISON_NONE;
+
+ client = mateconf_client_get_default ();
+ custom_list = mateconf_client_all_dirs (client, mateconf_path, NULL);
+
+ for (l = custom_list; l != NULL; l = l->next)
+ {
+ key.name = g_strconcat (l->data, "/binding", NULL);
+ key.cmd_name = g_strconcat (l->data, "/action", NULL);
+ key.description_name = g_strconcat (l->data, "/name", NULL);
+ g_array_append_val (entries, key);
+
+ g_free (l->data);
+ }
+
+ g_slist_free (custom_list);
+ g_object_unref (client);
+
+ if (entries->len > 0)
+ {
+ KeyListEntry *keys;
+ int i;
+
+ /* Empty KeyListEntry to end the array */
+ key.name = NULL;
+ key.description_name = NULL;
+ g_array_append_val (entries, key);
+
+ keys = (KeyListEntry *) entries->data;
+ append_keys_to_tree (builder, _("Custom Shortcuts"), keys);
+ for (i = 0; i < entries->len; ++i)
+ {
+ g_free (keys[i].name);
+ g_free (keys[i].description_name);
+ }
+ }
+
+ g_array_free (entries, TRUE);
+}
+
+static void
+reload_key_entries (GtkBuilder *builder)
+{
+ gchar **wm_keybindings;
+ GDir *dir;
+ const char *name;
+ GList *list, *l;
+
+ wm_keybindings = wm_common_get_current_keybindings();
+
+ clear_old_model (builder);
+
+ dir = g_dir_open (MATECC_KEYBINDINGS_DIR, 0, NULL);
+ if (!dir)
+ return;
+
+ list = NULL;
+ for (name = g_dir_read_name (dir) ; name ; name = g_dir_read_name (dir))
+ {
+ if (g_str_has_suffix (name, ".xml"))
+ {
+ list = g_list_insert_sorted (list, g_strdup (name),
+ (GCompareFunc) g_ascii_strcasecmp);
+ }
+ }
+ g_dir_close (dir);
+
+ for (l = list; l != NULL; l = l->next)
+ {
+ gchar *path;
+
+ path = g_build_filename (MATECC_KEYBINDINGS_DIR, l->data, NULL);
+ append_keys_to_tree_from_file (builder, path, wm_keybindings);
+ g_free (l->data);
+ g_free (path);
+ }
+ g_list_free (list);
+
+ /* Load custom shortcuts _after_ system-provided ones,
+ * since some of the custom shortcuts may also be listed
+ * in a file. Loading the custom shortcuts last makes
+ * such keys not show up in the custom section.
+ */
+ append_keys_to_tree_from_mateconf (builder, MATECONF_BINDING_DIR);
+
+ g_strfreev (wm_keybindings);
+}
+
+static void
+key_entry_controlling_key_changed (MateConfClient *client,
+ guint cnxn_id,
+ MateConfEntry *entry,
+ gpointer user_data)
+{
+ reload_key_entries (user_data);
+}
+
+static gboolean
+cb_check_for_uniqueness (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ KeyEntry *new_key)
+{
+ KeyEntry *element;
+
+ gtk_tree_model_get (new_key->model, iter,
+ KEYENTRY_COLUMN, &element,
+ -1);
+
+ /* no conflict for : blanks, different modifiers, or ourselves */
+ if (element == NULL || new_key->mask != element->mask ||
+ !strcmp (new_key->mateconf_key, element->mateconf_key))
+ return FALSE;
+
+ if (new_key->keyval != 0) {
+ if (new_key->keyval != element->keyval)
+ return FALSE;
+ } else if (element->keyval != 0 || new_key->keycode != element->keycode)
+ return FALSE;
+
+ new_key->editable = FALSE;
+ new_key->mateconf_key = element->mateconf_key;
+ new_key->description = element->description;
+ new_key->desc_mateconf_key = element->desc_mateconf_key;
+ new_key->desc_editable = element->desc_editable;
+ return TRUE;
+}
+
+static const guint forbidden_keyvals[] = {
+ /* Navigation keys */
+ GDK_Home,
+ GDK_Left,
+ GDK_Up,
+ GDK_Right,
+ GDK_Down,
+ GDK_Page_Up,
+ GDK_Page_Down,
+ GDK_End,
+ GDK_Tab,
+
+ /* Return */
+ GDK_KP_Enter,
+ GDK_Return,
+
+ GDK_space,
+ GDK_Mode_switch
+};
+
+static gboolean
+keyval_is_forbidden (guint keyval)
+{
+ guint i;
+
+ for (i = 0; i < G_N_ELEMENTS(forbidden_keyvals); i++) {
+ if (keyval == forbidden_keyvals[i])
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+show_error (GtkWindow *parent,
+ GError *err)
+{
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new (parent,
+ GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
+ GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_OK,
+ _("Error saving the new shortcut"));
+
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ "%s", err->message);
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+}
+
+static void
+accel_edited_callback (GtkCellRendererText *cell,
+ const char *path_string,
+ guint keyval,
+ EggVirtualModifierType mask,
+ guint keycode,
+ gpointer data)
+{
+ MateConfClient *client;
+ GtkTreeView *view = (GtkTreeView *)data;
+ GtkTreeModel *model;
+ GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
+ GtkTreeIter iter;
+ KeyEntry *key_entry, tmp_key;
+ GError *err = NULL;
+ char *str;
+
+ block_accels = FALSE;
+
+ model = gtk_tree_view_get_model (view);
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_path_free (path);
+ gtk_tree_model_get (model, &iter,
+ KEYENTRY_COLUMN, &key_entry,
+ -1);
+
+ /* sanity check */
+ if (key_entry == NULL)
+ return;
+
+ /* CapsLock isn't supported as a keybinding modifier, so keep it from confusing us */
+ mask &= ~EGG_VIRTUAL_LOCK_MASK;
+
+ tmp_key.model = model;
+ tmp_key.keyval = keyval;
+ tmp_key.keycode = keycode;
+ tmp_key.mask = mask;
+ tmp_key.mateconf_key = key_entry->mateconf_key;
+ tmp_key.description = NULL;
+ tmp_key.editable = TRUE; /* kludge to stuff in a return flag */
+
+ if (keyval != 0 || keycode != 0) /* any number of keys can be disabled */
+ gtk_tree_model_foreach (model,
+ (GtkTreeModelForeachFunc) cb_check_for_uniqueness,
+ &tmp_key);
+
+ /* Check for unmodified keys */
+ if (tmp_key.mask == 0 && tmp_key.keycode != 0)
+ {
+ if ((tmp_key.keyval >= GDK_a && tmp_key.keyval <= GDK_z)
+ || (tmp_key.keyval >= GDK_A && tmp_key.keyval <= GDK_Z)
+ || (tmp_key.keyval >= GDK_0 && tmp_key.keyval <= GDK_9)
+ || (tmp_key.keyval >= GDK_kana_fullstop && tmp_key.keyval <= GDK_semivoicedsound)
+ || (tmp_key.keyval >= GDK_Arabic_comma && tmp_key.keyval <= GDK_Arabic_sukun)
+ || (tmp_key.keyval >= GDK_Serbian_dje && tmp_key.keyval <= GDK_Cyrillic_HARDSIGN)
+ || (tmp_key.keyval >= GDK_Greek_ALPHAaccent && tmp_key.keyval <= GDK_Greek_omega)
+ || (tmp_key.keyval >= GDK_hebrew_doublelowline && tmp_key.keyval <= GDK_hebrew_taf)
+ || (tmp_key.keyval >= GDK_Thai_kokai && tmp_key.keyval <= GDK_Thai_lekkao)
+ || (tmp_key.keyval >= GDK_Hangul && tmp_key.keyval <= GDK_Hangul_Special)
+ || (tmp_key.keyval >= GDK_Hangul_Kiyeog && tmp_key.keyval <= GDK_Hangul_J_YeorinHieuh)
+ || keyval_is_forbidden (tmp_key.keyval)) {
+ GtkWidget *dialog;
+ char *name;
+
+ name = binding_name (keyval, keycode, mask, TRUE);
+
+ dialog =
+ gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view))),
+ GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
+ GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_CANCEL,
+ _("The shortcut \"%s\" cannot be used because it will become impossible to type using this key.\n"
+ "Please try with a key such as Control, Alt or Shift at the same time."),
+ name);
+
+ g_free (name);
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+
+ /* set it back to its previous value. */
+ egg_cell_renderer_keys_set_accelerator
+ (EGG_CELL_RENDERER_KEYS (cell),
+ key_entry->keyval, key_entry->keycode, key_entry->mask);
+ return;
+ }
+ }
+
+ /* flag to see if the new accelerator was in use by something */
+ if (!tmp_key.editable)
+ {
+ GtkWidget *dialog;
+ char *name;
+ int response;
+
+ name = binding_name (keyval, keycode, mask, TRUE);
+
+ dialog =
+ gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view))),
+ GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
+ GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_CANCEL,
+ _("The shortcut \"%s\" is already used for\n\"%s\""),
+ name, tmp_key.description ?
+ tmp_key.description : tmp_key.mateconf_key);
+ g_free (name);
+
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ _("If you reassign the shortcut to \"%s\", the \"%s\" shortcut "
+ "will be disabled."),
+ key_entry->description ?
+ key_entry->description : key_entry->mateconf_key,
+ tmp_key.description ?
+ tmp_key.description : tmp_key.mateconf_key);
+
+ gtk_dialog_add_button (GTK_DIALOG (dialog),
+ _("_Reassign"),
+ GTK_RESPONSE_ACCEPT);
+
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog),
+ GTK_RESPONSE_ACCEPT);
+
+ response = gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+
+ if (response == GTK_RESPONSE_ACCEPT)
+ {
+ MateConfClient *client;
+
+ client = mateconf_client_get_default ();
+
+ mateconf_client_set_string (client,
+ tmp_key.mateconf_key,
+ "", &err);
+
+ if (err != NULL)
+ {
+ show_error (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view))),
+ err);
+ g_error_free (err);
+ g_object_unref (client);
+ return;
+ }
+
+ str = binding_name (keyval, keycode, mask, FALSE);
+ mateconf_client_set_string (client,
+ key_entry->mateconf_key,
+ str, &err);
+
+ if (err != NULL)
+ {
+ show_error (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view))),
+ err);
+ g_error_free (err);
+
+ /* reset the previous shortcut */
+ mateconf_client_set_string (client,
+ tmp_key.mateconf_key,
+ str, NULL);
+ }
+
+ g_free (str);
+ g_object_unref (client);
+ }
+ else
+ {
+ /* set it back to its previous value. */
+ egg_cell_renderer_keys_set_accelerator (EGG_CELL_RENDERER_KEYS (cell),
+ key_entry->keyval,
+ key_entry->keycode,
+ key_entry->mask);
+ }
+
+ return;
+ }
+
+ str = binding_name (keyval, keycode, mask, FALSE);
+
+ client = mateconf_client_get_default ();
+ mateconf_client_set_string (client,
+ key_entry->mateconf_key,
+ str,
+ &err);
+ g_free (str);
+ g_object_unref (client);
+
+ if (err != NULL)
+ {
+ show_error (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view))), err);
+ g_error_free (err);
+ key_entry->editable = FALSE;
+ }
+}
+
+static void
+accel_cleared_callback (GtkCellRendererText *cell,
+ const char *path_string,
+ gpointer data)
+{
+ MateConfClient *client;
+ GtkTreeView *view = (GtkTreeView *) data;
+ GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
+ KeyEntry *key_entry;
+ GtkTreeIter iter;
+ GError *err = NULL;
+ GtkTreeModel *model;
+
+ block_accels = FALSE;
+
+ model = gtk_tree_view_get_model (view);
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_path_free (path);
+ gtk_tree_model_get (model, &iter,
+ KEYENTRY_COLUMN, &key_entry,
+ -1);
+
+ /* sanity check */
+ if (key_entry == NULL)
+ return;
+
+ /* Unset the key */
+ client = mateconf_client_get_default();
+ mateconf_client_set_string (client,
+ key_entry->mateconf_key,
+ "",
+ &err);
+ g_object_unref (client);
+
+ if (err != NULL)
+ {
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view))),
+ GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
+ GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_OK,
+ _("Error unsetting accelerator in configuration database: %s"),
+ err->message);
+ gtk_dialog_run (GTK_DIALOG (dialog));
+
+ gtk_widget_destroy (dialog);
+ g_error_free (err);
+ key_entry->editable = FALSE;
+ }
+}
+
+static void
+description_edited_callback (GtkCellRendererText *renderer,
+ gchar *path_string,
+ gchar *new_text,
+ gpointer user_data)
+{
+ MateConfClient *client;
+ GtkTreeView *view = GTK_TREE_VIEW (user_data);
+ GtkTreeModel *model;
+ GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
+ GtkTreeIter iter;
+ KeyEntry *key_entry;
+
+ model = gtk_tree_view_get_model (view);
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_path_free (path);
+
+ gtk_tree_model_get (model, &iter,
+ KEYENTRY_COLUMN, &key_entry,
+ -1);
+
+ /* sanity check */
+ if (key_entry == NULL || key_entry->desc_mateconf_key == NULL)
+ return;
+
+ client = mateconf_client_get_default ();
+ if (!mateconf_client_set_string (client, key_entry->desc_mateconf_key, new_text, NULL))
+ key_entry->desc_editable = FALSE;
+
+ g_object_unref (client);
+}
+
+
+typedef struct
+{
+ GtkTreeView *tree_view;
+ GtkTreePath *path;
+ GtkTreeViewColumn *column;
+} IdleData;
+
+static gboolean
+real_start_editing_cb (IdleData *idle_data)
+{
+ gtk_widget_grab_focus (GTK_WIDGET (idle_data->tree_view));
+ gtk_tree_view_set_cursor (idle_data->tree_view,
+ idle_data->path,
+ idle_data->column,
+ TRUE);
+ gtk_tree_path_free (idle_data->path);
+ g_free (idle_data);
+ return FALSE;
+}
+
+static gboolean
+edit_custom_shortcut (KeyEntry *key)
+{
+ gint result;
+ const gchar *text;
+ gboolean ret;
+
+ gtk_entry_set_text (GTK_ENTRY (custom_shortcut_name_entry), key->description ? key->description : "");
+ gtk_widget_set_sensitive (custom_shortcut_name_entry, key->desc_editable);
+ gtk_widget_grab_focus (custom_shortcut_name_entry);
+ gtk_entry_set_text (GTK_ENTRY (custom_shortcut_command_entry), key->command ? key->command : "");
+ gtk_widget_set_sensitive (custom_shortcut_command_entry, key->cmd_editable);
+
+ gtk_window_present (GTK_WINDOW (custom_shortcut_dialog));
+ result = gtk_dialog_run (GTK_DIALOG (custom_shortcut_dialog));
+ switch (result)
+ {
+ case GTK_RESPONSE_OK:
+ text = gtk_entry_get_text (GTK_ENTRY (custom_shortcut_name_entry));
+ g_free (key->description);
+ key->description = g_strdup (text);
+ text = gtk_entry_get_text (GTK_ENTRY (custom_shortcut_command_entry));
+ g_free (key->command);
+ key->command = g_strdup (text);
+ ret = TRUE;
+ break;
+ default:
+ ret = FALSE;
+ break;
+ }
+
+ gtk_widget_hide (custom_shortcut_dialog);
+
+ return ret;
+}
+
+static gboolean
+remove_custom_shortcut (GtkTreeModel *model, GtkTreeIter *iter)
+{
+ GtkTreeIter parent;
+ MateConfClient *client;
+ gchar *base;
+ KeyEntry *key;
+
+ gtk_tree_model_get (model, iter,
+ KEYENTRY_COLUMN, &key,
+ -1);
+
+ /* not a custom shortcut */
+ if (key->command == NULL)
+ return FALSE;
+
+ client = mateconf_client_get_default ();
+
+ mateconf_client_notify_remove (client, key->mateconf_cnxn);
+ if (key->mateconf_cnxn_desc != 0)
+ mateconf_client_notify_remove (client, key->mateconf_cnxn_desc);
+ if (key->mateconf_cnxn_cmd != 0)
+ mateconf_client_notify_remove (client, key->mateconf_cnxn_cmd);
+
+ base = g_path_get_dirname (key->mateconf_key);
+ mateconf_client_recursive_unset (client, base, 0, NULL);
+ g_free (base);
+ /* suggest sync now so the unset directory actually gets dropped;
+ * if we don't do this we may end up with 'zombie' shortcuts when
+ * restarting the app */
+ mateconf_client_suggest_sync (client, NULL);
+ g_object_unref (client);
+
+ g_free (key->mateconf_key);
+ g_free (key->description);
+ g_free (key->desc_mateconf_key);
+ g_free (key->command);
+ g_free (key->cmd_mateconf_key);
+ g_free (key);
+
+ gtk_tree_model_iter_parent (model, &parent, iter);
+ gtk_tree_store_remove (GTK_TREE_STORE (model), iter);
+ if (!gtk_tree_model_iter_has_child (model, &parent))
+ gtk_tree_store_remove (GTK_TREE_STORE (model), &parent);
+
+ return TRUE;
+}
+
+static void
+update_custom_shortcut (GtkTreeModel *model, GtkTreeIter *iter)
+{
+ KeyEntry *key;
+
+ gtk_tree_model_get (model, iter,
+ KEYENTRY_COLUMN, &key,
+ -1);
+
+ edit_custom_shortcut (key);
+ if (key->command == NULL || key->command[0] == '\0')
+ {
+ remove_custom_shortcut (model, iter);
+ }
+ else
+ {
+ MateConfClient *client;
+
+ gtk_tree_store_set (GTK_TREE_STORE (model), iter,
+ KEYENTRY_COLUMN, key, -1);
+ client = mateconf_client_get_default ();
+ if (key->description != NULL)
+ mateconf_client_set_string (client, key->desc_mateconf_key, key->description, NULL);
+ else
+ mateconf_client_unset (client, key->desc_mateconf_key, NULL);
+ mateconf_client_set_string (client, key->cmd_mateconf_key, key->command, NULL);
+ g_object_unref (client);
+ }
+}
+
+static gchar *
+find_free_mateconf_key (GError **error)
+{
+ MateConfClient *client;
+
+ gchar *dir;
+ int i;
+
+ client = mateconf_client_get_default ();
+
+ for (i = 0; i < MAX_CUSTOM_SHORTCUTS; i++)
+ {
+ dir = g_strdup_printf ("%s/custom%d", MATECONF_BINDING_DIR, i);
+ if (!mateconf_client_dir_exists (client, dir, NULL))
+ break;
+ g_free (dir);
+ }
+
+ if (i == MAX_CUSTOM_SHORTCUTS)
+ {
+ dir = NULL;
+ g_set_error_literal (error,
+ g_quark_from_string ("Keyboard Shortcuts"),
+ 0,
+ _("Too many custom shortcuts"));
+ }
+
+ g_object_unref (client);
+
+ return dir;
+}
+
+static void
+add_custom_shortcut (GtkTreeView *tree_view,
+ GtkTreeModel *model)
+{
+ KeyEntry *key_entry;
+ GtkTreeIter iter;
+ GtkTreeIter parent_iter;
+ GtkTreePath *path;
+ gchar *dir;
+ MateConfClient *client;
+ GError *error;
+
+ error = NULL;
+ dir = find_free_mateconf_key (&error);
+ if (dir == NULL)
+ {
+ show_error (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (tree_view))), error);
+
+ g_error_free (error);
+ return;
+ }
+
+ key_entry = g_new0 (KeyEntry, 1);
+ key_entry->mateconf_key = g_strconcat (dir, "/binding", NULL);
+ key_entry->editable = TRUE;
+ key_entry->model = model;
+ key_entry->desc_mateconf_key = g_strconcat (dir, "/name", NULL);
+ key_entry->description = g_strdup ("");
+ key_entry->desc_editable = TRUE;
+ key_entry->cmd_mateconf_key = g_strconcat (dir, "/action", NULL);
+ key_entry->command = g_strdup ("");
+ key_entry->cmd_editable = TRUE;
+ g_free (dir);
+
+ if (edit_custom_shortcut (key_entry) &&
+ key_entry->command && key_entry->command[0])
+ {
+ find_section (model, &iter, _("Custom Shortcuts"));
+ parent_iter = iter;
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, &parent_iter);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &iter, KEYENTRY_COLUMN, key_entry, -1);
+
+ /* store in mateconf */
+ client = mateconf_client_get_default ();
+ mateconf_client_set_string (client, key_entry->mateconf_key, "", NULL);
+ mateconf_client_set_string (client, key_entry->desc_mateconf_key, key_entry->description, NULL);
+ mateconf_client_set_string (client, key_entry->cmd_mateconf_key, key_entry->command, NULL);
+
+ /* add mateconf watches */
+ key_entry->mateconf_cnxn_desc = mateconf_client_notify_add (client,
+ key_entry->desc_mateconf_key,
+ (MateConfClientNotifyFunc) &keybinding_description_changed,
+ key_entry, NULL, NULL);
+ key_entry->mateconf_cnxn_cmd = mateconf_client_notify_add (client,
+ key_entry->cmd_mateconf_key,
+ (MateConfClientNotifyFunc) &keybinding_command_changed,
+ key_entry, NULL, NULL);
+ key_entry->mateconf_cnxn = mateconf_client_notify_add (client,
+ key_entry->mateconf_key,
+ (MateConfClientNotifyFunc) &keybinding_key_changed,
+ key_entry, NULL, NULL);
+
+
+ g_object_unref (client);
+
+ /* make the new shortcut visible */
+ path = gtk_tree_model_get_path (model, &iter);
+ gtk_tree_view_expand_to_path (tree_view, path);
+ gtk_tree_view_scroll_to_cell (tree_view, path, NULL, FALSE, 0, 0);
+ gtk_tree_path_free (path);
+ }
+ else
+ {
+ g_free (key_entry->mateconf_key);
+ g_free (key_entry->description);
+ g_free (key_entry->desc_mateconf_key);
+ g_free (key_entry->command);
+ g_free (key_entry->cmd_mateconf_key);
+ g_free (key_entry);
+ }
+}
+
+static void
+start_editing_kb_cb (GtkTreeView *treeview,
+ GtkTreePath *path,
+ GtkTreeViewColumn *column,
+ gpointer user_data)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ KeyEntry *key;
+
+ model = gtk_tree_view_get_model (treeview);
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_model_get (model, &iter,
+ KEYENTRY_COLUMN, &key,
+ -1);
+
+ if (key == NULL)
+ {
+ /* This is a section heading - expand or collapse */
+ if (gtk_tree_view_row_expanded (treeview, path))
+ gtk_tree_view_collapse_row (treeview, path);
+ else
+ gtk_tree_view_expand_row (treeview, path, FALSE);
+ return;
+ }
+
+ /* if only the accel can be edited on the selected row
+ * always select the accel column */
+ if (key->desc_editable &&
+ column == gtk_tree_view_get_column (treeview, 0))
+ {
+ gtk_widget_grab_focus (GTK_WIDGET (treeview));
+ gtk_tree_view_set_cursor (treeview, path,
+ gtk_tree_view_get_column (treeview, 0),
+ FALSE);
+ update_custom_shortcut (model, &iter);
+ }
+ else
+ {
+ gtk_widget_grab_focus (GTK_WIDGET (treeview));
+ gtk_tree_view_set_cursor (treeview,
+ path,
+ gtk_tree_view_get_column (treeview, 1),
+ TRUE);
+ }
+}
+
+static gboolean
+start_editing_cb (GtkTreeView *tree_view,
+ GdkEventButton *event,
+ gpointer user_data)
+{
+ GtkTreePath *path;
+ GtkTreeViewColumn *column;
+
+ if (event->window != gtk_tree_view_get_bin_window (tree_view))
+ return FALSE;
+
+ if (gtk_tree_view_get_path_at_pos (tree_view,
+ (gint) event->x,
+ (gint) event->y,
+ &path, &column,
+ NULL, NULL))
+ {
+ IdleData *idle_data;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ KeyEntry *key;
+
+ if (gtk_tree_path_get_depth (path) == 1)
+ {
+ gtk_tree_path_free (path);
+ return FALSE;
+ }
+
+ model = gtk_tree_view_get_model (tree_view);
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_model_get (model, &iter,
+ KEYENTRY_COLUMN, &key,
+ -1);
+
+ /* if only the accel can be edited on the selected row
+ * always select the accel column */
+ if (key->desc_editable &&
+ column == gtk_tree_view_get_column (tree_view, 0))
+ {
+ gtk_widget_grab_focus (GTK_WIDGET (tree_view));
+ gtk_tree_view_set_cursor (tree_view, path,
+ gtk_tree_view_get_column (tree_view, 0),
+ FALSE);
+ update_custom_shortcut (model, &iter);
+ }
+ else
+ {
+ idle_data = g_new (IdleData, 1);
+ idle_data->tree_view = tree_view;
+ idle_data->path = path;
+ idle_data->column = key->desc_editable ? column :
+ gtk_tree_view_get_column (tree_view, 1);
+ g_idle_add ((GSourceFunc) real_start_editing_cb, idle_data);
+ block_accels = TRUE;
+ }
+ g_signal_stop_emission_by_name (tree_view, "button_press_event");
+ }
+ return TRUE;
+}
+
+/* this handler is used to keep accels from activating while the user
+ * is assigning a new shortcut so that he won't accidentally trigger one
+ * of the widgets */
+static gboolean
+maybe_block_accels (GtkWidget *widget,
+ GdkEventKey *event,
+ gpointer user_data)
+{
+ if (block_accels)
+ {
+ return gtk_window_propagate_key_event (GTK_WINDOW (widget), event);
+ }
+ return FALSE;
+}
+
+static void
+cb_dialog_response (GtkWidget *widget, gint response_id, gpointer data)
+{
+ GtkBuilder *builder = data;
+ GtkTreeView *treeview;
+ GtkTreeModel *model;
+ GtkTreeSelection *selection;
+ GtkTreeIter iter;
+
+ treeview = GTK_TREE_VIEW (gtk_builder_get_object (builder,
+ "shortcut_treeview"));
+ model = gtk_tree_view_get_model (treeview);
+
+ if (response_id == GTK_RESPONSE_HELP)
+ {
+ capplet_help (GTK_WINDOW (widget),
+ "goscustdesk-39");
+ }
+ else if (response_id == RESPONSE_ADD)
+ {
+ add_custom_shortcut (treeview, model);
+ }
+ else if (response_id == RESPONSE_REMOVE)
+ {
+ selection = gtk_tree_view_get_selection (treeview);
+ if (gtk_tree_selection_get_selected (selection, NULL, &iter))
+ {
+ remove_custom_shortcut (model, &iter);
+ }
+ }
+ else
+ {
+ clear_old_model (builder);
+ gtk_main_quit ();
+ }
+}
+
+static void
+selection_changed (GtkTreeSelection *selection, gpointer data)
+{
+ GtkWidget *button = data;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ KeyEntry *key;
+ gboolean can_remove;
+
+ can_remove = FALSE;
+ if (gtk_tree_selection_get_selected (selection, &model, &iter))
+ {
+ gtk_tree_model_get (model, &iter, KEYENTRY_COLUMN, &key, -1);
+ if (key && key->command != NULL && key->editable)
+ can_remove = TRUE;
+ }
+
+ gtk_widget_set_sensitive (button, can_remove);
+}
+
+static void
+setup_dialog (GtkBuilder *builder)
+{
+ MateConfClient *client;
+ GtkCellRenderer *renderer;
+ GtkTreeViewColumn *column;
+ GtkWidget *widget;
+ GtkTreeView *treeview;
+ GtkTreeSelection *selection;
+ GSList *allowed_keys;
+
+ treeview = GTK_TREE_VIEW (gtk_builder_get_object (builder,
+ "shortcut_treeview"));
+
+ client = mateconf_client_get_default ();
+
+ g_signal_connect (treeview, "button_press_event",
+ G_CALLBACK (start_editing_cb), builder);
+ g_signal_connect (treeview, "row-activated",
+ G_CALLBACK (start_editing_kb_cb), NULL);
+
+ renderer = gtk_cell_renderer_text_new ();
+
+ g_signal_connect (renderer, "edited",
+ G_CALLBACK (description_edited_callback),
+ treeview);
+
+ column = gtk_tree_view_column_new_with_attributes (_("Action"),
+ renderer,
+ "text", DESCRIPTION_COLUMN,
+ NULL);
+ gtk_tree_view_column_set_cell_data_func (column, renderer, description_set_func, NULL, NULL);
+ gtk_tree_view_column_set_resizable (column, FALSE);
+
+ gtk_tree_view_append_column (treeview, column);
+ gtk_tree_view_column_set_sort_column_id (column, DESCRIPTION_COLUMN);
+
+ renderer = (GtkCellRenderer *) g_object_new (EGG_TYPE_CELL_RENDERER_KEYS,
+ "accel_mode", EGG_CELL_RENDERER_KEYS_MODE_X,
+ NULL);
+
+ g_signal_connect (renderer, "accel_edited",
+ G_CALLBACK (accel_edited_callback),
+ treeview);
+
+ g_signal_connect (renderer, "accel_cleared",
+ G_CALLBACK (accel_cleared_callback),
+ treeview);
+
+ column = gtk_tree_view_column_new_with_attributes (_("Shortcut"), renderer, NULL);
+ gtk_tree_view_column_set_cell_data_func (column, renderer, accel_set_func, NULL, NULL);
+ gtk_tree_view_column_set_resizable (column, FALSE);
+
+ gtk_tree_view_append_column (treeview, column);
+ gtk_tree_view_column_set_sort_column_id (column, KEYENTRY_COLUMN);
+
+ mateconf_client_add_dir (client, MATECONF_BINDING_DIR, MATECONF_CLIENT_PRELOAD_ONELEVEL, NULL);
+ mateconf_client_add_dir (client, "/apps/marco/general", MATECONF_CLIENT_PRELOAD_ONELEVEL, NULL);
+ mateconf_client_notify_add (client,
+ "/apps/marco/general/num_workspaces",
+ (MateConfClientNotifyFunc) key_entry_controlling_key_changed,
+ builder, NULL, NULL);
+
+ /* set up the dialog */
+ reload_key_entries (builder);
+
+ widget = _gtk_builder_get_widget (builder, "mate-keybinding-dialog");
+ capplet_set_icon (widget, "preferences-desktop-keyboard-shortcuts");
+ gtk_widget_show (widget);
+
+ g_signal_connect (widget, "key_press_event", G_CALLBACK (maybe_block_accels), NULL);
+ g_signal_connect (widget, "response", G_CALLBACK (cb_dialog_response), builder);
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
+ g_signal_connect (selection, "changed",
+ G_CALLBACK (selection_changed),
+ _gtk_builder_get_widget (builder, "remove-button"));
+
+ allowed_keys = mateconf_client_get_list (client,
+ MATECONF_BINDING_DIR "/allowed_keys",
+ MATECONF_VALUE_STRING,
+ NULL);
+ if (allowed_keys != NULL)
+ {
+ g_slist_foreach (allowed_keys, (GFunc)g_free, NULL);
+ g_slist_free (allowed_keys);
+ gtk_widget_set_sensitive (_gtk_builder_get_widget (builder, "add-button"),
+ FALSE);
+ }
+
+ g_object_unref (client);
+
+ /* setup the custom shortcut dialog */
+ custom_shortcut_dialog = _gtk_builder_get_widget (builder,
+ "custom-shortcut-dialog");
+ custom_shortcut_name_entry = _gtk_builder_get_widget (builder,
+ "custom-shortcut-name-entry");
+ custom_shortcut_command_entry = _gtk_builder_get_widget (builder,
+ "custom-shortcut-command-entry");
+ gtk_dialog_set_default_response (GTK_DIALOG (custom_shortcut_dialog),
+ GTK_RESPONSE_OK);
+ gtk_window_set_transient_for (GTK_WINDOW (custom_shortcut_dialog),
+ GTK_WINDOW (widget));
+}
+
+static void
+on_window_manager_change (const char *wm_name, GtkBuilder *builder)
+{
+ reload_key_entries (builder);
+}
+
+int
+main (int argc, char *argv[])
+{
+ GtkBuilder *builder;
+
+ g_thread_init (NULL);
+ gtk_init (&argc, &argv);
+
+ bindtextdomain (GETTEXT_PACKAGE, MATELOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+ textdomain (GETTEXT_PACKAGE);
+
+ gtk_init (&argc, &argv);
+
+ activate_settings_daemon ();
+
+ builder = create_builder ();
+
+ if (!builder) /* Warning was already printed to console */
+ exit (EXIT_FAILURE);
+
+ wm_common_register_window_manager_change ((GFunc) on_window_manager_change, builder);
+ setup_dialog (builder);
+
+ gtk_main ();
+
+ g_object_unref (builder);
+ return 0;
+}
+
+/*
+ * vim: sw=2 ts=8 cindent noai bs=2
+ */
diff --git a/capplets/keybindings/mate-keybinding-properties.ui b/capplets/keybindings/mate-keybinding-properties.ui
new file mode 100644
index 00000000..ecd0ae26
--- /dev/null
+++ b/capplets/keybindings/mate-keybinding-properties.ui
@@ -0,0 +1,301 @@
+<?xml version="1.0"?>
+<interface>
+ <requires lib="gtk+" version="2.14"/>
+ <!-- interface-naming-policy toplevel-contextual -->
+ <object class="GtkDialog" id="mate-keybinding-dialog">
+ <property name="border_width">5</property>
+ <property name="title" translatable="yes">Keyboard Shortcuts</property>
+ <property name="type_hint">dialog</property>
+ <property name="has_separator">False</property>
+ <child internal-child="vbox">
+ <object class="GtkVBox" id="shortcut_dialog">
+ <property name="visible">True</property>
+ <property name="spacing">2</property>
+ <child>
+ <object class="GtkVBox" id="vbox3">
+ <property name="visible">True</property>
+ <property name="border_width">5</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkVBox" id="shortcuts_vbox">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkScrolledWindow" id="actions_swindow">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">never</property>
+ <property name="vscrollbar_policy">never</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkTreeView" id="shortcut_treeview">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="rules_hint">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox1">
+ <property name="visible">True</property>
+ <property name="border_width">6</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkImage" id="image1">
+ <property name="visible">True</property>
+ <property name="yalign">0</property>
+ <property name="stock">gtk-dialog-info</property>
+ <property name="icon-size">6</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label12">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">To edit a shortcut key, click on the corresponding row and type a new key combination, or press backspace to clear.</property>
+ <property name="justify">fill</property>
+ <property name="wrap">True</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <object class="GtkHButtonBox" id="dialog-action_area1">
+ <property name="visible">True</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="helpbutton1">
+ <property name="label">gtk-help</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="add-button">
+ <property name="label">gtk-add</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="remove-button">
+ <property name="label">gtk-remove</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="button1">
+ <property name="label">gtk-close</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-11">helpbutton1</action-widget>
+ <action-widget response="0">add-button</action-widget>
+ <action-widget response="1">remove-button</action-widget>
+ <action-widget response="-7">button1</action-widget>
+ </action-widgets>
+ </object>
+ <object class="GtkDialog" id="custom-shortcut-dialog">
+ <property name="title" translatable="yes">Custom Shortcut</property>
+ <property name="type_hint">dialog</property>
+ <property name="has_separator">False</property>
+ <child internal-child="vbox">
+ <object class="GtkVBox" id="dialog-vbox1">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkVBox" id="vbox4">
+ <property name="visible">True</property>
+ <property name="border_width">5</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkTable" id="table1">
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">6</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label13">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Name:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">custom-shortcut-name-entry</property>
+ </object>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label14">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">C_ommand:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">custom-shortcut-command-entry</property>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="custom-shortcut-name-entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">&#x2022;</property>
+ <property name="activates_default">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="custom-shortcut-command-entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">&#x2022;</property>
+ <property name="activates_default">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <object class="GtkHButtonBox" id="dialog-action_area2">
+ <property name="visible">True</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="cancelbutton1">
+ <property name="label">gtk-cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="okbutton1">
+ <property name="label">gtk-apply</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-6">cancelbutton1</action-widget>
+ <action-widget response="-5">okbutton1</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/capplets/keybindings/mate-keybinding.desktop.in.in b/capplets/keybindings/mate-keybinding.desktop.in.in
new file mode 100644
index 00000000..b05bb1ef
--- /dev/null
+++ b/capplets/keybindings/mate-keybinding.desktop.in.in
@@ -0,0 +1,14 @@
+[Desktop Entry]
+_Name=Keyboard Shortcuts
+_Comment=Assign shortcut keys to commands
+Exec=mate-keybinding-properties
+Icon=preferences-desktop-keyboard-shortcuts
+Terminal=false
+Type=Application
+StartupNotify=true
+Categories=MATE;GTK;Settings;X-MATE-PersonalSettings;
+OnlyShowIn=MATE;
+X-MATE-Bugzilla-Bugzilla=MATE
+X-MATE-Bugzilla-Product=mate-control-center
+X-MATE-Bugzilla-Component=Keybinding
+X-MATE-Bugzilla-Version=@VERSION@
diff --git a/capplets/keybindings/mate-keybindings.pc.in b/capplets/keybindings/mate-keybindings.pc.in
new file mode 100644
index 00000000..e9b95105
--- /dev/null
+++ b/capplets/keybindings/mate-keybindings.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+datarootdir=@datarootdir@
+datadir=@datadir@
+pkgdatadir=${datadir}/@PACKAGE@
+keysdir=${pkgdatadir}/keybindings
+
+Name: mate-keybindings
+Description: Keybindings configuration for MATE applications
+Version: @VERSION@
+
diff --git a/capplets/keyboard/Makefile.am b/capplets/keyboard/Makefile.am
new file mode 100644
index 00000000..5705b01f
--- /dev/null
+++ b/capplets/keyboard/Makefile.am
@@ -0,0 +1,42 @@
+# This is used in MATECC_CAPPLETS_CFLAGS
+cappletname = keyboard
+
+bin_PROGRAMS = mate-keyboard-properties
+
+mate_keyboard_properties_SOURCES = \
+ mate-keyboard-properties.c \
+ mate-keyboard-properties-a11y.c \
+ mate-keyboard-properties-a11y.h \
+ mate-keyboard-properties-xkb.c \
+ mate-keyboard-properties-xkbmc.c \
+ mate-keyboard-properties-xkblt.c \
+ mate-keyboard-properties-xkbltadd.c \
+ mate-keyboard-properties-xkbot.c \
+ mate-keyboard-properties-xkbpv.c \
+ mate-keyboard-properties-xkb.h
+
+mate_keyboard_properties_LDADD = $(MATECC_CAPPLETS_LIBS) $(LIBMATEKBDUI_LIBS)
+
+@INTLTOOL_DESKTOP_RULE@
+
+uidir = $(pkgdatadir)/ui
+dist_ui_DATA = mate-keyboard-properties-a11y-notifications.ui \
+ mate-keyboard-properties-dialog.ui \
+ mate-keyboard-properties-layout-chooser.ui \
+ mate-keyboard-properties-model-chooser.ui \
+ mate-keyboard-properties-options-dialog.ui
+
+desktopdir = $(datadir)/applications
+Desktop_in_files = keyboard.desktop.in
+desktop_DATA = $(Desktop_in_files:.desktop.in=.desktop)
+
+INCLUDES = \
+ $(MATECC_CAPPLETS_CFLAGS) \
+ $(LIBMATEKBDUI_CFLAGS) \
+ -DMATELOCALEDIR="\"$(datadir)/locale\"" \
+ -DMATECC_DATA_DIR="\"$(pkgdatadir)\"" \
+ -DMATECC_UI_DIR="\"$(uidir)\""
+CLEANFILES = $(MATECC_CAPPLETS_CLEANFILES) $(Desktop_in_files) $(desktop_DATA)
+EXTRA_DIST = $(ui_DATA)
+
+-include $(top_srcdir)/git.mk
diff --git a/capplets/keyboard/keyboard.desktop.in.in b/capplets/keyboard/keyboard.desktop.in.in
new file mode 100644
index 00000000..fdfacfa6
--- /dev/null
+++ b/capplets/keyboard/keyboard.desktop.in.in
@@ -0,0 +1,14 @@
+[Desktop Entry]
+_Name=Keyboard
+_Comment=Set your keyboard preferences
+Exec=mate-keyboard-properties
+Icon=preferences-desktop-keyboard
+Terminal=false
+Type=Application
+StartupNotify=true
+Categories=MATE;GTK;Settings;HardwareSettings;
+OnlyShowIn=MATE;
+X-MATE-Bugzilla-Bugzilla=MATE
+X-MATE-Bugzilla-Product=mate-control-center
+X-MATE-Bugzilla-Component=keyboard
+X-MATE-Bugzilla-Version=@VERSION@
diff --git a/capplets/keyboard/mate-keyboard-properties-a11y-notifications.ui b/capplets/keyboard/mate-keyboard-properties-a11y-notifications.ui
new file mode 100644
index 00000000..3f33d991
--- /dev/null
+++ b/capplets/keyboard/mate-keyboard-properties-a11y-notifications.ui
@@ -0,0 +1,526 @@
+<?xml version="1.0"?>
+<interface>
+ <requires lib="gtk+" version="2.16"/>
+ <!-- interface-naming-policy toplevel-contextual -->
+ <object class="GtkDialog" id="a11y_notifications_dialog">
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="border_width">5</property>
+ <property name="title" translatable="yes">Keyboard Accessibility Audio Feedback</property>
+ <property name="window_position">center-on-parent</property>
+ <property name="type_hint">dialog</property>
+ <property name="has_separator">False</property>
+ <child internal-child="vbox">
+ <object class="GtkVBox" id="dialog-vbox7">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">2</property>
+ <child>
+ <object class="GtkVBox" id="vbox46">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="border_width">5</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">18</property>
+ <child>
+ <object class="GtkVBox" id="vbox47">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label33">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">General</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox15">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <child>
+ <object class="GtkLabel" id="label40">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label"> </property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox48">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkCheckButton" id="feature_state_change_beep">
+ <property name="label" translatable="yes">Beep when _accessibility features are turned on or off</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="togglekeys_enable">
+ <property name="label" translatable="yes">Beep when a _toggle key is pressed</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="system_bell_box">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label500">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Visual cues for sounds</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox99">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkLabel" id="label99">
+ <property name="visible">True</property>
+ <property name="label"> </property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox99">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkCheckButton" id="visual_bell_enable">
+ <property name="label" translatable="yes">Show _visual feedback for the alert sound</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox3">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkLabel" id="label98">
+ <property name="visible">True</property>
+ <property name="label"> </property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox98">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkRadioButton" id="visual_bell_titlebar">
+ <property name="label" translatable="yes">Flash _window titlebar</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="visual_bell_fullscreen">
+ <property name="label" translatable="yes">Flash entire _screen</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">visual_bell_titlebar</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="slowkeys_notifications_box">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label51">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Slow Keys</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox18">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <child>
+ <object class="GtkLabel" id="label53">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label"> </property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox52">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkCheckButton" id="slowkeys_beep_press">
+ <property name="label" translatable="yes">Beep when a key is pr_essed</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="slowkeys_beep_accept">
+ <property name="label" translatable="yes">Beep when key is _accepted</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="slowkeys_beep_reject">
+ <property name="label" translatable="yes">Beep when key is _rejected</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="bouncekeys_notifications_box">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label54">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Bounce Keys</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox22">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <child>
+ <object class="GtkLabel" id="label55">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label"> </property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox54">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkCheckButton" id="bouncekeys_beep_reject">
+ <property name="label" translatable="yes">Beep when a key is reje_cted</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="stickykeys_notifications_box">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label47">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Sticky Keys</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox17">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <child>
+ <object class="GtkLabel" id="label50">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label"> </property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox50">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkCheckButton" id="stickykeys_modifier_beep">
+ <property name="label" translatable="yes">Beep when a _modifier key is pressed</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <object class="GtkHButtonBox" id="dialog-action_area7">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="button11">
+ <property name="label">gtk-help</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="button12">
+ <property name="label">gtk-close</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-11">button11</action-widget>
+ <action-widget response="-7">button12</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/capplets/keyboard/mate-keyboard-properties-a11y.c b/capplets/keyboard/mate-keyboard-properties-a11y.c
new file mode 100644
index 00000000..3405ffa7
--- /dev/null
+++ b/capplets/keyboard/mate-keyboard-properties-a11y.c
@@ -0,0 +1,325 @@
+/* -*- mode: c; style: linux -*- */
+
+/*
+ * Copyright (C) 2007 The MATE Foundation
+ * Written by Denis Washington <[email protected]>
+ * All Rights Reserved
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "mate-keyboard-properties-a11y.h"
+#include <mateconf/mateconf-client.h>
+#include "mateconf-property-editor.h"
+#include "capplet-util.h"
+
+#define CONFIG_ROOT "/desktop/mate/accessibility/keyboard"
+#define NWID(s) GTK_WIDGET (gtk_builder_get_object (notifications_dialog, s))
+
+static GtkBuilder *notifications_dialog = NULL;
+
+static void
+stickykeys_enable_toggled_cb (GtkWidget *w, GtkBuilder *dialog)
+{
+ gboolean active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w));
+
+ gtk_widget_set_sensitive (WID ("stickykeys_two_key_off"), active);
+ if (notifications_dialog)
+ gtk_widget_set_sensitive (NWID ("stickykeys_notifications_box"), active);
+}
+
+static void
+slowkeys_enable_toggled_cb (GtkWidget *w, GtkBuilder *dialog)
+{
+ gboolean active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w));
+
+ gtk_widget_set_sensitive (WID ("slowkeys_delay_box"), active);
+ if (notifications_dialog)
+ gtk_widget_set_sensitive (NWID ("slowkeys_notifications_box"), active);
+}
+
+static void
+bouncekeys_enable_toggled_cb (GtkWidget *w, GtkBuilder *dialog)
+{
+ gboolean active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w));
+
+ gtk_widget_set_sensitive (WID ("bouncekeys_delay_box"), active);
+ if (notifications_dialog)
+ gtk_widget_set_sensitive (NWID ("bouncekeys_notifications_box"), active);
+}
+
+static void
+visual_bell_enable_toggled_cb (GtkWidget *w, GtkBuilder *dialog)
+{
+ gboolean active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w));
+
+ if (notifications_dialog) {
+ gtk_widget_set_sensitive (NWID ("visual_bell_titlebar"), active);
+ gtk_widget_set_sensitive (NWID ("visual_bell_fullscreen"), active);
+ }
+}
+
+static MateConfEnumStringPair bell_flash_enums[] = {
+ { 0, "frame_flash" },
+ { 1, "fullscreen" },
+ { -1, NULL }
+};
+
+static MateConfValue *
+bell_flash_from_widget (MateConfPropertyEditor *peditor, const MateConfValue *value)
+{
+ MateConfValue *new_value;
+
+ new_value = mateconf_value_new (MATECONF_VALUE_STRING);
+ mateconf_value_set_string (new_value,
+ mateconf_enum_to_string (bell_flash_enums, mateconf_value_get_int (value)));
+
+ return new_value;
+}
+
+static MateConfValue *
+bell_flash_to_widget (MateConfPropertyEditor *peditor, const MateConfValue *value)
+{
+ MateConfValue *new_value;
+ const gchar *str;
+ gint val = 2;
+
+ str = (value && (value->type == MATECONF_VALUE_STRING)) ? mateconf_value_get_string (value) : NULL;
+
+ new_value = mateconf_value_new (MATECONF_VALUE_INT);
+ if (value->type == MATECONF_VALUE_STRING) {
+ mateconf_string_to_enum (bell_flash_enums,
+ str,
+ &val);
+ }
+ mateconf_value_set_int (new_value, val);
+
+ return new_value;
+}
+
+static void
+a11y_notifications_dialog_response_cb (GtkWidget *w, gint response)
+{
+ if (response == GTK_RESPONSE_HELP) {
+
+ }
+ else {
+ gtk_widget_destroy (w);
+ }
+}
+static void
+notifications_button_clicked_cb (GtkWidget *button, GtkBuilder *dialog)
+{
+ GtkWidget *w;
+
+ notifications_dialog = gtk_builder_new ();
+ gtk_builder_add_from_file (notifications_dialog, MATECC_UI_DIR
+ "/mate-keyboard-properties-a11y-notifications.ui",
+ NULL);
+
+ stickykeys_enable_toggled_cb (WID ("stickykeys_enable"), dialog);
+ slowkeys_enable_toggled_cb (WID ("slowkeys_enable"), dialog);
+ bouncekeys_enable_toggled_cb (WID ("bouncekeys_enable"), dialog);
+
+ w = NWID ("feature_state_change_beep");
+ mateconf_peditor_new_boolean (NULL,
+ CONFIG_ROOT "/feature_state_change_beep",
+ w, NULL);
+
+ w = NWID ("togglekeys_enable");
+ mateconf_peditor_new_boolean (NULL,
+ CONFIG_ROOT "/togglekeys_enable",
+ w, NULL);
+
+ w = NWID ("stickykeys_modifier_beep");
+ mateconf_peditor_new_boolean (NULL,
+ CONFIG_ROOT "/stickykeys_modifier_beep",
+ w, NULL);
+
+ w = NWID ("slowkeys_beep_press");
+ mateconf_peditor_new_boolean (NULL,
+ CONFIG_ROOT "/slowkeys_beep_press",
+ w, NULL);
+
+ w = NWID ("slowkeys_beep_accept");
+ mateconf_peditor_new_boolean (NULL,
+ CONFIG_ROOT "/slowkeys_beep_accept",
+ w, NULL);
+
+ w = NWID ("slowkeys_beep_reject");
+ mateconf_peditor_new_boolean (NULL,
+ CONFIG_ROOT "/slowkeys_beep_reject",
+ w, NULL);
+
+ w = NWID ("bouncekeys_beep_reject");
+ mateconf_peditor_new_boolean (NULL,
+ CONFIG_ROOT "/bouncekeys_beep_reject",
+ w, NULL);
+
+ w = NWID ("visual_bell_enable");
+ mateconf_peditor_new_boolean (NULL,
+ "/apps/marco/general/visual_bell",
+ w, NULL);
+ g_signal_connect (w, "toggled",
+ G_CALLBACK (visual_bell_enable_toggled_cb), dialog);
+ visual_bell_enable_toggled_cb (w, dialog);
+
+ mateconf_peditor_new_select_radio (NULL,
+ "/apps/marco/general/visual_bell_type",
+ gtk_radio_button_get_group (GTK_RADIO_BUTTON (NWID ("visual_bell_titlebar"))),
+ "conv-to-widget-cb", bell_flash_to_widget,
+ "conv-from-widget-cb", bell_flash_from_widget,
+ NULL);
+
+ w = NWID ("a11y_notifications_dialog");
+ gtk_window_set_transient_for (GTK_WINDOW (w),
+ GTK_WINDOW (WID ("keyboard_dialog")));
+ g_signal_connect (w, "response",
+ G_CALLBACK (a11y_notifications_dialog_response_cb), NULL);
+
+ gtk_dialog_run (GTK_DIALOG (w));
+
+ g_object_unref (notifications_dialog);
+ notifications_dialog = NULL;
+}
+
+static void
+mousekeys_enable_toggled_cb (GtkWidget *w, GtkBuilder *dialog)
+{
+ gboolean active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w));
+ gtk_widget_set_sensitive (WID ("mousekeys_table"), active);
+}
+
+static MateConfValue *
+mousekeys_accel_time_to_widget (MateConfPropertyEditor *peditor, const MateConfValue *value)
+{
+ GtkAdjustment *adjustment;
+ gdouble range_upper;
+ MateConfValue *new_value;
+
+ adjustment = GTK_ADJUSTMENT (mateconf_property_editor_get_ui_control (peditor));
+ g_object_get (adjustment,
+ "upper", &range_upper,
+ NULL);
+
+ new_value = mateconf_value_new (MATECONF_VALUE_INT);
+ mateconf_value_set_int (new_value, MAX (0, ((int) range_upper) - mateconf_value_get_int (value)));
+
+ return new_value;
+}
+
+static MateConfValue *
+mousekeys_accel_time_from_widget (MateConfPropertyEditor *peditor, const MateConfValue *value)
+{
+ GtkAdjustment *adjustment;
+ gdouble range_value, range_upper;
+ MateConfValue *new_value;
+
+ adjustment = GTK_ADJUSTMENT (mateconf_property_editor_get_ui_control (peditor));
+ g_object_get (adjustment,
+ "value", &range_value,
+ "upper", &range_upper,
+ NULL);
+
+ new_value = mateconf_value_new (MATECONF_VALUE_INT);
+ mateconf_value_set_int (new_value, (int) range_upper - range_value);
+
+ return new_value;
+}
+
+void
+setup_a11y_tabs (GtkBuilder *dialog, MateConfChangeSet *changeset)
+{
+ MateConfClient *client;
+ GtkWidget *w;
+
+ client = mateconf_client_get_default ();
+ mateconf_client_add_dir (client, CONFIG_ROOT, MATECONF_CLIENT_PRELOAD_ONELEVEL, NULL);
+ g_object_unref (client);
+
+ /* Accessibility tab */
+
+ w = WID ("master_enable");
+ mateconf_peditor_new_boolean (changeset,
+ CONFIG_ROOT "/enable",
+ w, NULL);
+
+ w = WID ("stickykeys_enable");
+ mateconf_peditor_new_boolean (changeset,
+ CONFIG_ROOT "/stickykeys_enable",
+ w, NULL);
+ g_signal_connect (w, "toggled",
+ G_CALLBACK (stickykeys_enable_toggled_cb), dialog);
+ stickykeys_enable_toggled_cb (w, dialog);
+
+ w = WID ("stickykeys_two_key_off");
+ mateconf_peditor_new_boolean (changeset,
+ CONFIG_ROOT "/stickykeys_two_key_off",
+ w, NULL);
+
+ w = WID ("slowkeys_enable");
+ mateconf_peditor_new_boolean (changeset,
+ CONFIG_ROOT "/slowkeys_enable",
+ w, NULL);
+ g_signal_connect (w, "toggled",
+ G_CALLBACK (slowkeys_enable_toggled_cb), dialog);
+ slowkeys_enable_toggled_cb (w, dialog);
+
+ w = WID ("bouncekeys_enable");
+ mateconf_peditor_new_boolean (changeset,
+ CONFIG_ROOT "/bouncekeys_enable",
+ w, NULL);
+ g_signal_connect (w, "toggled",
+ G_CALLBACK (bouncekeys_enable_toggled_cb), dialog);
+ bouncekeys_enable_toggled_cb (w, dialog);
+
+ mateconf_peditor_new_numeric_range (changeset,
+ CONFIG_ROOT "/slowkeys_delay",
+ WID ("slowkeys_delay_slide"), NULL);
+ mateconf_peditor_new_numeric_range (changeset,
+ CONFIG_ROOT "/bouncekeys_delay",
+ WID ("bouncekeys_delay_slide"), NULL);
+
+ w = WID ("notifications_button");
+ g_signal_connect (w, "clicked",
+ G_CALLBACK (notifications_button_clicked_cb), dialog);
+
+ /* Mouse Keys tab */
+
+ w = WID ("mousekeys_enable");
+ mateconf_peditor_new_boolean (changeset,
+ CONFIG_ROOT "/mousekeys_enable",
+ w, NULL);
+ g_signal_connect (w, "toggled",
+ G_CALLBACK (mousekeys_enable_toggled_cb), dialog);
+ mousekeys_enable_toggled_cb (w, dialog);
+
+ mateconf_peditor_new_numeric_range (changeset,
+ CONFIG_ROOT "/mousekeys_accel_time",
+ WID ("mousekeys_accel_time_slide"),
+ "conv-to-widget-cb", mousekeys_accel_time_to_widget,
+ "conv-from-widget-cb", mousekeys_accel_time_from_widget,
+ NULL);
+ mateconf_peditor_new_numeric_range (changeset,
+ CONFIG_ROOT "/mousekeys_max_speed",
+ WID ("mousekeys_max_speed_slide"), NULL);
+ mateconf_peditor_new_numeric_range (changeset,
+ CONFIG_ROOT "/mousekeys_init_delay",
+ WID ("mousekeys_init_delay_slide"), NULL);
+}
diff --git a/capplets/keyboard/mate-keyboard-properties-a11y.h b/capplets/keyboard/mate-keyboard-properties-a11y.h
new file mode 100644
index 00000000..35e5678d
--- /dev/null
+++ b/capplets/keyboard/mate-keyboard-properties-a11y.h
@@ -0,0 +1,32 @@
+/* -*- mode: c; style: linux -*- */
+
+/* accessibility-keyboard.c
+ * Copyright (C) 2002 Ximian, Inc.
+ *
+ * Written by: Jody Goldberg <[email protected]>
+ *
+ * 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, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef __MATE_KEYBOARD_PROPERTY_A11Y_H
+#define __MATE_KEYBOARD_PROPERTY_A11Y_H
+
+#include <mateconf/mateconf-changeset.h>
+#include <gtk/gtk.h>
+
+extern void setup_a11y_tabs (GtkBuilder * dialog, MateConfChangeSet * changeset);
+
+#endif /* __MATE_KEYBOARD_PROPERTY_A11Y_H */
diff --git a/capplets/keyboard/mate-keyboard-properties-dialog.ui b/capplets/keyboard/mate-keyboard-properties-dialog.ui
new file mode 100644
index 00000000..eb9e92f0
--- /dev/null
+++ b/capplets/keyboard/mate-keyboard-properties-dialog.ui
@@ -0,0 +1,1857 @@
+<?xml version="1.0"?>
+<interface>
+ <requires lib="gtk+" version="2.16"/>
+ <!-- interface-naming-policy toplevel-contextual -->
+ <object class="GtkAdjustment" id="adjustment1">
+ <property name="value">500</property>
+ <property name="lower">100</property>
+ <property name="upper">2000</property>
+ <property name="step_increment">10</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment10">
+ <property name="value">1</property>
+ <property name="lower">1</property>
+ <property name="upper">100000</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment2">
+ <property name="value">30</property>
+ <property name="lower">10</property>
+ <property name="upper">110</property>
+ <property name="step_increment">10</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment3">
+ <property name="value">1000</property>
+ <property name="lower">100</property>
+ <property name="upper">2500</property>
+ <property name="step_increment">200</property>
+ <property name="page_increment">200</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment4">
+ <property name="value">0.5</property>
+ <property name="upper">500</property>
+ <property name="step_increment">10</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment5">
+ <property name="value">0.5</property>
+ <property name="upper">900</property>
+ <property name="step_increment">10</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment6">
+ <property name="value">1800</property>
+ <property name="upper">3000</property>
+ <property name="step_increment">10</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment7">
+ <property name="value">300</property>
+ <property name="lower">10</property>
+ <property name="upper">1000</property>
+ <property name="step_increment">10</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment8">
+ <property name="value">300</property>
+ <property name="lower">10</property>
+ <property name="upper">2000</property>
+ <property name="step_increment">10</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment9">
+ <property name="value">1</property>
+ <property name="lower">1</property>
+ <property name="upper">100000</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkDialog" id="keyboard_dialog">
+ <property name="border_width">5</property>
+ <property name="title" translatable="yes">Keyboard Preferences</property>
+ <property name="default_width">450</property>
+ <property name="default_height">430</property>
+ <property name="type_hint">dialog</property>
+ <property name="has_separator">False</property>
+ <child internal-child="vbox">
+ <object class="GtkVBox" id="dialog-vbox1">
+ <property name="visible">True</property>
+ <property name="spacing">2</property>
+ <child>
+ <object class="GtkVBox" id="vbox1">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="border_width">5</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkNotebook" id="keyboard_notebook">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <child>
+ <object class="GtkVBox" id="vbox2">
+ <property name="visible">True</property>
+ <property name="border_width">12</property>
+ <property name="spacing">18</property>
+ <child>
+ <object class="GtkVBox" id="vbox22">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Repeat Keys</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox19">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkLabel" id="label43">
+ <property name="visible">True</property>
+ <property name="label"> </property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox3">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkCheckButton" id="repeat_toggle">
+ <property name="label" translatable="yes">Key presses _repeat when key is held down</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="repeat_table">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkVBox" id="vbox24">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="repeat_delay_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Delay:</property>
+ <property name="use_underline">True</property>
+ <property name="justify">center</property>
+ <property name="mnemonic_widget">repeat_delay_scale</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="repeat_speed_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Speed:</property>
+ <property name="use_underline">True</property>
+ <property name="justify">center</property>
+ <property name="mnemonic_widget">repeat_speed_scale</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox25">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="delay_short_label">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property name="xpad">10</property>
+ <property name="label" translatable="yes">Short</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ <attribute name="scale" value="0.830000"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="repeat_slow_label">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property name="xpad">10</property>
+ <property name="label" translatable="yes">Slow</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ <attribute name="scale" value="0.830000"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox26">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkHScale" id="repeat_delay_scale">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="adjustment">adjustment1</property>
+ <property name="draw_value">False</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHScale" id="repeat_speed_scale">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="adjustment">adjustment2</property>
+ <property name="draw_value">False</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="repeat_speed_scale-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes">Repeat keys speed</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox27">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="delay_long_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Long</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ <attribute name="scale" value="0.830000"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="repeat_fast_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Fast</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ <attribute name="scale" value="0.830000"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox23">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label5">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Cursor Blinking</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox20">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkLabel" id="label44">
+ <property name="visible">True</property>
+ <property name="label"> </property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="cursor_vbox">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkCheckButton" id="cursor_toggle">
+ <property name="label" translatable="yes">Cursor _blinks in text fields</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="cursor_hbox">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="cursor_speed_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">S_peed:</property>
+ <property name="use_underline">True</property>
+ <property name="justify">center</property>
+ <property name="mnemonic_widget">cursor_blink_time_scale</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox25">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="blink_slow_label">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property name="xpad">10</property>
+ <property name="label" translatable="yes">Slow</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ <attribute name="scale" value="0.830000"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHScale" id="cursor_blink_time_scale">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="update_policy">discontinuous</property>
+ <property name="adjustment">adjustment3</property>
+ <property name="draw_value">False</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="cursor_blink_time_scale-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes">Cursor blinks speed</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="blink_fast_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Fast</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ <attribute name="scale" value="0.830000"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">General</property>
+ <property name="justify">center</property>
+ </object>
+ <packing>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox33">
+ <property name="visible">True</property>
+ <property name="border_width">12</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkVBox" id="vbox34">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkScrolledWindow" id="scrolledwindow1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">automatic</property>
+ <property name="vscrollbar_policy">automatic</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkTreeView" id="xkb_layouts_selected">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip_text" translatable="yes">List of keyboard layouts selected for usage</property>
+ <property name="headers_visible">False</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox2">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <property name="homogeneous">True</property>
+ <child>
+ <object class="GtkVBox" id="vbox4">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <property name="homogeneous">True</property>
+ <child>
+ <object class="GtkButton" id="xkb_layouts_add">
+ <property name="label" translatable="yes">_Add...</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="tooltip_text" translatable="yes">Select a keyboard layout to be added to the list</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="xkb_layouts_remove">
+ <property name="label">gtk-remove</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="tooltip_text" translatable="yes">Remove the selected keyboard layout from the list</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox5">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <property name="homogeneous">True</property>
+ <child>
+ <object class="GtkButton" id="xkb_layouts_move_up">
+ <property name="label" translatable="yes">Move _Up</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="tooltip_text" translatable="yes">Move the selected keyboard layout up in the list</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="xkb_layouts_move_down">
+ <property name="label" translatable="yes">Move _Down</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="tooltip_text" translatable="yes">Move the selected keyboard layout down in the list</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox6">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <property name="homogeneous">True</property>
+ <child>
+ <object class="GtkButton" id="xkb_layouts_show">
+ <property name="label" translatable="yes">_Show...</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="tooltip_text" translatable="yes">Print a diagram of the selected keyboard layout</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="chk_separate_group_per_window">
+ <property name="label" translatable="yes">_Separate layout for each window</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="chk_new_windows_inherit_layout">
+ <property name="label" translatable="yes">New windows u_se active window's layout</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="xkb_models_box">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="label48">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Keyboard _model:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">xkb_model_pick</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="xkb_model_pick">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHButtonBox" id="hbuttonbox2">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="xkb_layout_options">
+ <property name="label" translatable="yes">_Options...</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="tooltip_text" translatable="yes">View and edit keyboard layout options</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="xkb_reset_to_defaults">
+ <property name="label" translatable="yes">Reset to De_faults</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="tooltip_text" translatable="yes">Replace the current keyboard layout settings with the
+default settings</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="label46">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Layouts</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox77">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="border_width">12</property>
+ <property name="spacing">18</property>
+ <child>
+ <object class="GtkVBox" id="vbox78">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkHBox" id="hbox39">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <child>
+ <object class="GtkVBox" id="vbox79">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkCheckButton" id="master_enable">
+ <property name="label" translatable="yes">_Accessibility features can be toggled with keyboard shortcuts</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox80">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label73">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Sticky Keys</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox40">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <child>
+ <object class="GtkLabel" id="label74">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label"> </property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox81">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkCheckButton" id="stickykeys_enable">
+ <property name="label" translatable="yes">_Simulate simultaneous keypresses</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="stickykeys_two_key_off">
+ <property name="label" translatable="yes">Disa_ble sticky keys if two keys are pressed together</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox82">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label75">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Slow Keys</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox41">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <child>
+ <object class="GtkLabel" id="label76">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label"> </property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox83">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkCheckButton" id="slowkeys_enable">
+ <property name="label" translatable="yes">_Only accept long keypresses</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="slowkeys_delay_box">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="slowkeys_delay_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Delay:</property>
+ <property name="use_underline">True</property>
+ <property name="justify">center</property>
+ <property name="mnemonic_widget">slowkeys_delay_slide</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox42">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="slowkeys_slow_label">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property name="xpad">10</property>
+ <property name="label" translatable="yes">Short</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ <attribute name="scale" value="0.830000"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHScale" id="slowkeys_delay_slide">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="update_policy">discontinuous</property>
+ <property name="adjustment">adjustment4</property>
+ <property name="draw_value">False</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="slowkeys_delay_slide-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes">Cursor blinks speed</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="slowkeys_long_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Long</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ <attribute name="scale" value="0.830000"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox84">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label77">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Bounce Keys</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox43">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <child>
+ <object class="GtkLabel" id="label78">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label"> </property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox85">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkCheckButton" id="bouncekeys_enable">
+ <property name="label" translatable="yes">_Ignore fast duplicate keypresses</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="bouncekeys_delay_box">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="bouncekeys_delay_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">D_elay:</property>
+ <property name="use_underline">True</property>
+ <property name="justify">center</property>
+ <property name="mnemonic_widget">bouncekeys_delay_slide</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox44">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="bouncekeys_short_label">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property name="xpad">10</property>
+ <property name="label" translatable="yes">Short</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ <attribute name="scale" value="0.830000"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHScale" id="bouncekeys_delay_slide">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="update_policy">discontinuous</property>
+ <property name="adjustment">adjustment5</property>
+ <property name="draw_value">False</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="bouncekeys_delay_slide-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes">Cursor blinks speed</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="bouncekeys_long_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Long</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ <attribute name="scale" value="0.830000"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHButtonBox" id="hbuttonbox7">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="notifications_button">
+ <property name="label" translatable="yes">Audio _Feedback...</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="label6">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label" translatable="yes">Accessibility</property>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox89">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="border_width">12</property>
+ <child>
+ <object class="GtkVBox" id="vbox90">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkCheckButton" id="mousekeys_enable">
+ <property name="label" translatable="yes">_Pointer can be controlled using the keypad</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox46">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <child>
+ <object class="GtkLabel" id="label80">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label"> </property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox91">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkTable" id="mousekeys_table">
+ <property name="visible">True</property>
+ <property name="n_rows">3</property>
+ <property name="n_columns">4</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="mousekeys_slow_label2">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property name="label" translatable="yes">Slow</property>
+ <property name="justify">center</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ <attribute name="scale" value="0.830000"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="mousekeys_slow_label">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property name="label" translatable="yes">Slow</property>
+ <property name="justify">center</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ <attribute name="scale" value="0.830000"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHScale" id="mousekeys_accel_time_slide">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="update_policy">discontinuous</property>
+ <property name="adjustment">adjustment6</property>
+ <property name="draw_value">False</property>
+ <property name="value_pos">right</property>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHScale" id="mousekeys_max_speed_slide">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="update_policy">discontinuous</property>
+ <property name="adjustment">adjustment7</property>
+ <property name="digits">0</property>
+ <property name="draw_value">False</property>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="mousekeys_fast_label2">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Fast</property>
+ <property name="justify">center</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ <attribute name="scale" value="0.830000"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="right_attach">4</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="mousekeys_fast_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Fast</property>
+ <property name="justify">center</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ <attribute name="scale" value="0.830000"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="right_attach">4</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="mousekeys_speed_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Speed:</property>
+ <property name="use_underline">True</property>
+ <property name="justify">center</property>
+ <property name="mnemonic_widget">mousekeys_max_speed_slide</property>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="mousekeys_acceleration_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Acceleration:</property>
+ <property name="use_underline">True</property>
+ <property name="justify">center</property>
+ <property name="mnemonic_widget">mousekeys_accel_time_slide</property>
+ </object>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="mousekeys_delay_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Delay:</property>
+ <property name="use_underline">True</property>
+ <property name="justify">center</property>
+ <property name="mnemonic_widget">mousekeys_init_delay_slide</property>
+ </object>
+ <packing>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="mousekeys_short_label">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property name="label" translatable="yes">Short</property>
+ <property name="justify">center</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ <attribute name="scale" value="0.830000"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHScale" id="mousekeys_init_delay_slide">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="update_policy">discontinuous</property>
+ <property name="adjustment">adjustment8</property>
+ <property name="digits">0</property>
+ <property name="draw_value">False</property>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="mousekeys_long_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Long</property>
+ <property name="justify">center</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ <attribute name="scale" value="0.830000"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="right_attach">4</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="label8">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label" translatable="yes">Mouse Keys</property>
+ </object>
+ <packing>
+ <property name="position">3</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox14">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkVBox" id="vbox18">
+ <property name="visible">True</property>
+ <property name="border_width">12</property>
+ <property name="spacing">18</property>
+ <child>
+ <object class="GtkVBox" id="vbox28">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkCheckButton" id="break_enabled_toggle">
+ <property name="label" translatable="yes">_Lock screen to enforce typing break</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="tooltip_text" translatable="yes">Lock screen after a certain duration to help prevent repetitive keyboard use injuries</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox26">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkLabel" id="label45">
+ <property name="visible">True</property>
+ <property name="label"> </property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="break_details_table">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkHBox" id="hbox27">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkVBox" id="vbox30">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label37">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Work interval lasts:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">break_enabled_spin</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label30">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Break interval lasts:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">break_interval_spin</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox28">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkVBox" id="vbox31">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkSpinButton" id="break_enabled_spin">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip_text" translatable="yes">Duration of work before forcing a break</property>
+ <property name="adjustment">adjustment9</property>
+ <property name="climb_rate">1</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="break_interval_spin">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip_text" translatable="yes">Duration of the break when typing is disallowed</property>
+ <property name="adjustment">adjustment10</property>
+ <property name="climb_rate">1</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox32">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label39">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">minutes</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label31">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">minutes</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="break_postponement_toggle">
+ <property name="label" translatable="yes">All_ow postponing of breaks</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="tooltip_text" translatable="yes">Check if breaks are allowed to be postponed</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="label20">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Typing Break</property>
+ </object>
+ <packing>
+ <property name="position">4</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox21">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="label42">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Type to test settings:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">test_entry</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="test_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="max_length">256</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <object class="GtkHButtonBox" id="hbuttonbox1">
+ <property name="visible">True</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="helpbutton1">
+ <property name="label">gtk-help</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="button4">
+ <property name="label">gtk-close</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="has_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-1">helpbutton1</action-widget>
+ <action-widget response="-1">button4</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/capplets/keyboard/mate-keyboard-properties-layout-chooser.ui b/capplets/keyboard/mate-keyboard-properties-layout-chooser.ui
new file mode 100644
index 00000000..2beb56d0
--- /dev/null
+++ b/capplets/keyboard/mate-keyboard-properties-layout-chooser.ui
@@ -0,0 +1,315 @@
+<?xml version="1.0"?>
+<interface>
+ <requires lib="gtk+" version="2.16"/>
+ <!-- interface-naming-policy toplevel-contextual -->
+ <object class="GtkDialog" id="xkb_layout_chooser">
+ <property name="visible">True</property>
+ <property name="border_width">5</property>
+ <property name="title" translatable="yes">Choose a Layout</property>
+ <property name="default_width">670</property>
+ <property name="default_height">350</property>
+ <property name="type_hint">dialog</property>
+ <property name="has_separator">False</property>
+ <child internal-child="vbox">
+ <object class="GtkVBox" id="dialog-vbox3">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">2</property>
+ <child>
+ <object class="GtkVBox" id="vbox40">
+ <property name="visible">True</property>
+ <property name="border_width">5</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkNotebook" id="choosers_nb">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <child>
+ <object class="GtkAlignment" id="alignment1">
+ <property name="visible">True</property>
+ <property name="top_padding">3</property>
+ <property name="bottom_padding">3</property>
+ <property name="left_padding">3</property>
+ <property name="right_padding">6</property>
+ <child>
+ <object class="GtkTable" id="table1">
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkComboBox" id="xkb_country_variants_available">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBox" id="xkb_countries_available">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Variants:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">xkb_country_variants_available</property>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Country:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">xkb_countries_available</property>
+ </object>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="label22">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">By _country</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment2">
+ <property name="visible">True</property>
+ <property name="top_padding">3</property>
+ <property name="bottom_padding">3</property>
+ <property name="left_padding">3</property>
+ <property name="right_padding">3</property>
+ <child>
+ <object class="GtkTable" id="table3">
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkComboBox" id="xkb_language_variants_available">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBox" id="xkb_languages_available">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label13">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Variants:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">xkb_country_variants_available</property>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label12">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Language:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">xkb_countries_available</property>
+ </object>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="label9">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">By _language</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vboxPreview">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkHBox" id="hbox1">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label10">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Preview:</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="previewFrame">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <object class="GtkHButtonBox" id="hbtnBox">
+ <property name="visible">True</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="btnPrint">
+ <property name="label">gtk-print</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ <property name="secondary">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="cancelbutton2">
+ <property name="label">gtk-cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="btnOk1">
+ <property name="label">gtk-add</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="1">btnPrint</action-widget>
+ <action-widget response="-6">cancelbutton2</action-widget>
+ <action-widget response="-5">btnOk1</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/capplets/keyboard/mate-keyboard-properties-model-chooser.ui b/capplets/keyboard/mate-keyboard-properties-model-chooser.ui
new file mode 100644
index 00000000..3fe7d4e1
--- /dev/null
+++ b/capplets/keyboard/mate-keyboard-properties-model-chooser.ui
@@ -0,0 +1,142 @@
+<?xml version="1.0"?>
+<interface>
+ <requires lib="gtk+" version="2.16"/>
+ <!-- interface-naming-policy toplevel-contextual -->
+ <object class="GtkDialog" id="xkb_model_chooser">
+ <property name="visible">True</property>
+ <property name="border_width">5</property>
+ <property name="title" translatable="yes">Choose a Keyboard Model</property>
+ <property name="modal">True</property>
+ <property name="default_width">450</property>
+ <property name="default_height">400</property>
+ <property name="type_hint">dialog</property>
+ <property name="has_separator">False</property>
+ <child internal-child="vbox">
+ <object class="GtkVBox" id="dialog-vbox2">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">2</property>
+ <child>
+ <object class="GtkVBox" id="xkb_model_chooser_pane">
+ <property name="visible">True</property>
+ <property name="border_width">5</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="vendors_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Vendors:</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="vendors_scrolledwindow">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">automatic</property>
+ <property name="vscrollbar_policy">automatic</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkTreeView" id="vendors_list">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_visible">False</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label7">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Models:</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="scrolledwindow3">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">automatic</property>
+ <property name="vscrollbar_policy">automatic</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkTreeView" id="models_list">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_visible">False</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <object class="GtkHButtonBox" id="dialog-action_area1">
+ <property name="visible">True</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="cancelbutton1">
+ <property name="label">gtk-cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="btnOk">
+ <property name="label">gtk-ok</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-6">cancelbutton1</action-widget>
+ <action-widget response="-5">btnOk</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/capplets/keyboard/mate-keyboard-properties-options-dialog.ui b/capplets/keyboard/mate-keyboard-properties-options-dialog.ui
new file mode 100644
index 00000000..f92c4cd2
--- /dev/null
+++ b/capplets/keyboard/mate-keyboard-properties-options-dialog.ui
@@ -0,0 +1,94 @@
+<?xml version="1.0"?>
+<interface>
+ <requires lib="gtk+" version="2.16"/>
+ <!-- interface-naming-policy toplevel-contextual -->
+ <object class="GtkDialog" id="xkb_options_dialog">
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="border_width">5</property>
+ <property name="title" translatable="yes">Keyboard Layout Options</property>
+ <property name="window_position">center-on-parent</property>
+ <property name="default_width">550</property>
+ <property name="default_height">400</property>
+ <property name="type_hint">dialog</property>
+ <property name="has_separator">False</property>
+ <child internal-child="vbox">
+ <object class="GtkVBox" id="dialog-vbox4">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">2</property>
+ <child>
+ <object class="GtkScrolledWindow" id="options_scroll">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="border_width">5</property>
+ <property name="hscrollbar_policy">automatic</property>
+ <property name="vscrollbar_policy">automatic</property>
+ <property name="shadow_type">out</property>
+ <child>
+ <object class="GtkViewport" id="viewport1">
+ <property name="visible">True</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkVBox" id="options_vbox">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <object class="GtkHButtonBox" id="dialog-action_area4">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="button3">
+ <property name="label">gtk-help</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="button2">
+ <property name="label">gtk-close</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-11">button3</action-widget>
+ <action-widget response="-7">button2</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/capplets/keyboard/mate-keyboard-properties-xkb.c b/capplets/keyboard/mate-keyboard-properties-xkb.c
new file mode 100644
index 00000000..3316b4d4
--- /dev/null
+++ b/capplets/keyboard/mate-keyboard-properties-xkb.c
@@ -0,0 +1,254 @@
+/* -*- mode: c; style: linux -*- */
+
+/* mate-keyboard-properties-xkb.c
+ * Copyright (C) 2003-2007 Sergey V. Udaltsov
+ *
+ * Written by: Sergey V. Udaltsov <[email protected]>
+ *
+ * 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, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+#include <gdk/gdkx.h>
+#include <mateconf/mateconf-client.h>
+#include <glib/gi18n.h>
+
+#include "capplet-util.h"
+#include "mateconf-property-editor.h"
+
+#include "mate-keyboard-properties-xkb.h"
+
+#include <libmatekbd/matekbd-desktop-config.h>
+
+XklEngine *engine;
+XklConfigRegistry *config_registry;
+
+MatekbdKeyboardConfig initial_config;
+MatekbdDesktopConfig desktop_config;
+
+MateConfClient *xkb_mateconf_client;
+
+char *
+xci_desc_to_utf8 (XklConfigItem * ci)
+{
+ char *sd = g_strstrip (ci->description);
+ return sd[0] == 0 ? g_strdup (ci->name) : g_strdup (sd);
+}
+
+static void
+set_model_text (GtkWidget * picker, MateConfValue * value)
+{
+ XklConfigItem *ci = xkl_config_item_new ();
+ const char *model = NULL;
+
+ if (value != NULL && value->type == MATECONF_VALUE_STRING) {
+ model = mateconf_value_get_string (value);
+ if (model != NULL && model[0] == '\0')
+ model = NULL;
+ }
+
+ if (model == NULL) {
+ model = initial_config.model;
+ if (model == NULL)
+ model = "";
+ }
+
+ g_snprintf (ci->name, sizeof (ci->name), "%s", model);
+
+ if (xkl_config_registry_find_model (config_registry, ci)) {
+ char *d;
+
+ d = xci_desc_to_utf8 (ci);
+ gtk_button_set_label (GTK_BUTTON (picker), d);
+ g_free (d);
+ } else {
+ gtk_button_set_label (GTK_BUTTON (picker), _("Unknown"));
+ }
+ g_object_unref (G_OBJECT (ci));
+}
+
+static void
+model_key_changed (MateConfClient * client,
+ guint cnxn_id, MateConfEntry * entry, GtkBuilder * dialog)
+{
+ set_model_text (WID ("xkb_model_pick"),
+ mateconf_entry_get_value (entry));
+
+ enable_disable_restoring (dialog);
+}
+
+static void
+setup_model_entry (GtkBuilder * dialog)
+{
+ MateConfValue *value;
+
+ value = mateconf_client_get (xkb_mateconf_client,
+ MATEKBD_KEYBOARD_CONFIG_KEY_MODEL, NULL);
+ set_model_text (WID ("xkb_model_pick"), value);
+ if (value != NULL)
+ mateconf_value_free (value);
+
+ mateconf_client_notify_add (xkb_mateconf_client,
+ MATEKBD_KEYBOARD_CONFIG_KEY_MODEL,
+ (MateConfClientNotifyFunc) model_key_changed,
+ dialog, NULL, NULL);
+}
+
+static void
+cleanup_xkb_tabs (GtkBuilder * dialog)
+{
+ matekbd_desktop_config_term (&desktop_config);
+ matekbd_keyboard_config_term (&initial_config);
+ g_object_unref (G_OBJECT (config_registry));
+ config_registry = NULL;
+ g_object_unref (G_OBJECT (engine));
+ engine = NULL;
+ g_object_unref (G_OBJECT (xkb_mateconf_client));
+ xkb_mateconf_client = NULL;
+}
+
+static void
+reset_to_defaults (GtkWidget * button, GtkBuilder * dialog)
+{
+ MatekbdKeyboardConfig empty_kbd_config;
+
+ matekbd_keyboard_config_init (&empty_kbd_config, xkb_mateconf_client,
+ engine);
+ matekbd_keyboard_config_save_to_mateconf (&empty_kbd_config);
+ matekbd_keyboard_config_term (&empty_kbd_config);
+
+ mateconf_client_unset (xkb_mateconf_client,
+ MATEKBD_DESKTOP_CONFIG_KEY_DEFAULT_GROUP, NULL);
+
+ /* all the rest is g-s-d's business */
+}
+
+static void
+chk_separate_group_per_window_toggled (MateConfPropertyEditor * peditor,
+ const gchar * key,
+ const MateConfValue * value,
+ GtkBuilder * dialog)
+{
+ gtk_widget_set_sensitive (WID ("chk_new_windows_inherit_layout"),
+ mateconf_value_get_bool (value));
+}
+
+static void
+chk_new_windows_inherit_layout_toggled (GtkWidget *
+ chk_new_windows_inherit_layout,
+ GtkBuilder * dialog)
+{
+ xkb_save_default_group (gtk_toggle_button_get_active
+ (GTK_TOGGLE_BUTTON
+ (chk_new_windows_inherit_layout)) ? -1 :
+ 0);
+}
+
+void
+setup_xkb_tabs (GtkBuilder * dialog, MateConfChangeSet * changeset)
+{
+ GObject *peditor;
+ GtkWidget *chk_new_windows_inherit_layout =
+ WID ("chk_new_windows_inherit_layout");
+
+ xkb_mateconf_client = mateconf_client_get_default ();
+
+ engine = xkl_engine_get_instance (GDK_DISPLAY ());
+ config_registry = xkl_config_registry_get_instance (engine);
+
+ matekbd_desktop_config_init (&desktop_config, xkb_mateconf_client,
+ engine);
+ matekbd_desktop_config_load_from_mateconf (&desktop_config);
+
+ xkl_config_registry_load (config_registry,
+ desktop_config.load_extra_items);
+
+ matekbd_keyboard_config_init (&initial_config, xkb_mateconf_client,
+ engine);
+ matekbd_keyboard_config_load_from_x_initial (&initial_config, NULL);
+
+ setup_model_entry (dialog);
+
+ peditor = mateconf_peditor_new_boolean
+ (changeset, (gchar *) MATEKBD_DESKTOP_CONFIG_KEY_GROUP_PER_WINDOW,
+ WID ("chk_separate_group_per_window"), NULL);
+
+ g_signal_connect (peditor, "value-changed", (GCallback)
+ chk_separate_group_per_window_toggled, dialog);
+
+#ifdef HAVE_X11_EXTENSIONS_XKB_H
+ if (strcmp (xkl_engine_get_backend_name (engine), "XKB"))
+#endif
+ gtk_widget_hide (WID ("xkb_layouts_print"));
+
+ xkb_layouts_prepare_selected_tree (dialog, changeset);
+ xkb_layouts_fill_selected_tree (dialog);
+
+ gtk_widget_set_sensitive (chk_new_windows_inherit_layout,
+ gtk_toggle_button_get_active
+ (GTK_TOGGLE_BUTTON
+ (WID
+ ("chk_separate_group_per_window"))));
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON
+ (chk_new_windows_inherit_layout),
+ xkb_get_default_group () < 0);
+
+ xkb_layouts_register_buttons_handlers (dialog);
+ g_signal_connect (G_OBJECT (WID ("xkb_reset_to_defaults")),
+ "clicked", G_CALLBACK (reset_to_defaults),
+ dialog);
+
+ g_signal_connect (G_OBJECT (chk_new_windows_inherit_layout),
+ "toggled", (GCallback)
+ chk_new_windows_inherit_layout_toggled, dialog);
+
+ g_signal_connect_swapped (G_OBJECT (WID ("xkb_layout_options")),
+ "clicked",
+ G_CALLBACK (xkb_options_popup_dialog),
+ dialog);
+
+ g_signal_connect_swapped (G_OBJECT (WID ("xkb_model_pick")),
+ "clicked", G_CALLBACK (choose_model),
+ dialog);
+
+ xkb_layouts_register_mateconf_listener (dialog);
+ xkb_options_register_mateconf_listener (dialog);
+
+ g_signal_connect (G_OBJECT (WID ("keyboard_dialog")),
+ "destroy", G_CALLBACK (cleanup_xkb_tabs),
+ dialog);
+
+ enable_disable_restoring (dialog);
+}
+
+void
+enable_disable_restoring (GtkBuilder * dialog)
+{
+ MatekbdKeyboardConfig gswic;
+ gboolean enable;
+
+ matekbd_keyboard_config_init (&gswic, xkb_mateconf_client, engine);
+ matekbd_keyboard_config_load_from_mateconf (&gswic, NULL);
+
+ enable = !matekbd_keyboard_config_equals (&gswic, &initial_config);
+
+ matekbd_keyboard_config_term (&gswic);
+ gtk_widget_set_sensitive (WID ("xkb_reset_to_defaults"), enable);
+}
diff --git a/capplets/keyboard/mate-keyboard-properties-xkb.h b/capplets/keyboard/mate-keyboard-properties-xkb.h
new file mode 100644
index 00000000..19b673ba
--- /dev/null
+++ b/capplets/keyboard/mate-keyboard-properties-xkb.h
@@ -0,0 +1,104 @@
+/* -*- mode: c; style: linux -*- */
+
+/* mate-keyboard-properties-xkb.h
+ * Copyright (C) 2003-2007 Sergey V Udaltsov
+ *
+ * Written by Sergey V. Udaltsov <[email protected]>
+ *
+ * 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, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef __MATE_KEYBOARD_PROPERTY_XKB_H
+#define __MATE_KEYBOARD_PROPERTY_XKB_H
+
+#include <mateconf/mateconf-client.h>
+
+#include "libmatekbd/matekbd-keyboard-config.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#define CWID(s) GTK_WIDGET (gtk_builder_get_object (chooser_dialog, s))
+extern XklEngine *engine;
+extern XklConfigRegistry *config_registry;
+extern MateConfClient *xkb_mateconf_client;
+extern MatekbdKeyboardConfig initial_config;
+
+extern void setup_xkb_tabs (GtkBuilder * dialog,
+ MateConfChangeSet * changeset);
+
+extern void xkb_layouts_fill_selected_tree (GtkBuilder * dialog);
+
+extern void xkb_layouts_register_buttons_handlers (GtkBuilder * dialog);
+
+extern void xkb_layouts_register_mateconf_listener (GtkBuilder * dialog);
+
+extern void xkb_options_register_mateconf_listener (GtkBuilder * dialog);
+
+extern void xkb_layouts_prepare_selected_tree (GtkBuilder * dialog,
+ MateConfChangeSet * changeset);
+
+extern void xkb_options_load_options (GtkBuilder * dialog);
+
+extern void xkb_options_popup_dialog (GtkBuilder * dialog);
+
+extern void clear_xkb_elements_list (GSList * list);
+
+extern char *xci_desc_to_utf8 (XklConfigItem * ci);
+
+extern gchar *xkb_layout_description_utf8 (const gchar * visible);
+
+extern void enable_disable_restoring (GtkBuilder * dialog);
+
+extern void preview_toggled (GtkBuilder * dialog, GtkWidget * button);
+
+extern void choose_model (GtkBuilder * dialog);
+
+extern void xkb_layout_choose (GtkBuilder * dialog);
+
+extern GSList *xkb_layouts_get_selected_list (void);
+
+extern GSList *xkb_options_get_selected_list (void);
+
+#define xkb_layouts_set_selected_list(list) \
+ mateconf_client_set_list (mateconf_client_get_default (), \
+ MATEKBD_KEYBOARD_CONFIG_KEY_LAYOUTS, \
+ MATECONF_VALUE_STRING, (list), NULL)
+
+#define xkb_options_set_selected_list(list) \
+ mateconf_client_set_list (mateconf_client_get_default (), \
+ MATEKBD_KEYBOARD_CONFIG_KEY_OPTIONS, \
+ MATECONF_VALUE_STRING, (list), NULL)
+
+extern GtkWidget *xkb_layout_preview_create_widget (GtkBuilder *
+ chooser_dialog);
+
+extern void xkb_layout_preview_update (GtkBuilder * chooser_dialog);
+
+extern void xkb_layout_preview_set_drawing_layout (GtkWidget * kbdraw,
+ const gchar * id);
+
+extern gchar *xkb_layout_chooser_get_selected_id (GtkBuilder *
+ chooser_dialog);
+
+extern void xkb_save_default_group (gint group_no);
+
+extern gint xkb_get_default_group (void);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __MATE_KEYBOARD_PROPERTY_XKB_H */
diff --git a/capplets/keyboard/mate-keyboard-properties-xkblt.c b/capplets/keyboard/mate-keyboard-properties-xkblt.c
new file mode 100644
index 00000000..41132647
--- /dev/null
+++ b/capplets/keyboard/mate-keyboard-properties-xkblt.c
@@ -0,0 +1,475 @@
+/* -*- mode: c; style: linux -*- */
+
+/* mate-keyboard-properties-xkblt.c
+ * Copyright (C) 2003-2007 Sergey V. Udaltsov
+ *
+ * Written by: Sergey V. Udaltsov <[email protected]>
+ *
+ * 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, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <gdk/gdkx.h>
+#include <mateconf/mateconf-client.h>
+#include <glib/gi18n.h>
+
+#include <libmatekbd/matekbd-desktop-config.h>
+#include <libmatekbd/matekbd-keyboard-drawing.h>
+
+#include "capplet-util.h"
+#include "mate-keyboard-properties-xkb.h"
+
+
+#define SEL_LAYOUT_TREE_COL_DESCRIPTION 0
+#define SEL_LAYOUT_TREE_COL_ID 1
+#define SEL_LAYOUT_TREE_COL_ENABLED 2
+
+static int idx2select = -1;
+static int max_selected_layouts = -1;
+static int default_group = -1;
+
+static GtkCellRenderer *text_renderer;
+
+static gboolean disable_buttons_sensibility_update = FALSE;
+
+void
+clear_xkb_elements_list (GSList * list)
+{
+ while (list != NULL) {
+ GSList *p = list;
+ list = list->next;
+ g_free (p->data);
+ g_slist_free_1 (p);
+ }
+}
+
+static gint
+find_selected_layout_idx (GtkBuilder * dialog)
+{
+ GtkTreeSelection *selection =
+ gtk_tree_view_get_selection (GTK_TREE_VIEW
+ (WID ("xkb_layouts_selected")));
+ GtkTreeIter selected_iter;
+ GtkTreeModel *model;
+ GtkTreePath *path;
+ gint *indices;
+ gint rv;
+
+ if (!gtk_tree_selection_get_selected
+ (selection, &model, &selected_iter))
+ return -1;
+
+ path = gtk_tree_model_get_path (model, &selected_iter);
+ if (path == NULL)
+ return -1;
+
+ indices = gtk_tree_path_get_indices (path);
+ rv = indices[0];
+ gtk_tree_path_free (path);
+ return rv;
+}
+
+GSList *
+xkb_layouts_get_selected_list (void)
+{
+ GSList *retval;
+
+ retval = mateconf_client_get_list (xkb_mateconf_client,
+ MATEKBD_KEYBOARD_CONFIG_KEY_LAYOUTS,
+ MATECONF_VALUE_STRING, NULL);
+ if (retval == NULL) {
+ GSList *cur_layout;
+
+ for (cur_layout = initial_config.layouts_variants;
+ cur_layout != NULL; cur_layout = cur_layout->next)
+ retval =
+ g_slist_prepend (retval,
+ g_strdup (cur_layout->data));
+
+ retval = g_slist_reverse (retval);
+ }
+
+ return retval;
+}
+
+gint
+xkb_get_default_group ()
+{
+ return mateconf_client_get_int (xkb_mateconf_client,
+ MATEKBD_DESKTOP_CONFIG_KEY_DEFAULT_GROUP,
+ NULL);
+}
+
+void
+xkb_save_default_group (gint default_group)
+{
+ if (default_group != xkb_get_default_group ())
+ mateconf_client_set_int (xkb_mateconf_client,
+ MATEKBD_DESKTOP_CONFIG_KEY_DEFAULT_GROUP,
+ default_group, NULL);
+}
+
+static void
+xkb_layouts_enable_disable_buttons (GtkBuilder * dialog)
+{
+ GtkWidget *add_layout_btn = WID ("xkb_layouts_add");
+ GtkWidget *show_layout_btn = WID ("xkb_layouts_show");
+ GtkWidget *del_layout_btn = WID ("xkb_layouts_remove");
+ GtkWidget *selected_layouts_tree = WID ("xkb_layouts_selected");
+ GtkWidget *move_up_layout_btn = WID ("xkb_layouts_move_up");
+ GtkWidget *move_down_layout_btn = WID ("xkb_layouts_move_down");
+
+ GtkTreeSelection *s_selection =
+ gtk_tree_view_get_selection (GTK_TREE_VIEW
+ (selected_layouts_tree));
+ const int n_selected_selected_layouts =
+ gtk_tree_selection_count_selected_rows (s_selection);
+ GtkTreeModel *selected_layouts_model = gtk_tree_view_get_model
+ (GTK_TREE_VIEW (selected_layouts_tree));
+ const int n_selected_layouts =
+ gtk_tree_model_iter_n_children (selected_layouts_model,
+ NULL);
+ gint sidx = find_selected_layout_idx (dialog);
+
+ if (disable_buttons_sensibility_update)
+ return;
+
+ gtk_widget_set_sensitive (add_layout_btn,
+ (n_selected_layouts <
+ max_selected_layouts
+ || max_selected_layouts == 0));
+ gtk_widget_set_sensitive (del_layout_btn, (n_selected_layouts > 1)
+ && (n_selected_selected_layouts > 0));
+ gtk_widget_set_sensitive (show_layout_btn,
+ (n_selected_selected_layouts > 0));
+ gtk_widget_set_sensitive (move_up_layout_btn, sidx > 0);
+ gtk_widget_set_sensitive (move_down_layout_btn, sidx >= 0
+ && sidx < (n_selected_layouts - 1));
+}
+
+static void
+xkb_layouts_dnd_data_get (GtkWidget * widget, GdkDragContext * dc,
+ GtkSelectionData * selection_data, guint info,
+ guint t, GtkBuilder * dialog)
+{
+ /* Storing the value into selection -
+ * while it is actually not used
+ */
+ gint idx = find_selected_layout_idx (dialog);
+ gtk_selection_data_set (selection_data,
+ GDK_SELECTION_TYPE_INTEGER, 32,
+ (guchar *) & idx, sizeof (idx));
+}
+
+static void
+xkb_layouts_dnd_data_received (GtkWidget * widget, GdkDragContext * dc,
+ gint x, gint y,
+ GtkSelectionData * selection_data,
+ guint info, guint t, GtkBuilder * dialog)
+{
+ gint sidx = find_selected_layout_idx (dialog);
+ GtkWidget *tree_view = WID ("xkb_layouts_selected");
+ GtkTreePath *path = NULL;
+ GtkTreeViewDropPosition pos;
+ gint didx;
+ gchar *id;
+ GSList *layouts_list;
+ GSList *node2Remove;
+
+ if (sidx == -1)
+ return;
+
+ layouts_list = xkb_layouts_get_selected_list ();
+ node2Remove = g_slist_nth (layouts_list, sidx);
+
+ id = (gchar *) node2Remove->data;
+ layouts_list = g_slist_delete_link (layouts_list, node2Remove);
+
+ if (!gtk_tree_view_get_dest_row_at_pos
+ (GTK_TREE_VIEW (tree_view), x, y, &path, &pos)) {
+ /* Move to the very end */
+ layouts_list =
+ g_slist_append (layouts_list, g_strdup (id));
+ xkb_layouts_set_selected_list (layouts_list);
+ } else if (path != NULL) {
+ gint *indices = gtk_tree_path_get_indices (path);
+ didx = indices[0];
+ gtk_tree_path_free (path);
+ /* Move to the new position */
+ if (sidx != didx) {
+ layouts_list =
+ g_slist_insert (layouts_list, g_strdup (id),
+ didx);
+ xkb_layouts_set_selected_list (layouts_list);
+ }
+ }
+ g_free (id);
+ clear_xkb_elements_list (layouts_list);
+}
+
+void
+xkb_layouts_prepare_selected_tree (GtkBuilder * dialog,
+ MateConfChangeSet * changeset)
+{
+ GtkListStore *list_store =
+ gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING,
+ G_TYPE_BOOLEAN);
+ GtkWidget *tree_view = WID ("xkb_layouts_selected");
+ GtkTreeSelection *selection;
+ GtkTargetEntry self_drag_target =
+ { "xkb_layouts_selected", GTK_TARGET_SAME_WIDGET, 0 };
+ GtkTreeViewColumn *desc_column;
+
+ text_renderer = GTK_CELL_RENDERER (gtk_cell_renderer_text_new ());
+
+ desc_column =
+ gtk_tree_view_column_new_with_attributes (_("Layout"),
+ text_renderer,
+ "text",
+ SEL_LAYOUT_TREE_COL_DESCRIPTION,
+ "sensitive",
+ SEL_LAYOUT_TREE_COL_ENABLED,
+ NULL);
+ selection =
+ gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
+
+ gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view),
+ GTK_TREE_MODEL (list_store));
+
+ gtk_tree_view_column_set_sizing (desc_column,
+ GTK_TREE_VIEW_COLUMN_AUTOSIZE);
+ gtk_tree_view_column_set_resizable (desc_column, TRUE);
+ gtk_tree_view_column_set_expand (desc_column, TRUE);
+
+ gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view),
+ desc_column);
+
+ g_signal_connect_swapped (G_OBJECT (selection), "changed",
+ G_CALLBACK
+ (xkb_layouts_enable_disable_buttons),
+ dialog);
+ max_selected_layouts = xkl_engine_get_max_num_groups (engine);
+
+ /* Setting up DnD */
+ gtk_drag_source_set (tree_view, GDK_BUTTON1_MASK,
+ &self_drag_target, 1, GDK_ACTION_MOVE);
+ gtk_drag_source_set_icon_name (tree_view, "input-keyboard");
+ gtk_drag_dest_set (tree_view, GTK_DEST_DEFAULT_ALL,
+ &self_drag_target, 1, GDK_ACTION_MOVE);
+
+ g_signal_connect (G_OBJECT (tree_view), "drag_data_get",
+ G_CALLBACK (xkb_layouts_dnd_data_get), dialog);
+ g_signal_connect (G_OBJECT (tree_view), "drag_data_received",
+ G_CALLBACK (xkb_layouts_dnd_data_received),
+ dialog);
+}
+
+gchar *
+xkb_layout_description_utf8 (const gchar * visible)
+{
+ char *l, *sl, *v, *sv;
+ if (matekbd_keyboard_config_get_descriptions
+ (config_registry, visible, &sl, &l, &sv, &v))
+ visible = matekbd_keyboard_config_format_full_layout (l, v);
+ return g_strstrip (g_strdup (visible));
+}
+
+void
+xkb_layouts_fill_selected_tree (GtkBuilder * dialog)
+{
+ GSList *layouts = xkb_layouts_get_selected_list ();
+ GSList *cur_layout;
+ GtkListStore *list_store =
+ GTK_LIST_STORE (gtk_tree_view_get_model
+ (GTK_TREE_VIEW
+ (WID ("xkb_layouts_selected"))));
+ int counter = 0;
+
+ /* temporarily disable the buttons' status update */
+ disable_buttons_sensibility_update = TRUE;
+
+ gtk_list_store_clear (list_store);
+
+ for (cur_layout = layouts; cur_layout != NULL;
+ cur_layout = cur_layout->next, counter++) {
+ GtkTreeIter iter;
+ const char *visible = (char *) cur_layout->data;
+ gchar *utf_visible = xkb_layout_description_utf8 (visible);
+ gtk_list_store_append (list_store, &iter);
+ gtk_list_store_set (list_store, &iter,
+ SEL_LAYOUT_TREE_COL_DESCRIPTION,
+ utf_visible,
+ SEL_LAYOUT_TREE_COL_ID,
+ cur_layout->data,
+ SEL_LAYOUT_TREE_COL_ENABLED,
+ counter < max_selected_layouts, -1);
+ g_free (utf_visible);
+ }
+
+ clear_xkb_elements_list (layouts);
+
+ /* enable the buttons' status update */
+ disable_buttons_sensibility_update = FALSE;
+
+ if (idx2select != -1) {
+ GtkTreeSelection *selection =
+ gtk_tree_view_get_selection ((GTK_TREE_VIEW
+ (WID
+ ("xkb_layouts_selected"))));
+ GtkTreePath *path =
+ gtk_tree_path_new_from_indices (idx2select, -1);
+ gtk_tree_selection_select_path (selection, path);
+ gtk_tree_path_free (path);
+ idx2select = -1;
+ } else {
+ /* if there is nothing to select - just enable/disable the buttons,
+ otherwise it would be done by the selection change */
+ xkb_layouts_enable_disable_buttons (dialog);
+ }
+}
+
+static void
+add_selected_layout (GtkWidget * button, GtkBuilder * dialog)
+{
+ xkb_layout_choose (dialog);
+}
+
+static void
+show_selected_layout (GtkWidget * button, GtkBuilder * dialog)
+{
+ gint idx = find_selected_layout_idx (dialog);
+
+ if (idx != -1) {
+ GSList *layouts_list = xkb_layouts_get_selected_list ();
+ const gchar *id = g_slist_nth_data (layouts_list, idx);
+ char *descr = xkb_layout_description_utf8 (id);
+ GtkWidget *parent = WID ("keyboard_dialog");
+ GtkWidget *popup = matekbd_keyboard_drawing_new_dialog (idx, descr);
+ gtk_widget_set_parent (popup, parent);
+ clear_xkb_elements_list (layouts_list);
+ g_free (descr);
+ }
+}
+
+static void
+remove_selected_layout (GtkWidget * button, GtkBuilder * dialog)
+{
+ gint idx = find_selected_layout_idx (dialog);
+
+ if (idx != -1) {
+ GSList *layouts_list = xkb_layouts_get_selected_list ();
+ char *id = NULL;
+ GSList *node2Remove = g_slist_nth (layouts_list, idx);
+
+ layouts_list =
+ g_slist_remove_link (layouts_list, node2Remove);
+
+ id = (char *) node2Remove->data;
+ g_slist_free_1 (node2Remove);
+ g_free (id);
+
+ if (default_group > idx)
+ xkb_save_default_group (default_group - 1);
+ else if (default_group == idx)
+ xkb_save_default_group (-1);
+
+ xkb_layouts_set_selected_list (layouts_list);
+ clear_xkb_elements_list (layouts_list);
+ }
+}
+
+static void
+move_up_selected_layout (GtkWidget * button, GtkBuilder * dialog)
+{
+ gint idx = find_selected_layout_idx (dialog);
+
+ if (idx != -1) {
+ GSList *layouts_list = xkb_layouts_get_selected_list ();
+ GSList *node2Remove = g_slist_nth (layouts_list, idx);
+
+ layouts_list =
+ g_slist_remove_link (layouts_list, node2Remove);
+ layouts_list =
+ g_slist_insert (layouts_list, node2Remove->data,
+ idx - 1);
+ g_slist_free_1 (node2Remove);
+
+ idx2select = idx - 1;
+ xkb_layouts_set_selected_list (layouts_list);
+ clear_xkb_elements_list (layouts_list);
+ }
+}
+
+static void
+move_down_selected_layout (GtkWidget * button, GtkBuilder * dialog)
+{
+ gint idx = find_selected_layout_idx (dialog);
+
+ if (idx != -1) {
+ GSList *layouts_list = xkb_layouts_get_selected_list ();
+ GSList *node2Remove = g_slist_nth (layouts_list, idx);
+
+ layouts_list =
+ g_slist_remove_link (layouts_list, node2Remove);
+ layouts_list =
+ g_slist_insert (layouts_list, node2Remove->data,
+ idx + 1);
+ g_slist_free_1 (node2Remove);
+
+ idx2select = idx + 1;
+ xkb_layouts_set_selected_list (layouts_list);
+ clear_xkb_elements_list (layouts_list);
+ }
+}
+
+void
+xkb_layouts_register_buttons_handlers (GtkBuilder * dialog)
+{
+ g_signal_connect (G_OBJECT (WID ("xkb_layouts_add")), "clicked",
+ G_CALLBACK (add_selected_layout), dialog);
+ g_signal_connect (G_OBJECT (WID ("xkb_layouts_show")), "clicked",
+ G_CALLBACK (show_selected_layout), dialog);
+ g_signal_connect (G_OBJECT (WID ("xkb_layouts_remove")), "clicked",
+ G_CALLBACK (remove_selected_layout), dialog);
+ g_signal_connect (G_OBJECT (WID ("xkb_layouts_move_up")),
+ "clicked", G_CALLBACK (move_up_selected_layout),
+ dialog);
+ g_signal_connect (G_OBJECT (WID ("xkb_layouts_move_down")),
+ "clicked",
+ G_CALLBACK (move_down_selected_layout), dialog);
+}
+
+static void
+xkb_layouts_update_list (MateConfClient * client,
+ guint cnxn_id, MateConfEntry * entry,
+ GtkBuilder * dialog)
+{
+ xkb_layouts_fill_selected_tree (dialog);
+ enable_disable_restoring (dialog);
+}
+
+void
+xkb_layouts_register_mateconf_listener (GtkBuilder * dialog)
+{
+ mateconf_client_notify_add (xkb_mateconf_client,
+ MATEKBD_KEYBOARD_CONFIG_KEY_LAYOUTS,
+ (MateConfClientNotifyFunc)
+ xkb_layouts_update_list, dialog, NULL,
+ NULL);
+}
diff --git a/capplets/keyboard/mate-keyboard-properties-xkbltadd.c b/capplets/keyboard/mate-keyboard-properties-xkbltadd.c
new file mode 100644
index 00000000..e73e59cc
--- /dev/null
+++ b/capplets/keyboard/mate-keyboard-properties-xkbltadd.c
@@ -0,0 +1,561 @@
+/* -*- mode: c; style: linux -*- */
+
+/* mate-keyboard-properties-xkbltadd.c
+ * Copyright (C) 2007 Sergey V. Udaltsov
+ *
+ * Written by: Sergey V. Udaltsov <[email protected]>
+ *
+ * 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, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+
+#include <libmatekbd/matekbd-keyboard-drawing.h>
+#include <libmatekbd/matekbd-util.h>
+
+#include "capplet-util.h"
+#include "mate-keyboard-properties-xkb.h"
+
+enum {
+ COMBO_BOX_MODEL_COL_SORT,
+ COMBO_BOX_MODEL_COL_VISIBLE,
+ COMBO_BOX_MODEL_COL_XKB_ID,
+ COMBO_BOX_MODEL_COL_REAL_ID
+};
+
+typedef void (*LayoutIterFunc) (XklConfigRegistry * config,
+ ConfigItemProcessFunc func, gpointer data);
+
+typedef struct {
+ GtkListStore *list_store;
+ const gchar *lang_id;
+} AddVariantData;
+
+static void
+
+
+
+
+
+
+
+
+
+xkb_layout_chooser_available_layouts_fill (GtkBuilder * chooser_dialog,
+ const gchar cblid[],
+ const gchar cbvid[],
+ LayoutIterFunc layout_iterator,
+ ConfigItemProcessFunc
+ layout_handler,
+ GCallback combo_changed_notify);
+
+static void
+
+
+
+
+
+
+
+
+
+xkb_layout_chooser_available_language_variants_fill (GtkBuilder *
+ chooser_dialog);
+
+static void
+
+
+
+
+
+
+
+
+
+xkb_layout_chooser_available_country_variants_fill (GtkBuilder *
+ chooser_dialog);
+
+static void
+ xkb_layout_chooser_add_variant_to_available_country_variants
+ (XklConfigRegistry * config_registry,
+ XklConfigItem * parent_config_item, XklConfigItem * config_item,
+ AddVariantData * data) {
+ gchar *utf_variant_name = config_item ?
+ xkb_layout_description_utf8 (matekbd_keyboard_config_merge_items
+ (parent_config_item->name,
+ config_item->name)) :
+ xci_desc_to_utf8 (parent_config_item);
+ GtkTreeIter iter;
+ const gchar *xkb_id =
+ config_item ?
+ matekbd_keyboard_config_merge_items (parent_config_item->name,
+ config_item->name) :
+ parent_config_item->name;
+
+ if (config_item && g_object_get_data
+ (G_OBJECT (config_item), XCI_PROP_EXTRA_ITEM)) {
+ gchar *buf =
+ g_strdup_printf ("<i>%s</i>", utf_variant_name);
+ gtk_list_store_insert_with_values (data->list_store, &iter,
+ -1,
+ COMBO_BOX_MODEL_COL_SORT,
+ utf_variant_name,
+ COMBO_BOX_MODEL_COL_VISIBLE,
+ buf,
+ COMBO_BOX_MODEL_COL_XKB_ID,
+ xkb_id, -1);
+ g_free (buf);
+ } else
+ gtk_list_store_insert_with_values (data->list_store, &iter,
+ -1,
+ COMBO_BOX_MODEL_COL_SORT,
+ utf_variant_name,
+ COMBO_BOX_MODEL_COL_VISIBLE,
+ utf_variant_name,
+ COMBO_BOX_MODEL_COL_XKB_ID,
+ xkb_id, -1);
+ g_free (utf_variant_name);
+}
+
+static void
+ xkb_layout_chooser_add_variant_to_available_language_variants
+ (XklConfigRegistry * config_registry,
+ XklConfigItem * parent_config_item, XklConfigItem * config_item,
+ AddVariantData * data) {
+ xkb_layout_chooser_add_variant_to_available_country_variants
+ (config_registry, parent_config_item, config_item, data);
+}
+
+static void
+xkb_layout_chooser_add_language_to_available_languages (XklConfigRegistry *
+ config_registry,
+ XklConfigItem *
+ config_item,
+ GtkListStore *
+ list_store)
+{
+ gtk_list_store_insert_with_values (list_store, NULL, -1,
+ COMBO_BOX_MODEL_COL_SORT,
+ config_item->description,
+ COMBO_BOX_MODEL_COL_VISIBLE,
+ config_item->description,
+ COMBO_BOX_MODEL_COL_REAL_ID,
+ config_item->name, -1);
+}
+
+static void
+xkb_layout_chooser_add_country_to_available_countries (XklConfigRegistry *
+ config_registry,
+ XklConfigItem *
+ config_item,
+ GtkListStore *
+ list_store)
+{
+ gtk_list_store_insert_with_values (list_store, NULL, -1,
+ COMBO_BOX_MODEL_COL_SORT,
+ config_item->description,
+ COMBO_BOX_MODEL_COL_VISIBLE,
+ config_item->description,
+ COMBO_BOX_MODEL_COL_REAL_ID,
+ config_item->name, -1);
+}
+
+static void
+xkb_layout_chooser_enable_disable_buttons (GtkBuilder * chooser_dialog)
+{
+ GtkWidget *cbv =
+ CWID (gtk_notebook_get_current_page
+ (GTK_NOTEBOOK (CWID ("choosers_nb"))) ?
+ "xkb_language_variants_available" :
+ "xkb_country_variants_available");
+ GtkTreeIter viter;
+ gboolean enable_ok =
+ gtk_combo_box_get_active_iter (GTK_COMBO_BOX (cbv),
+ &viter);
+
+ gtk_dialog_set_response_sensitive (GTK_DIALOG
+ (CWID
+ ("xkb_layout_chooser")),
+ GTK_RESPONSE_OK, enable_ok);
+ gtk_widget_set_sensitive (CWID ("btnPrint"), enable_ok);
+}
+
+static void
+xkb_layout_chooser_available_variant_changed (GtkBuilder * chooser_dialog)
+{
+ xkb_layout_preview_update (chooser_dialog);
+ xkb_layout_chooser_enable_disable_buttons (chooser_dialog);
+}
+
+static void
+xkb_layout_chooser_available_language_changed (GtkBuilder * chooser_dialog)
+{
+ xkb_layout_chooser_available_language_variants_fill
+ (chooser_dialog);
+ xkb_layout_chooser_available_variant_changed (chooser_dialog);
+}
+
+static void
+xkb_layout_chooser_available_country_changed (GtkBuilder * chooser_dialog)
+{
+ xkb_layout_chooser_available_country_variants_fill
+ (chooser_dialog);
+ xkb_layout_chooser_available_variant_changed (chooser_dialog);
+}
+
+static void
+xkb_layout_chooser_page_changed (GtkWidget * notebook, GtkWidget * page,
+ gint page_num,
+ GtkBuilder * chooser_dialog)
+{
+ xkb_layout_chooser_available_variant_changed (chooser_dialog);
+}
+
+static void
+xkb_layout_chooser_available_language_variants_fill (GtkBuilder *
+ chooser_dialog)
+{
+ GtkWidget *cbl = CWID ("xkb_languages_available");
+ GtkWidget *cbv = CWID ("xkb_language_variants_available");
+ GtkListStore *list_store;
+ GtkTreeIter liter;
+
+ list_store = gtk_list_store_new
+ (4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
+ G_TYPE_STRING);
+
+ if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (cbl), &liter)) {
+ GtkTreeModel *lm =
+ gtk_combo_box_get_model (GTK_COMBO_BOX (cbl));
+ gchar *lang_id;
+ AddVariantData data = { list_store, 0 };
+
+ /* Now the variants of the selected layout */
+ gtk_tree_model_get (lm, &liter,
+ COMBO_BOX_MODEL_COL_REAL_ID,
+ &lang_id, -1);
+ data.lang_id = lang_id;
+
+ xkl_config_registry_foreach_language_variant
+ (config_registry, lang_id, (TwoConfigItemsProcessFunc)
+ xkb_layout_chooser_add_variant_to_available_language_variants,
+ &data);
+ g_free (lang_id);
+ }
+
+ /* Turn on sorting after filling the store, since that's faster */
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE
+ (list_store),
+ COMBO_BOX_MODEL_COL_SORT,
+ GTK_SORT_ASCENDING);
+
+ gtk_combo_box_set_model (GTK_COMBO_BOX (cbv),
+ GTK_TREE_MODEL (list_store));
+ gtk_combo_box_set_active (GTK_COMBO_BOX (cbv), 0);
+}
+
+static void
+xkb_layout_chooser_available_country_variants_fill (GtkBuilder *
+ chooser_dialog)
+{
+ GtkWidget *cbl = CWID ("xkb_countries_available");
+ GtkWidget *cbv = CWID ("xkb_country_variants_available");
+ GtkListStore *list_store;
+ GtkTreeIter liter;
+
+ list_store = gtk_list_store_new
+ (4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
+ G_TYPE_STRING);
+
+ if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (cbl), &liter)) {
+ GtkTreeModel *lm =
+ gtk_combo_box_get_model (GTK_COMBO_BOX (cbl));
+ gchar *country_id;
+ AddVariantData data = { list_store, 0 };
+
+ /* Now the variants of the selected layout */
+ gtk_tree_model_get (lm, &liter,
+ COMBO_BOX_MODEL_COL_REAL_ID,
+ &country_id, -1);
+ xkl_config_registry_foreach_country_variant
+ (config_registry, country_id,
+ (TwoConfigItemsProcessFunc)
+ xkb_layout_chooser_add_variant_to_available_country_variants,
+ &data);
+ g_free (country_id);
+ }
+
+ /* Turn on sorting after filling the store, since that's faster */
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE
+ (list_store),
+ COMBO_BOX_MODEL_COL_SORT,
+ GTK_SORT_ASCENDING);
+
+ gtk_combo_box_set_model (GTK_COMBO_BOX (cbv),
+ GTK_TREE_MODEL (list_store));
+ gtk_combo_box_set_active (GTK_COMBO_BOX (cbv), 0);
+}
+
+static void
+xkb_layout_chooser_available_layouts_fill (GtkBuilder *
+ chooser_dialog,
+ const gchar cblid[],
+ const gchar cbvid[],
+ LayoutIterFunc layout_iterator,
+ ConfigItemProcessFunc
+ layout_handler,
+ GCallback combo_changed_notify)
+{
+ GtkWidget *cbl = CWID (cblid);
+ GtkWidget *cbev = CWID (cbvid);
+ GtkCellRenderer *renderer;
+ GtkListStore *list_store;
+
+ list_store = gtk_list_store_new
+ (4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
+ G_TYPE_STRING);
+
+ gtk_combo_box_set_model (GTK_COMBO_BOX (cbl),
+ GTK_TREE_MODEL (list_store));
+
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (cbl), renderer, TRUE);
+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (cbl),
+ renderer, "markup",
+ COMBO_BOX_MODEL_COL_VISIBLE, NULL);
+
+ layout_iterator (config_registry, layout_handler, list_store);
+
+ /* Turn on sorting after filling the model since that's faster */
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE
+ (list_store),
+ COMBO_BOX_MODEL_COL_SORT,
+ GTK_SORT_ASCENDING);
+
+ g_signal_connect_swapped (G_OBJECT (cbl), "changed",
+ combo_changed_notify, chooser_dialog);
+
+ /* Setup the variants combo */
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (cbev),
+ renderer, TRUE);
+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (cbev),
+ renderer, "markup",
+ COMBO_BOX_MODEL_COL_VISIBLE, NULL);
+
+ g_signal_connect_swapped (G_OBJECT (cbev), "changed",
+ G_CALLBACK
+ (xkb_layout_chooser_available_variant_changed),
+ chooser_dialog);
+}
+
+void
+xkl_layout_chooser_add_default_switcher_if_necessary (GSList *
+ layouts_list)
+{
+ GSList *options_list = xkb_options_get_selected_list ();
+ gboolean was_appended;
+
+ options_list =
+ matekbd_keyboard_config_add_default_switch_option_if_necessary
+ (layouts_list, options_list, &was_appended);
+ if (was_appended)
+ xkb_options_set_selected_list (options_list);
+ clear_xkb_elements_list (options_list);
+}
+
+static void
+xkb_layout_chooser_print (GtkBuilder * chooser_dialog)
+{
+ GtkWidget *chooser = CWID ("xkb_layout_chooser");
+ GtkWidget *kbdraw =
+ GTK_WIDGET (g_object_get_data (G_OBJECT (chooser), "kbdraw"));
+ const char *id =
+ xkb_layout_chooser_get_selected_id (chooser_dialog);
+ char *descr = xkb_layout_description_utf8 (id);
+ matekbd_keyboard_drawing_print (MATEKBD_KEYBOARD_DRAWING
+ (kbdraw),
+ GTK_WINDOW (CWID
+ ("xkb_layout_chooser")),
+ descr);
+ g_free (descr);
+}
+
+static void
+xkb_layout_chooser_response (GtkDialog * dialog,
+ gint response, GtkBuilder * chooser_dialog)
+{
+ GdkRectangle rect;
+
+ if (response == GTK_RESPONSE_OK) {
+ gchar *selected_id = (gchar *)
+ xkb_layout_chooser_get_selected_id (chooser_dialog);
+
+ if (selected_id != NULL) {
+ GSList *layouts_list =
+ xkb_layouts_get_selected_list ();
+
+ selected_id = g_strdup (selected_id);
+
+ layouts_list =
+ g_slist_append (layouts_list, selected_id);
+ xkb_layouts_set_selected_list (layouts_list);
+
+ xkl_layout_chooser_add_default_switcher_if_necessary
+ (layouts_list);
+
+ clear_xkb_elements_list (layouts_list);
+ }
+ } else if (response == gtk_dialog_get_response_for_widget
+ (dialog, CWID ("btnPrint"))) {
+ xkb_layout_chooser_print (chooser_dialog);
+ g_signal_stop_emission_by_name (dialog, "response");
+ return;
+ }
+
+ gtk_window_get_position (GTK_WINDOW (dialog), &rect.x, &rect.y);
+ gtk_window_get_size (GTK_WINDOW (dialog), &rect.width,
+ &rect.height);
+ matekbd_preview_save_position (&rect);
+}
+
+void
+xkb_layout_choose (GtkBuilder * dialog)
+{
+ GtkBuilder *chooser_dialog;
+
+ chooser_dialog = gtk_builder_new ();
+ gtk_builder_add_from_file (chooser_dialog, MATECC_UI_DIR
+ "/mate-keyboard-properties-layout-chooser.ui",
+ NULL);
+ GtkWidget *chooser = CWID ("xkb_layout_chooser");
+ GtkWidget *lang_chooser = CWID ("xkb_languages_available");
+ GtkWidget *notebook = CWID ("choosers_nb");
+ GtkWidget *kbdraw = NULL;
+ GtkWidget *toplevel = NULL;
+
+ gtk_window_set_transient_for (GTK_WINDOW (chooser),
+ GTK_WINDOW (WID
+ ("keyboard_dialog")));
+
+ xkb_layout_chooser_available_layouts_fill (chooser_dialog,
+ "xkb_countries_available",
+ "xkb_country_variants_available",
+ xkl_config_registry_foreach_country,
+ (ConfigItemProcessFunc)
+ xkb_layout_chooser_add_country_to_available_countries,
+ G_CALLBACK
+ (xkb_layout_chooser_available_country_changed));
+ xkb_layout_chooser_available_layouts_fill (chooser_dialog,
+ "xkb_languages_available",
+ "xkb_language_variants_available",
+ xkl_config_registry_foreach_language,
+ (ConfigItemProcessFunc)
+ xkb_layout_chooser_add_language_to_available_languages,
+ G_CALLBACK
+ (xkb_layout_chooser_available_language_changed));
+
+ g_signal_connect_after (G_OBJECT (notebook), "switch_page",
+ G_CALLBACK
+ (xkb_layout_chooser_page_changed),
+ chooser_dialog);
+
+ gtk_combo_box_set_active (GTK_COMBO_BOX
+ (CWID ("xkb_countries_available")),
+ FALSE);
+
+ if (gtk_tree_model_iter_n_children
+ (gtk_combo_box_get_model (GTK_COMBO_BOX (lang_chooser)),
+ NULL)) {
+ gtk_combo_box_set_active (GTK_COMBO_BOX
+ (CWID
+ ("xkb_languages_available")),
+ FALSE);
+ } else {
+ /* If language info is not available - remove the corresponding tab,
+ pretend there is no notebook at all */
+ gtk_notebook_remove_page (GTK_NOTEBOOK (notebook), 1);
+ gtk_notebook_set_show_tabs (GTK_NOTEBOOK (notebook),
+ FALSE);
+ gtk_notebook_set_show_border (GTK_NOTEBOOK (notebook),
+ FALSE);
+ }
+
+#ifdef HAVE_X11_EXTENSIONS_XKB_H
+ if (!strcmp (xkl_engine_get_backend_name (engine), "XKB")) {
+ kbdraw = xkb_layout_preview_create_widget (chooser_dialog);
+ g_object_set_data (G_OBJECT (chooser), "kbdraw", kbdraw);
+ gtk_container_add (GTK_CONTAINER
+ (CWID ("previewFrame")), kbdraw);
+ gtk_widget_show_all (kbdraw);
+ gtk_button_box_set_child_secondary (GTK_BUTTON_BOX
+ (CWID
+ ("hbtnBox")),
+ CWID
+ ("btnPrint"), TRUE);
+ } else
+#endif
+ {
+ gtk_widget_hide_all (CWID ("vboxPreview"));
+ gtk_widget_hide (CWID ("btnPrint"));
+ }
+
+ g_signal_connect (G_OBJECT (chooser),
+ "response",
+ G_CALLBACK (xkb_layout_chooser_response),
+ chooser_dialog);
+
+ toplevel = gtk_widget_get_toplevel (chooser);
+ if (gtk_widget_is_toplevel (toplevel)) {
+ GdkRectangle *rect = matekbd_preview_load_position ();
+ if (rect != NULL) {
+ gtk_window_move (GTK_WINDOW (toplevel),
+ rect->x, rect->y);
+ gtk_window_resize (GTK_WINDOW (toplevel),
+ rect->width, rect->height);
+ g_free (rect);
+ }
+ }
+
+ xkb_layout_preview_update (chooser_dialog);
+ gtk_dialog_run (GTK_DIALOG (chooser));
+ gtk_widget_destroy (chooser);
+}
+
+gchar *
+xkb_layout_chooser_get_selected_id (GtkBuilder * chooser_dialog)
+{
+ GtkWidget *cbv =
+ CWID (gtk_notebook_get_current_page
+ (GTK_NOTEBOOK (CWID ("choosers_nb"))) ?
+ "xkb_language_variants_available" :
+ "xkb_country_variants_available");
+ GtkTreeModel *vm = gtk_combo_box_get_model (GTK_COMBO_BOX (cbv));
+ GtkTreeIter viter;
+ gchar *v_id;
+
+ if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (cbv), &viter))
+ return NULL;
+
+ gtk_tree_model_get (vm, &viter,
+ COMBO_BOX_MODEL_COL_XKB_ID, &v_id, -1);
+
+ return v_id;
+}
diff --git a/capplets/keyboard/mate-keyboard-properties-xkbmc.c b/capplets/keyboard/mate-keyboard-properties-xkbmc.c
new file mode 100644
index 00000000..b09068d7
--- /dev/null
+++ b/capplets/keyboard/mate-keyboard-properties-xkbmc.c
@@ -0,0 +1,347 @@
+/* -*- mode: c; style: linux -*- */
+
+/* mate-keyboard-properties-xkbmc.c
+ * Copyright (C) 2003-2007 Sergey V. Udaltsov
+ *
+ * Written by: Sergey V. Udaltsov <[email protected]>
+ *
+ * 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, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <gdk/gdkx.h>
+#include <mateconf/mateconf-client.h>
+#include <glib/gi18n.h>
+
+#include "capplet-util.h"
+
+#include "mate-keyboard-properties-xkb.h"
+
+static gchar *current_model_name = NULL;
+static gchar *current_vendor_name = NULL;
+
+static void fill_models_list (GtkBuilder * chooser_dialog);
+
+static gboolean fill_vendors_list (GtkBuilder * chooser_dialog);
+
+static GtkTreePath *
+gtk_list_store_find_entry (GtkListStore * list_store,
+ GtkTreeIter * iter, gchar * name, int column_id)
+{
+ GtkTreePath *path;
+ char *current_name = NULL;
+ if (gtk_tree_model_get_iter_first
+ (GTK_TREE_MODEL (list_store), iter)) {
+ do {
+ gtk_tree_model_get (GTK_TREE_MODEL
+ (list_store), iter, column_id,
+ &current_name, -1);
+ if (!g_ascii_strcasecmp (name, current_name)) {
+ path =
+ gtk_tree_model_get_path
+ (GTK_TREE_MODEL (list_store), iter);
+ return path;
+ }
+ g_free (current_name);
+ } while (gtk_tree_model_iter_next
+ (GTK_TREE_MODEL (list_store), iter));
+ }
+ return NULL;
+}
+
+static void
+add_vendor_to_list (XklConfigRegistry * config_registry,
+ XklConfigItem * config_item,
+ GtkTreeView * vendors_list)
+{
+ GtkTreeIter iter;
+ GtkTreePath *found_existing;
+ GtkListStore *list_store;
+
+ gchar *vendor_name =
+ (gchar *) g_object_get_data (G_OBJECT (config_item),
+ XCI_PROP_VENDOR);
+
+ if (vendor_name == NULL)
+ return;
+
+ list_store =
+ GTK_LIST_STORE (gtk_tree_view_get_model (vendors_list));
+
+ if (!g_ascii_strcasecmp (config_item->name, current_model_name)) {
+ current_vendor_name = g_strdup (vendor_name);
+ }
+
+ found_existing =
+ gtk_list_store_find_entry (list_store, &iter, vendor_name, 0);
+ /* This vendor is already there */
+ if (found_existing != NULL) {
+ gtk_tree_path_free (found_existing);
+ return;
+ }
+
+ gtk_list_store_append (list_store, &iter);
+ gtk_list_store_set (list_store, &iter, 0, vendor_name, -1);
+}
+
+static void
+add_model_to_list (XklConfigRegistry * config_registry,
+ XklConfigItem * config_item, GtkTreeView * models_list)
+{
+ GtkTreeIter iter;
+ GtkListStore *list_store =
+ GTK_LIST_STORE (gtk_tree_view_get_model (models_list));
+ char *utf_model_name;
+ if (current_vendor_name != NULL) {
+ gchar *vendor_name =
+ (gchar *) g_object_get_data (G_OBJECT (config_item),
+ XCI_PROP_VENDOR);
+ if (vendor_name == NULL)
+ return;
+
+ if (g_ascii_strcasecmp (vendor_name, current_vendor_name))
+ return;
+ }
+ utf_model_name = xci_desc_to_utf8 (config_item);
+ gtk_list_store_append (list_store, &iter);
+ gtk_list_store_set (list_store, &iter,
+ 0, utf_model_name, 1, config_item->name, -1);
+
+ g_free (utf_model_name);
+}
+
+static void
+xkb_model_chooser_change_vendor_sel (GtkTreeSelection * selection,
+ GtkBuilder * chooser_dialog)
+{
+ GtkTreeIter iter;
+ GtkTreeModel *list_store = NULL;
+ if (gtk_tree_selection_get_selected
+ (selection, &list_store, &iter)) {
+ gchar *vendor_name = NULL;
+ gtk_tree_model_get (list_store, &iter,
+ 0, &vendor_name, -1);
+
+ current_vendor_name = vendor_name;
+ fill_models_list (chooser_dialog);
+ g_free (vendor_name);
+ } else {
+ current_vendor_name = NULL;
+ fill_models_list (chooser_dialog);
+ }
+
+}
+
+static void
+xkb_model_chooser_change_model_sel (GtkTreeSelection * selection,
+ GtkBuilder * chooser_dialog)
+{
+ gboolean anysel =
+ gtk_tree_selection_get_selected (selection, NULL, NULL);
+ gtk_dialog_set_response_sensitive (GTK_DIALOG
+ (CWID ("xkb_model_chooser")),
+ GTK_RESPONSE_OK, anysel);
+}
+
+static void
+prepare_vendors_list (GtkBuilder * chooser_dialog)
+{
+ GtkWidget *vendors_list = CWID ("vendors_list");
+ GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
+ GtkTreeViewColumn *vendor_col =
+ gtk_tree_view_column_new_with_attributes (_("Vendors"),
+ renderer,
+ "text", 0,
+ NULL);
+ gtk_tree_view_column_set_visible (vendor_col, TRUE);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (vendors_list),
+ vendor_col);
+}
+
+static gboolean
+fill_vendors_list (GtkBuilder * chooser_dialog)
+{
+ GtkWidget *vendors_list = CWID ("vendors_list");
+ GtkListStore *list_store = gtk_list_store_new (1, G_TYPE_STRING);
+ GtkTreeIter iter;
+ GtkTreePath *path;
+
+ gtk_tree_view_set_model (GTK_TREE_VIEW (vendors_list),
+ GTK_TREE_MODEL (list_store));
+
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE
+ (list_store), 0,
+ GTK_SORT_ASCENDING);
+
+ current_vendor_name = NULL;
+
+ xkl_config_registry_foreach_model (config_registry,
+ (ConfigItemProcessFunc)
+ add_vendor_to_list,
+ vendors_list);
+
+ if (current_vendor_name != NULL) {
+ path = gtk_list_store_find_entry (list_store,
+ &iter,
+ current_vendor_name, 0);
+ if (path != NULL) {
+ gtk_tree_selection_select_iter
+ (gtk_tree_view_get_selection
+ (GTK_TREE_VIEW (vendors_list)), &iter);
+ gtk_tree_view_scroll_to_cell
+ (GTK_TREE_VIEW (vendors_list),
+ path, NULL, TRUE, 0.5, 0);
+ gtk_tree_path_free (path);
+ }
+ fill_models_list (chooser_dialog);
+ g_free (current_vendor_name);
+ } else {
+ fill_models_list (chooser_dialog);
+ }
+
+ g_signal_connect (G_OBJECT
+ (gtk_tree_view_get_selection
+ (GTK_TREE_VIEW (vendors_list))), "changed",
+ G_CALLBACK (xkb_model_chooser_change_vendor_sel),
+ chooser_dialog);
+
+ return gtk_tree_model_get_iter_first (GTK_TREE_MODEL (list_store),
+ &iter);
+}
+
+static void
+prepare_models_list (GtkBuilder * chooser_dialog)
+{
+ GtkWidget *models_list = CWID ("models_list");
+ GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
+ GtkTreeViewColumn *description_col =
+ gtk_tree_view_column_new_with_attributes (_("Models"),
+ renderer,
+ "text", 0,
+ NULL);
+ gtk_tree_view_column_set_visible (description_col, TRUE);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (models_list),
+ description_col);
+}
+
+static void
+fill_models_list (GtkBuilder * chooser_dialog)
+{
+ GtkWidget *models_list = CWID ("models_list");
+ GtkTreeIter iter;
+ GtkTreePath *path;
+
+ GtkListStore *list_store =
+ gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
+
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE
+ (list_store), 0,
+ GTK_SORT_ASCENDING);
+
+ gtk_tree_view_set_model (GTK_TREE_VIEW (models_list),
+ GTK_TREE_MODEL (list_store));
+
+ xkl_config_registry_foreach_model (config_registry,
+ (ConfigItemProcessFunc)
+ add_model_to_list, models_list);
+
+ if (current_model_name != NULL) {
+ path = gtk_list_store_find_entry (list_store,
+ &iter,
+ current_model_name, 1);
+ if (path != NULL) {
+ gtk_tree_selection_select_iter
+ (gtk_tree_view_get_selection
+ (GTK_TREE_VIEW (models_list)), &iter);
+ gtk_tree_view_scroll_to_cell
+ (GTK_TREE_VIEW (models_list),
+ path, NULL, TRUE, 0.5, 0);
+ gtk_tree_path_free (path);
+ }
+ }
+
+ g_signal_connect (G_OBJECT
+ (gtk_tree_view_get_selection
+ (GTK_TREE_VIEW (models_list))), "changed",
+ G_CALLBACK (xkb_model_chooser_change_model_sel),
+ chooser_dialog);
+}
+
+static void
+xkb_model_chooser_response (GtkDialog * dialog,
+ gint response, GtkBuilder * chooser_dialog)
+{
+ if (response == GTK_RESPONSE_OK) {
+ GtkWidget *models_list = CWID ("models_list");
+ GtkTreeSelection *selection =
+ gtk_tree_view_get_selection (GTK_TREE_VIEW
+ (models_list));
+ GtkTreeIter iter;
+ GtkTreeModel *list_store = NULL;
+ if (gtk_tree_selection_get_selected
+ (selection, &list_store, &iter)) {
+ gchar *model_name = NULL;
+ gtk_tree_model_get (list_store, &iter,
+ 1, &model_name, -1);
+
+ mateconf_client_set_string (xkb_mateconf_client,
+ MATEKBD_KEYBOARD_CONFIG_KEY_MODEL,
+ model_name, NULL);
+ g_free (model_name);
+ }
+ }
+}
+
+void
+choose_model (GtkBuilder * dialog)
+{
+ GtkBuilder *chooser_dialog;
+ GtkWidget *chooser;
+
+ chooser_dialog = gtk_builder_new ();
+ gtk_builder_add_from_file (chooser_dialog, MATECC_UI_DIR
+ "/mate-keyboard-properties-model-chooser.ui",
+ NULL);
+ chooser = CWID ("xkb_model_chooser");
+ gtk_window_set_transient_for (GTK_WINDOW (chooser),
+ GTK_WINDOW (WID
+ ("keyboard_dialog")));
+ current_model_name =
+ mateconf_client_get_string (xkb_mateconf_client,
+ MATEKBD_KEYBOARD_CONFIG_KEY_MODEL, NULL);
+
+
+ prepare_vendors_list (chooser_dialog);
+ prepare_models_list (chooser_dialog);
+
+ if (!fill_vendors_list (chooser_dialog)) {
+ gtk_widget_hide_all (CWID ("vendors_label"));
+ gtk_widget_hide_all (CWID ("vendors_scrolledwindow"));
+ current_vendor_name = NULL;
+ fill_models_list (chooser_dialog);
+ }
+
+ g_signal_connect (G_OBJECT (chooser),
+ "response",
+ G_CALLBACK (xkb_model_chooser_response),
+ chooser_dialog);
+ gtk_dialog_run (GTK_DIALOG (chooser));
+ gtk_widget_destroy (chooser);
+ g_free (current_model_name);
+}
diff --git a/capplets/keyboard/mate-keyboard-properties-xkbot.c b/capplets/keyboard/mate-keyboard-properties-xkbot.c
new file mode 100644
index 00000000..1436d86a
--- /dev/null
+++ b/capplets/keyboard/mate-keyboard-properties-xkbot.c
@@ -0,0 +1,516 @@
+/* -*- mode: c; style: linux -*- */
+
+/* mate-keyboard-properties-xkbot.c
+ * Copyright (C) 2003-2007 Sergey V. Udaltsov
+ *
+ * Written by: Sergey V. Udaltsov <[email protected]>
+ * John Spray <[email protected]>
+ *
+ * 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, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <glib/gi18n.h>
+#include <string.h>
+#include <mateconf/mateconf-client.h>
+
+#include "capplet-util.h"
+
+#include "mate-keyboard-properties-xkb.h"
+
+static GtkBuilder *chooser_dialog = NULL;
+static const char *current1st_level_id = NULL;
+static GSList *option_checks_list = NULL;
+static GtkWidget *current_none_radio = NULL;
+static GtkWidget *current_expander = NULL;
+static gboolean current_multi_select = FALSE;
+static GSList *current_radio_group = NULL;
+
+#define OPTION_ID_PROP "optionID"
+#define SELCOUNTER_PROP "selectionCounter"
+#define MATECONFSTATE_PROP "mateconfState"
+#define EXPANDERS_PROP "expandersList"
+
+GSList *
+xkb_options_get_selected_list (void)
+{
+ GSList *retval;
+
+ retval = mateconf_client_get_list (xkb_mateconf_client,
+ MATEKBD_KEYBOARD_CONFIG_KEY_OPTIONS,
+ MATECONF_VALUE_STRING, NULL);
+ if (retval == NULL) {
+ GSList *cur_option;
+
+ for (cur_option = initial_config.options;
+ cur_option != NULL; cur_option = cur_option->next)
+ retval =
+ g_slist_prepend (retval,
+ g_strdup (cur_option->data));
+
+ retval = g_slist_reverse (retval);
+ }
+
+ return retval;
+}
+
+/* Returns the selection counter of the expander (static current_expander) */
+static int
+xkb_options_expander_selcounter_get (void)
+{
+ return
+ GPOINTER_TO_INT (g_object_get_data
+ (G_OBJECT (current_expander),
+ SELCOUNTER_PROP));
+}
+
+/* Increments the selection counter in the expander (static current_expander)
+ using the value (can be 0)*/
+static void
+xkb_options_expander_selcounter_add (int value)
+{
+ g_object_set_data (G_OBJECT (current_expander), SELCOUNTER_PROP,
+ GINT_TO_POINTER
+ (xkb_options_expander_selcounter_get ()
+ + value));
+}
+
+/* Resets the seletion counter in the expander (static current_expander) */
+static void
+xkb_options_expander_selcounter_reset (void)
+{
+ g_object_set_data (G_OBJECT (current_expander), SELCOUNTER_PROP,
+ GINT_TO_POINTER (0));
+}
+
+/* Formats the expander (static current_expander), based on the selection counter */
+static void
+xkb_options_expander_highlight (void)
+{
+ char *utf_group_name =
+ g_object_get_data (G_OBJECT (current_expander),
+ "utfGroupName");
+ int counter = xkb_options_expander_selcounter_get ();
+ if (utf_group_name != NULL) {
+ gchar *titlemarkup =
+ g_strconcat (counter >
+ 0 ? "<span weight=\"bold\">" : "<span>",
+ utf_group_name, "</span>", NULL);
+ gtk_expander_set_label (GTK_EXPANDER (current_expander),
+ titlemarkup);
+ g_free (titlemarkup);
+ }
+}
+
+/* Add optionname from the backend's selection list if it's not
+ already in there. */
+static void
+xkb_options_select (gchar * optionname)
+{
+ gboolean already_selected = FALSE;
+ GSList *options_list = xkb_options_get_selected_list ();
+ GSList *option;
+ for (option = options_list; option != NULL; option = option->next)
+ if (!strcmp ((gchar *) option->data, optionname))
+ already_selected = TRUE;
+
+ if (!already_selected)
+ options_list =
+ g_slist_append (options_list, g_strdup (optionname));
+ xkb_options_set_selected_list (options_list);
+
+ clear_xkb_elements_list (options_list);
+}
+
+/* Remove all occurences of optionname from the backend's selection list */
+static void
+xkb_options_deselect (gchar * optionname)
+{
+ GSList *options_list = xkb_options_get_selected_list ();
+ GSList *nodetmp;
+ GSList *option = options_list;
+ while (option != NULL) {
+ gchar *id = (char *) option->data;
+ if (!strcmp (id, optionname)) {
+ nodetmp = option->next;
+ g_free (id);
+ options_list =
+ g_slist_remove_link (options_list, option);
+ g_slist_free_1 (option);
+ option = nodetmp;
+ } else
+ option = option->next;
+ }
+ xkb_options_set_selected_list (options_list);
+ clear_xkb_elements_list (options_list);
+}
+
+/* Return true if optionname describes a string already in the backend's
+ list of selected options */
+static gboolean
+xkb_options_is_selected (gchar * optionname)
+{
+ gboolean retval = FALSE;
+ GSList *options_list = xkb_options_get_selected_list ();
+ GSList *option;
+ for (option = options_list; option != NULL; option = option->next) {
+ if (!strcmp ((gchar *) option->data, optionname))
+ retval = TRUE;
+ }
+ clear_xkb_elements_list (options_list);
+ return retval;
+}
+
+/* Make sure selected options stay visible when navigating with the keyboard */
+static gboolean
+option_focused_cb (GtkWidget * widget, GdkEventFocus * event,
+ gpointer data)
+{
+ GtkScrolledWindow *win = GTK_SCROLLED_WINDOW (data);
+ GtkAllocation alloc;
+ GtkAdjustment *adj;
+
+ gtk_widget_get_allocation (widget, &alloc);
+ adj = gtk_scrolled_window_get_vadjustment (win);
+ gtk_adjustment_clamp_page (adj, alloc.y,
+ alloc.y + alloc.height);
+
+ return FALSE;
+}
+
+/* Update xkb backend to reflect the new UI state */
+static void
+option_toggled_cb (GtkWidget * checkbutton, gpointer data)
+{
+ gpointer optionID =
+ g_object_get_data (G_OBJECT (checkbutton), OPTION_ID_PROP);
+ if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (checkbutton)))
+ xkb_options_select (optionID);
+ else
+ xkb_options_deselect (optionID);
+}
+
+/* Add a check_button or radio_button to control a particular option
+ This function makes particular use of the current... variables at
+ the top of this file. */
+static void
+xkb_options_add_option (XklConfigRegistry * config_registry,
+ XklConfigItem * config_item, GtkBuilder * dialog)
+{
+ GtkWidget *option_check;
+ gchar *utf_option_name = xci_desc_to_utf8 (config_item);
+ /* Copy this out because we'll load it into the widget with set_data */
+ gchar *full_option_name =
+ g_strdup (matekbd_keyboard_config_merge_items
+ (current1st_level_id, config_item->name));
+ gboolean initial_state;
+
+ if (current_multi_select)
+ option_check =
+ gtk_check_button_new_with_label (utf_option_name);
+ else {
+ if (current_radio_group == NULL) {
+ /* The first radio in a group is to be "Default", meaning none of
+ the below options are to be included in the selected list.
+ This is a HIG-compliant alternative to allowing no
+ selection in the group. */
+ option_check =
+ gtk_radio_button_new_with_label
+ (current_radio_group, _("Default"));
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON
+ (option_check),
+ TRUE);
+ /* Make option name underscore -
+ to enforce its first position in the list */
+ g_object_set_data_full (G_OBJECT (option_check),
+ "utfOptionName",
+ g_strdup (" "), g_free);
+ option_checks_list =
+ g_slist_append (option_checks_list,
+ option_check);
+ current_radio_group =
+ gtk_radio_button_get_group (GTK_RADIO_BUTTON
+ (option_check));
+ current_none_radio = option_check;
+
+ g_signal_connect (option_check, "focus-in-event",
+ G_CALLBACK (option_focused_cb),
+ WID ("options_scroll"));
+ }
+ option_check =
+ gtk_radio_button_new_with_label (current_radio_group,
+ utf_option_name);
+ current_radio_group =
+ gtk_radio_button_get_group (GTK_RADIO_BUTTON
+ (option_check));
+ g_object_set_data (G_OBJECT (option_check), "NoneRadio",
+ current_none_radio);
+ }
+
+ initial_state = xkb_options_is_selected (full_option_name);
+
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (option_check),
+ initial_state);
+
+ g_object_set_data_full (G_OBJECT (option_check), OPTION_ID_PROP,
+ full_option_name, g_free);
+ g_object_set_data_full (G_OBJECT (option_check), "utfOptionName",
+ utf_option_name, g_free);
+
+ g_signal_connect (option_check, "toggled",
+ G_CALLBACK (option_toggled_cb), NULL);
+
+ option_checks_list =
+ g_slist_append (option_checks_list, option_check);
+
+ g_signal_connect (option_check, "focus-in-event",
+ G_CALLBACK (option_focused_cb),
+ WID ("options_scroll"));
+
+ xkb_options_expander_selcounter_add (initial_state);
+ g_object_set_data (G_OBJECT (option_check), MATECONFSTATE_PROP,
+ GINT_TO_POINTER (initial_state));
+}
+
+static gint
+xkb_option_checks_compare (GtkWidget * chk1, GtkWidget * chk2)
+{
+ const gchar *t1 =
+ g_object_get_data (G_OBJECT (chk1), "utfOptionName");
+ const gchar *t2 =
+ g_object_get_data (G_OBJECT (chk2), "utfOptionName");
+ return g_utf8_collate (t1, t2);
+}
+
+/* Add a group of options: create title and layout widgets and then
+ add widgets for all the options in the group. */
+static void
+xkb_options_add_group (XklConfigRegistry * config_registry,
+ XklConfigItem * config_item, GtkBuilder * dialog)
+{
+ GtkWidget *align, *vbox, *option_check;
+ gboolean allow_multiple_selection =
+ GPOINTER_TO_INT (g_object_get_data (G_OBJECT (config_item),
+ XCI_PROP_ALLOW_MULTIPLE_SELECTION));
+
+ GSList *expanders_list =
+ g_object_get_data (G_OBJECT (dialog), EXPANDERS_PROP);
+
+ gchar *utf_group_name = xci_desc_to_utf8 (config_item);
+ gchar *titlemarkup =
+ g_strconcat ("<span>", utf_group_name, "</span>", NULL);
+
+ current_expander = gtk_expander_new (titlemarkup);
+ gtk_expander_set_use_markup (GTK_EXPANDER (current_expander),
+ TRUE);
+ g_object_set_data_full (G_OBJECT (current_expander),
+ "utfGroupName", utf_group_name, g_free);
+ g_object_set_data_full (G_OBJECT (current_expander), "groupId",
+ g_strdup (config_item->name), g_free);
+
+ g_free (titlemarkup);
+ align = gtk_alignment_new (0, 0, 1, 1);
+ gtk_alignment_set_padding (GTK_ALIGNMENT (align), 6, 12, 12, 0);
+ vbox = gtk_vbox_new (TRUE, 6);
+ gtk_container_add (GTK_CONTAINER (align), vbox);
+ gtk_container_add (GTK_CONTAINER (current_expander), align);
+
+ current_multi_select = (gboolean) allow_multiple_selection;
+ current_radio_group = NULL;
+ current1st_level_id = config_item->name;
+
+ option_checks_list = NULL;
+
+ xkl_config_registry_foreach_option (config_registry,
+ config_item->name,
+ (ConfigItemProcessFunc)
+ xkb_options_add_option,
+ dialog);
+ /* sort it */
+ option_checks_list =
+ g_slist_sort (option_checks_list,
+ (GCompareFunc) xkb_option_checks_compare);
+ while (option_checks_list) {
+ option_check = GTK_WIDGET (option_checks_list->data);
+ gtk_box_pack_start (GTK_BOX (vbox), option_check, TRUE, TRUE, 0);
+ option_checks_list = option_checks_list->next;
+ }
+ /* free it */
+ g_slist_free (option_checks_list);
+ option_checks_list = NULL;
+
+ xkb_options_expander_highlight ();
+
+ expanders_list = g_slist_append (expanders_list, current_expander);
+ g_object_set_data (G_OBJECT (dialog), EXPANDERS_PROP,
+ expanders_list);
+
+ g_signal_connect (current_expander, "focus-in-event",
+ G_CALLBACK (option_focused_cb),
+ WID ("options_scroll"));
+}
+
+static gint
+xkb_options_expanders_compare (GtkWidget * expander1,
+ GtkWidget * expander2)
+{
+ const gchar *t1 =
+ g_object_get_data (G_OBJECT (expander1), "utfGroupName");
+ const gchar *t2 =
+ g_object_get_data (G_OBJECT (expander2), "utfGroupName");
+ return g_utf8_collate (t1, t2);
+}
+
+/* Create widgets to represent the options made available by the backend */
+void
+xkb_options_load_options (GtkBuilder * dialog)
+{
+ GtkWidget *opts_vbox = WID ("options_vbox");
+ GSList *expanders_list;
+ GtkWidget *expander;
+
+ current1st_level_id = NULL;
+ current_none_radio = NULL;
+ current_multi_select = FALSE;
+ current_radio_group = NULL;
+
+ /* fill the list */
+ xkl_config_registry_foreach_option_group (config_registry,
+ (ConfigItemProcessFunc)
+ xkb_options_add_group,
+ dialog);
+ /* sort it */
+ expanders_list =
+ g_object_get_data (G_OBJECT (dialog), EXPANDERS_PROP);
+ expanders_list =
+ g_slist_sort (expanders_list,
+ (GCompareFunc) xkb_options_expanders_compare);
+ g_object_set_data (G_OBJECT (dialog), EXPANDERS_PROP,
+ expanders_list);
+ while (expanders_list) {
+ expander = GTK_WIDGET (expanders_list->data);
+ gtk_box_pack_start (GTK_BOX (opts_vbox), expander, FALSE,
+ FALSE, 0);
+ expanders_list = expanders_list->next;
+ }
+
+ gtk_widget_show_all (opts_vbox);
+}
+
+static void
+chooser_response_cb (GtkDialog * dialog, gint response, gpointer data)
+{
+ switch (response) {
+ case GTK_RESPONSE_HELP:
+ capplet_help (GTK_WINDOW (dialog),
+ "prefs-keyboard-layoutoptions");
+ break;
+ case GTK_RESPONSE_CLOSE:{
+ /* just cleanup */
+ GSList *expanders_list =
+ g_object_get_data (G_OBJECT (dialog),
+ EXPANDERS_PROP);
+ g_object_set_data (G_OBJECT (dialog),
+ EXPANDERS_PROP, NULL);
+ g_slist_free (expanders_list);
+
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+ chooser_dialog = NULL;
+ }
+ break;
+ }
+}
+
+/* Create popup dialog */
+void
+xkb_options_popup_dialog (GtkBuilder * dialog)
+{
+ GtkWidget *chooser;
+
+ chooser_dialog = gtk_builder_new ();
+ gtk_builder_add_from_file (chooser_dialog, MATECC_UI_DIR
+ "/mate-keyboard-properties-options-dialog.ui",
+ NULL);
+
+ chooser = CWID ("xkb_options_dialog");
+ gtk_window_set_transient_for (GTK_WINDOW (chooser),
+ GTK_WINDOW (WID
+ ("keyboard_dialog")));
+ xkb_options_load_options (chooser_dialog);
+
+ g_signal_connect (chooser, "response",
+ G_CALLBACK (chooser_response_cb), dialog);
+
+ gtk_dialog_run (GTK_DIALOG (chooser));
+}
+
+/* Update selected option counters for a group-bound expander */
+static void
+xkb_options_update_option_counters (XklConfigRegistry * config_registry,
+ XklConfigItem * config_item)
+{
+ gchar *full_option_name =
+ g_strdup (matekbd_keyboard_config_merge_items
+ (current1st_level_id, config_item->name));
+ gboolean current_state =
+ xkb_options_is_selected (full_option_name);
+ xkb_options_expander_selcounter_add (current_state);
+}
+
+/* Respond to a change in the xkb mateconf settings */
+static void
+xkb_options_update (MateConfClient * client,
+ guint cnxn_id, MateConfEntry * entry, GtkBuilder * dialog)
+{
+ /* Updating options is handled by mateconf notifies for each widget
+ This is here to avoid calling it N_OPTIONS times for each mateconf
+ change. */
+ enable_disable_restoring (dialog);
+
+ if (chooser_dialog != NULL) {
+ GSList *expanders_list =
+ g_object_get_data (G_OBJECT (chooser_dialog),
+ EXPANDERS_PROP);
+ while (expanders_list) {
+ current_expander =
+ GTK_WIDGET (expanders_list->data);
+ gchar *group_id =
+ g_object_get_data (G_OBJECT (current_expander),
+ "groupId");
+ current1st_level_id = group_id;
+ xkb_options_expander_selcounter_reset ();
+ xkl_config_registry_foreach_option
+ (config_registry, group_id,
+ (ConfigItemProcessFunc)
+ xkb_options_update_option_counters,
+ current_expander);
+ xkb_options_expander_highlight ();
+ expanders_list = expanders_list->next;
+ }
+ }
+}
+
+void
+xkb_options_register_mateconf_listener (GtkBuilder * dialog)
+{
+ mateconf_client_notify_add (xkb_mateconf_client,
+ MATEKBD_KEYBOARD_CONFIG_KEY_OPTIONS,
+ (MateConfClientNotifyFunc)
+ xkb_options_update, dialog, NULL, NULL);
+}
diff --git a/capplets/keyboard/mate-keyboard-properties-xkbpv.c b/capplets/keyboard/mate-keyboard-properties-xkbpv.c
new file mode 100644
index 00000000..6aec3070
--- /dev/null
+++ b/capplets/keyboard/mate-keyboard-properties-xkbpv.c
@@ -0,0 +1,136 @@
+/* -*- mode: c; style: linux -*- */
+
+/* mate-keyboard-properties-xkbpv.c
+ * Copyright (C) 2003-2007 Sergey V. Udaltsov
+ *
+ * Written by: Sergey V. Udaltsov <[email protected]>
+ *
+ * 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, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <libmatekbd/matekbd-keyboard-drawing.h>
+
+#include "capplet-util.h"
+#include "mate-keyboard-properties-xkb.h"
+
+#ifdef HAVE_X11_EXTENSIONS_XKB_H
+#include "X11/XKBlib.h"
+/**
+ * BAD STYLE: Taken from xklavier_private_xkb.h
+ * Any ideas on architectural improvements are WELCOME
+ */
+extern gboolean xkl_xkb_config_native_prepare (XklEngine * engine,
+ const XklConfigRec * data,
+ XkbComponentNamesPtr
+ component_names);
+
+extern void xkl_xkb_config_native_cleanup (XklEngine * engine,
+ XkbComponentNamesPtr
+ component_names);
+
+/* */
+#endif
+
+static MatekbdKeyboardDrawingGroupLevel groupsLevels[] =
+ { {0, 1}, {0, 3}, {0, 0}, {0, 2} };
+static MatekbdKeyboardDrawingGroupLevel *pGroupsLevels[] = {
+ groupsLevels, groupsLevels + 1, groupsLevels + 2, groupsLevels + 3
+};
+
+GtkWidget *
+xkb_layout_preview_create_widget (GtkBuilder * chooserDialog)
+{
+ GtkWidget *kbdraw = matekbd_keyboard_drawing_new ();
+
+ matekbd_keyboard_drawing_set_groups_levels (MATEKBD_KEYBOARD_DRAWING
+ (kbdraw), pGroupsLevels);
+ return kbdraw;
+}
+
+void
+xkb_layout_preview_update (GtkBuilder * chooser_dialog)
+{
+#ifdef HAVE_X11_EXTENSIONS_XKB_H
+ GtkWidget *chooser = CWID ("xkb_layout_chooser");
+ GtkWidget *kbdraw =
+ GTK_WIDGET (g_object_get_data (G_OBJECT (chooser), "kbdraw"));
+ gchar *id = xkb_layout_chooser_get_selected_id (chooser_dialog);
+ xkb_layout_preview_set_drawing_layout (kbdraw, id);
+ g_free (id);
+#endif
+}
+
+void
+xkb_layout_preview_set_drawing_layout (GtkWidget * kbdraw,
+ const gchar * id)
+{
+#ifdef HAVE_X11_EXTENSIONS_XKB_H
+ if (kbdraw != NULL) {
+ if (id != NULL) {
+ XklConfigRec *data;
+ char **p, *layout, *variant;
+ XkbComponentNamesRec component_names;
+
+ data = xkl_config_rec_new ();
+ if (xkl_config_rec_get_from_server (data, engine)) {
+ if ((p = data->layouts) != NULL)
+ g_strfreev (data->layouts);
+
+ if ((p = data->variants) != NULL)
+ g_strfreev (data->variants);
+
+ data->layouts = g_new0 (char *, 2);
+ data->variants = g_new0 (char *, 2);
+ if (matekbd_keyboard_config_split_items
+ (id, &layout, &variant)
+ && variant != NULL) {
+ data->layouts[0] =
+ (layout ==
+ NULL) ? NULL :
+ g_strdup (layout);
+ data->variants[0] =
+ (variant ==
+ NULL) ? NULL :
+ g_strdup (variant);
+ } else {
+ data->layouts[0] =
+ (id ==
+ NULL) ? NULL : g_strdup (id);
+ data->variants[0] = NULL;
+ }
+
+ if (xkl_xkb_config_native_prepare
+ (engine, data, &component_names)) {
+ matekbd_keyboard_drawing_set_keyboard
+ (MATEKBD_KEYBOARD_DRAWING
+ (kbdraw), &component_names);
+
+ xkl_xkb_config_native_cleanup
+ (engine, &component_names);
+ }
+ }
+ g_object_unref (G_OBJECT (data));
+ } else
+ matekbd_keyboard_drawing_set_keyboard
+ (MATEKBD_KEYBOARD_DRAWING (kbdraw), NULL);
+
+ }
+#endif
+}
diff --git a/capplets/keyboard/mate-keyboard-properties.c b/capplets/keyboard/mate-keyboard-properties.c
new file mode 100644
index 00000000..41c4558e
--- /dev/null
+++ b/capplets/keyboard/mate-keyboard-properties.c
@@ -0,0 +1,265 @@
+/* -*- mode: c; style: linux -*- */
+
+/* keyboard-properties.c
+ * Copyright (C) 2000-2001 Ximian, Inc.
+ * Copyright (C) 2001 Jonathan Blandford
+ *
+ * Written by: Bradford Hovinen <[email protected]>
+ * Rachel Hestilow <[email protected]>
+ * Jonathan Blandford <[email protected]>
+ *
+ * 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, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <mateconf/mateconf-client.h>
+
+#include "capplet-util.h"
+#include "mateconf-property-editor.h"
+#include "activate-settings-daemon.h"
+#include "capplet-stock-icons.h"
+
+#include "mate-keyboard-properties-a11y.h"
+#include "mate-keyboard-properties-xkb.h"
+
+enum {
+ RESPONSE_APPLY = 1,
+ RESPONSE_CLOSE
+};
+
+static GtkBuilder *
+create_dialog (void)
+{
+ GtkBuilder *dialog;
+ GtkSizeGroup *size_group;
+ GtkWidget *image;
+
+ dialog = gtk_builder_new ();
+ gtk_builder_add_from_file (dialog, MATECC_UI_DIR
+ "/mate-keyboard-properties-dialog.ui",
+ NULL);
+
+ size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+ gtk_size_group_add_widget (size_group, WID ("repeat_slow_label"));
+ gtk_size_group_add_widget (size_group, WID ("delay_short_label"));
+ gtk_size_group_add_widget (size_group, WID ("blink_slow_label"));
+ g_object_unref (G_OBJECT (size_group));
+
+ size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+ gtk_size_group_add_widget (size_group, WID ("repeat_fast_label"));
+ gtk_size_group_add_widget (size_group, WID ("delay_long_label"));
+ gtk_size_group_add_widget (size_group, WID ("blink_fast_label"));
+ g_object_unref (G_OBJECT (size_group));
+
+ size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+ gtk_size_group_add_widget (size_group, WID ("repeat_delay_scale"));
+ gtk_size_group_add_widget (size_group, WID ("repeat_speed_scale"));
+ gtk_size_group_add_widget (size_group, WID ("cursor_blink_time_scale"));
+ g_object_unref (G_OBJECT (size_group));
+
+ image = gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_BUTTON);
+ gtk_button_set_image (GTK_BUTTON (WID ("xkb_layouts_add")), image);
+
+ image = gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_BUTTON);
+ gtk_button_set_image (GTK_BUTTON (WID ("xkb_reset_to_defaults")), image);
+
+ return dialog;
+}
+
+static MateConfValue *
+blink_from_widget (MateConfPropertyEditor * peditor, const MateConfValue * value)
+{
+ MateConfValue *new_value;
+
+ new_value = mateconf_value_new (MATECONF_VALUE_INT);
+ mateconf_value_set_int (new_value,
+ 2600 - mateconf_value_get_int (value));
+
+ return new_value;
+}
+
+static MateConfValue *
+blink_to_widget (MateConfPropertyEditor * peditor, const MateConfValue * value)
+{
+ MateConfValue *new_value;
+ gint current_rate;
+
+ current_rate = mateconf_value_get_int (value);
+ new_value = mateconf_value_new (MATECONF_VALUE_INT);
+ mateconf_value_set_int (new_value,
+ CLAMP (2600 - current_rate, 100, 2500));
+
+ return new_value;
+}
+
+static void
+dialog_response (GtkWidget * widget,
+ gint response_id, MateConfChangeSet * changeset)
+{
+ if (response_id == GTK_RESPONSE_HELP)
+ capplet_help (GTK_WINDOW (widget), "goscustperiph-2");
+ else
+ gtk_main_quit ();
+}
+
+static void
+setup_dialog (GtkBuilder * dialog, MateConfChangeSet * changeset)
+{
+ GObject *peditor;
+ gchar *monitor;
+
+ peditor = mateconf_peditor_new_boolean
+ (changeset, "/desktop/mate/peripherals/keyboard/repeat",
+ WID ("repeat_toggle"), NULL);
+ mateconf_peditor_widget_set_guard (MATECONF_PROPERTY_EDITOR (peditor),
+ WID ("repeat_table"));
+
+ mateconf_peditor_new_numeric_range
+ (changeset, "/desktop/mate/peripherals/keyboard/delay",
+ WID ("repeat_delay_scale"), NULL);
+
+ mateconf_peditor_new_numeric_range
+ (changeset, "/desktop/mate/peripherals/keyboard/rate",
+ WID ("repeat_speed_scale"), NULL);
+
+ peditor = mateconf_peditor_new_boolean
+ (changeset, "/desktop/mate/interface/cursor_blink",
+ WID ("cursor_toggle"), NULL);
+ mateconf_peditor_widget_set_guard (MATECONF_PROPERTY_EDITOR (peditor),
+ WID ("cursor_hbox"));
+ mateconf_peditor_new_numeric_range (changeset,
+ "/desktop/mate/interface/cursor_blink_time",
+ WID ("cursor_blink_time_scale"),
+ "conv-to-widget-cb",
+ blink_to_widget,
+ "conv-from-widget-cb",
+ blink_from_widget, NULL);
+
+ /* Ergonomics */
+ monitor = g_find_program_in_path ("mate-typing-monitor");
+ if (monitor != NULL) {
+ g_free (monitor);
+
+ peditor = mateconf_peditor_new_boolean
+ (changeset, "/desktop/mate/typing_break/enabled",
+ WID ("break_enabled_toggle"), NULL);
+ mateconf_peditor_widget_set_guard (MATECONF_PROPERTY_EDITOR (peditor),
+ WID ("break_details_table"));
+ mateconf_peditor_new_numeric_range (changeset,
+ "/desktop/mate/typing_break/type_time",
+ WID ("break_enabled_spin"), NULL);
+ mateconf_peditor_new_numeric_range (changeset,
+ "/desktop/mate/typing_break/break_time",
+ WID ("break_interval_spin"),
+ NULL);
+ mateconf_peditor_new_boolean (changeset,
+ "/desktop/mate/typing_break/allow_postpone",
+ WID ("break_postponement_toggle"),
+ NULL);
+
+ } else {
+ /* don't show the typing break tab if the daemon is not available */
+ GtkNotebook *nb = GTK_NOTEBOOK (WID ("keyboard_notebook"));
+ gint tb_page = gtk_notebook_page_num (nb, WID ("break_enabled_toggle"));
+ gtk_notebook_remove_page (nb, tb_page);
+ }
+
+ g_signal_connect (WID ("keyboard_dialog"), "response",
+ (GCallback) dialog_response, changeset);
+
+ setup_xkb_tabs (dialog, changeset);
+ setup_a11y_tabs (dialog, changeset);
+}
+
+int
+main (int argc, char **argv)
+{
+ MateConfClient *client;
+ MateConfChangeSet *changeset;
+ GtkBuilder *dialog;
+ GOptionContext *context;
+
+ static gboolean apply_only = FALSE;
+ static gboolean switch_to_typing_break_page = FALSE;
+ static gboolean switch_to_a11y_page = FALSE;
+
+ static GOptionEntry cap_options[] = {
+ {"apply", 0, 0, G_OPTION_ARG_NONE, &apply_only,
+ N_
+ ("Just apply settings and quit (compatibility only; now handled by daemon)"),
+ NULL},
+ {"init-session-settings", 0, 0, G_OPTION_ARG_NONE,
+ &apply_only,
+ N_
+ ("Just apply settings and quit (compatibility only; now handled by daemon)"),
+ NULL},
+ {"typing-break", 0, 0, G_OPTION_ARG_NONE,
+ &switch_to_typing_break_page,
+ N_
+ ("Start the page with the typing break settings showing"),
+ NULL},
+ {"a11y", 0, 0, G_OPTION_ARG_NONE,
+ &switch_to_a11y_page,
+ N_
+ ("Start the page with the accessibility settings showing"),
+ NULL},
+ {NULL}
+ };
+
+
+ context = g_option_context_new (_("- MATE Keyboard Preferences"));
+ g_option_context_add_main_entries (context, cap_options,
+ GETTEXT_PACKAGE);
+
+ capplet_init (context, &argc, &argv);
+
+ activate_settings_daemon ();
+
+ client = mateconf_client_get_default ();
+ mateconf_client_add_dir (client,
+ "/desktop/mate/peripherals/keyboard",
+ MATECONF_CLIENT_PRELOAD_ONELEVEL, NULL);
+ mateconf_client_add_dir (client, "/desktop/mate/interface",
+ MATECONF_CLIENT_PRELOAD_ONELEVEL, NULL);
+ g_object_unref (client);
+
+ changeset = NULL;
+ dialog = create_dialog ();
+ setup_dialog (dialog, changeset);
+ if (switch_to_typing_break_page) {
+ gtk_notebook_set_current_page (GTK_NOTEBOOK
+ (WID
+ ("keyboard_notebook")),
+ 4);
+ }
+ else if (switch_to_a11y_page) {
+ gtk_notebook_set_current_page (GTK_NOTEBOOK
+ (WID
+ ("keyboard_notebook")),
+ 2);
+
+ }
+
+ capplet_set_icon (WID ("keyboard_dialog"),
+ "preferences-desktop-keyboard");
+ gtk_widget_show (WID ("keyboard_dialog"));
+ gtk_main ();
+
+ return 0;
+}
diff --git a/capplets/mouse/Makefile.am b/capplets/mouse/Makefile.am
new file mode 100644
index 00000000..c60082a5
--- /dev/null
+++ b/capplets/mouse/Makefile.am
@@ -0,0 +1,35 @@
+# This is used in MATECC_CAPPLETS_CFLAGS
+cappletname = mouse
+
+bin_PROGRAMS = mate-mouse-properties
+
+mate_mouse_properties_LDADD = $(MATECC_CAPPLETS_LIBS)
+mate_mouse_properties_SOURCES = \
+ mate-mouse-properties.c \
+ mate-mouse-accessibility.c \
+ mate-mouse-accessibility.h
+
+@INTLTOOL_DESKTOP_RULE@
+
+pixmapdir = $(pkgdatadir)/pixmaps
+pixmap_DATA = \
+ double-click-on.png \
+ double-click-off.png \
+ double-click-maybe.png
+
+uidir = $(pkgdatadir)/ui
+ui_DATA = mate-mouse-properties.ui
+
+desktopdir = $(datadir)/applications
+Desktop_in_files = mate-settings-mouse.desktop.in
+desktop_DATA = $(Desktop_in_files:.desktop.in=.desktop)
+
+INCLUDES = \
+ $(MATECC_CAPPLETS_CFLAGS) \
+ -DMATELOCALEDIR="\"$(datadir)/locale\"" \
+ -DMATECC_DATA_DIR="\"$(pkgdatadir)\"" \
+ -DMATECC_UI_DIR="\"$(uidir)\""
+CLEANFILES = $(MATECC_CAPPLETS_CLEANFILES) $(Desktop_in_files) $(desktop_DATA)
+EXTRA_DIST = $(ui_DATA) $(pixmap_DATA)
+
+-include $(top_srcdir)/git.mk
diff --git a/capplets/mouse/double-click-maybe.png b/capplets/mouse/double-click-maybe.png
new file mode 100644
index 00000000..6504e2e9
--- /dev/null
+++ b/capplets/mouse/double-click-maybe.png
Binary files differ
diff --git a/capplets/mouse/double-click-off.png b/capplets/mouse/double-click-off.png
new file mode 100644
index 00000000..ab428d13
--- /dev/null
+++ b/capplets/mouse/double-click-off.png
Binary files differ
diff --git a/capplets/mouse/double-click-on.png b/capplets/mouse/double-click-on.png
new file mode 100644
index 00000000..1ee9202e
--- /dev/null
+++ b/capplets/mouse/double-click-on.png
Binary files differ
diff --git a/capplets/mouse/mate-mouse-accessibility.c b/capplets/mouse/mate-mouse-accessibility.c
new file mode 100644
index 00000000..a1c4277b
--- /dev/null
+++ b/capplets/mouse/mate-mouse-accessibility.c
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2007 Gerd Kohlberger
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+
+#include "capplet-util.h"
+#include "mateconf-property-editor.h"
+
+#define MT_MATECONF_HOME "/desktop/mate/accessibility/mouse"
+
+/* 5th entry in combo box */
+#define DIRECTION_DISABLE 4
+
+enum {
+ CLICK_TYPE_SINGLE,
+ CLICK_TYPE_DOUBLE,
+ CLICK_TYPE_DRAG,
+ CLICK_TYPE_SECONDARY,
+ N_CLICK_TYPES
+};
+
+static void
+update_mode_sensitivity (GtkBuilder *dialog, gint mode)
+{
+ gtk_widget_set_sensitive (WID ("box_ctw"), !mode);
+ gtk_widget_set_sensitive (WID ("box_gesture"), mode);
+}
+
+/* check if a direction (gesture mode) is already in use */
+static gboolean
+verify_setting (MateConfClient *client, gint value, gint type)
+{
+ gint i, ct[N_CLICK_TYPES];
+
+ ct[CLICK_TYPE_SINGLE] =
+ mateconf_client_get_int (client,
+ MT_MATECONF_HOME "/dwell_gesture_single",
+ NULL);
+ ct[CLICK_TYPE_DOUBLE] =
+ mateconf_client_get_int (client,
+ MT_MATECONF_HOME "/dwell_gesture_double",
+ NULL);
+ ct[CLICK_TYPE_DRAG] =
+ mateconf_client_get_int (client,
+ MT_MATECONF_HOME "/dwell_gesture_drag",
+ NULL);
+ ct[CLICK_TYPE_SECONDARY] =
+ mateconf_client_get_int (client,
+ MT_MATECONF_HOME "/dwell_gesture_secondary",
+ NULL);
+
+ for (i = 0; i < N_CLICK_TYPES; ++i) {
+ if (i == type)
+ continue;
+ if (ct[i] == value)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+populate_gesture_combo (GtkWidget *combo)
+{
+ GtkListStore *model;
+ GtkTreeIter iter;
+ GtkCellRenderer *cr;
+
+ model = gtk_list_store_new (1, G_TYPE_STRING);
+
+ gtk_list_store_append (model, &iter);
+ /* Translators: this is the gesture to trigger/choose the click type.
+ Don't include the prefix "gesture|" in the translation. */
+ gtk_list_store_set (model, &iter, 0, Q_("gesture|Move left"), -1);
+
+ gtk_list_store_append (model, &iter);
+ /* Translators: this is the gesture to trigger/choose the click type.
+ Don't include the prefix "gesture|" in the translation. */
+ gtk_list_store_set (model, &iter, 0, Q_("gesture|Move right"), -1);
+
+ gtk_list_store_append (model, &iter);
+ /* Translators: this is the gesture to trigger/choose the click type.
+ Don't include the prefix "gesture|" in the translation. */
+ gtk_list_store_set (model, &iter, 0, Q_("gesture|Move up"), -1);
+
+ gtk_list_store_append (model, &iter);
+ /* Translators: this is the gesture to trigger/choose the click type.
+ Don't include the prefix "gesture|" in the translation. */
+ gtk_list_store_set (model, &iter, 0, Q_("gesture|Move down"), -1);
+
+ gtk_list_store_append (model, &iter);
+ /* Translators: this is the gesture to trigger/choose the click type.
+ Don't include the prefix "gesture|" in the translation. */
+ gtk_list_store_set (model, &iter, 0, Q_("gesture|Disabled"), -1);
+
+ gtk_combo_box_set_model (GTK_COMBO_BOX (combo), GTK_TREE_MODEL (model));
+
+ cr = gtk_cell_renderer_text_new ();
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cr, TRUE);
+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), cr,
+ "text", 0,
+ NULL);
+}
+
+static void
+delay_enable_toggled_cb (GtkWidget *checkbox, GtkBuilder *dialog)
+{
+ gtk_widget_set_sensitive (WID ("delay_box"),
+ gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (checkbox)));
+}
+
+static void
+dwell_enable_toggled_cb (GtkWidget *checkbox, GtkBuilder *dialog)
+{
+ gtk_widget_set_sensitive (WID ("dwell_box"),
+ gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (checkbox)));
+}
+
+static void
+gesture_single (GtkComboBox *combo, gpointer data)
+{
+ if (!verify_setting (data, gtk_combo_box_get_active (combo), CLICK_TYPE_SINGLE))
+ gtk_combo_box_set_active (combo, DIRECTION_DISABLE);
+}
+
+static void
+gesture_double (GtkComboBox *combo, gpointer data)
+{
+ if (!verify_setting (data, gtk_combo_box_get_active (combo), CLICK_TYPE_DOUBLE))
+ gtk_combo_box_set_active (combo, DIRECTION_DISABLE);
+}
+
+static void
+gesture_drag (GtkComboBox *combo, gpointer data)
+{
+ if (!verify_setting (data, gtk_combo_box_get_active (combo), CLICK_TYPE_DRAG))
+ gtk_combo_box_set_active (combo, DIRECTION_DISABLE);
+}
+
+static void
+gesture_secondary (GtkComboBox *combo, gpointer data)
+{
+ if (!verify_setting (data, gtk_combo_box_get_active (combo), CLICK_TYPE_SECONDARY))
+ gtk_combo_box_set_active (combo, DIRECTION_DISABLE);
+}
+
+static void
+mateconf_value_changed (MateConfClient *client,
+ const gchar *key,
+ MateConfValue *value,
+ gpointer dialog)
+{
+ if (g_str_equal (key, MT_MATECONF_HOME "/dwell_mode"))
+ update_mode_sensitivity (dialog, mateconf_value_get_int (value));
+}
+
+void
+setup_accessibility (GtkBuilder *dialog, MateConfClient *client)
+{
+ mateconf_client_add_dir (client, MT_MATECONF_HOME,
+ MATECONF_CLIENT_PRELOAD_ONELEVEL, NULL);
+ g_signal_connect (client, "value_changed",
+ G_CALLBACK (mateconf_value_changed), dialog);
+
+ mateconf_peditor_new_boolean (NULL, MT_MATECONF_HOME "/dwell_enable",
+ WID ("dwell_enable"), NULL);
+ mateconf_peditor_new_boolean (NULL, MT_MATECONF_HOME "/delay_enable",
+ WID ("delay_enable"), NULL);
+ mateconf_peditor_new_boolean (NULL, MT_MATECONF_HOME "/dwell_show_ctw",
+ WID ("dwell_show_ctw"), NULL);
+
+ mateconf_peditor_new_numeric_range (NULL, MT_MATECONF_HOME "/delay_time",
+ WID ("delay_time"), NULL);
+ mateconf_peditor_new_numeric_range (NULL, MT_MATECONF_HOME "/dwell_time",
+ WID ("dwell_time"), NULL);
+ mateconf_peditor_new_numeric_range (NULL, MT_MATECONF_HOME "/threshold",
+ WID ("threshold"), NULL);
+
+ mateconf_peditor_new_select_radio (NULL, MT_MATECONF_HOME "/dwell_mode",
+ gtk_radio_button_get_group (GTK_RADIO_BUTTON (WID ("dwell_mode_ctw"))),
+ NULL);
+ update_mode_sensitivity (dialog,
+ mateconf_client_get_int (client,
+ MT_MATECONF_HOME "/dwell_mode",
+ NULL));
+
+ populate_gesture_combo (WID ("dwell_gest_single"));
+ mateconf_peditor_new_combo_box (NULL, MT_MATECONF_HOME "/dwell_gesture_single",
+ WID ("dwell_gest_single"), NULL);
+ g_signal_connect (WID ("dwell_gest_single"), "changed",
+ G_CALLBACK (gesture_single), client);
+
+ populate_gesture_combo (WID ("dwell_gest_double"));
+ mateconf_peditor_new_combo_box (NULL, MT_MATECONF_HOME "/dwell_gesture_double",
+ WID ("dwell_gest_double"), NULL);
+ g_signal_connect (WID ("dwell_gest_double"), "changed",
+ G_CALLBACK (gesture_double), client);
+
+ populate_gesture_combo (WID ("dwell_gest_drag"));
+ mateconf_peditor_new_combo_box (NULL, MT_MATECONF_HOME "/dwell_gesture_drag",
+ WID ("dwell_gest_drag"), NULL);
+ g_signal_connect (WID ("dwell_gest_drag"), "changed",
+ G_CALLBACK (gesture_drag), client);
+
+ populate_gesture_combo (WID ("dwell_gest_secondary"));
+ mateconf_peditor_new_combo_box (NULL, MT_MATECONF_HOME "/dwell_gesture_secondary",
+ WID ("dwell_gest_secondary"), NULL);
+ g_signal_connect (WID ("dwell_gest_secondary"), "changed",
+ G_CALLBACK (gesture_secondary), client);
+
+ g_signal_connect (WID ("delay_enable"), "toggled",
+ G_CALLBACK (delay_enable_toggled_cb), dialog);
+ delay_enable_toggled_cb (WID ("delay_enable"), dialog);
+ g_signal_connect (WID ("dwell_enable"), "toggled",
+ G_CALLBACK (dwell_enable_toggled_cb), dialog);
+ dwell_enable_toggled_cb (WID ("dwell_enable"), dialog);
+}
diff --git a/capplets/mouse/mate-mouse-accessibility.h b/capplets/mouse/mate-mouse-accessibility.h
new file mode 100644
index 00000000..0fd4ad33
--- /dev/null
+++ b/capplets/mouse/mate-mouse-accessibility.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2007 Gerd Kohlberger
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __MATE_MOUSE_A11Y_H
+#define __MATE_MOUSE_A11Y_H
+
+#include <mateconf/mateconf-client.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void setup_accessibility (GtkBuilder *dialog, MateConfClient *client);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MATE_MOUSE_A11Y_H */
diff --git a/capplets/mouse/mate-mouse-properties.c b/capplets/mouse/mate-mouse-properties.c
new file mode 100644
index 00000000..8e9824b9
--- /dev/null
+++ b/capplets/mouse/mate-mouse-properties.c
@@ -0,0 +1,647 @@
+/* -*- mode: c; style: linux -*- */
+
+/* mouse-properties-capplet.c
+ * Copyright (C) 2001 Red Hat, Inc.
+ * Copyright (C) 2001 Ximian, Inc.
+ *
+ * Written by: Jonathon Blandford <[email protected]>,
+ * Bradford Hovinen <[email protected]>,
+ *
+ * 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, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#include <glib/gi18n.h>
+#include <string.h>
+#include <mateconf/mateconf-client.h>
+#include <gdk/gdkx.h>
+#include <math.h>
+
+#include "capplet-util.h"
+#include "mateconf-property-editor.h"
+#include "activate-settings-daemon.h"
+#include "capplet-stock-icons.h"
+#include "mate-mouse-accessibility.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#ifdef HAVE_XINPUT
+#include <X11/Xatom.h>
+#include <X11/extensions/XInput.h>
+#endif
+
+#ifdef HAVE_XCURSOR
+#include <X11/Xcursor/Xcursor.h>
+#endif
+
+enum
+{
+ DOUBLE_CLICK_TEST_OFF,
+ DOUBLE_CLICK_TEST_MAYBE,
+ DOUBLE_CLICK_TEST_ON
+};
+
+/* We use this in at least half a dozen places, so it makes sense just to
+ * define the macro */
+
+#define DOUBLE_CLICK_KEY "/desktop/mate/peripherals/mouse/double_click"
+
+/* State in testing the double-click speed. Global for a great deal of
+ * convenience
+ */
+static gint double_click_state = DOUBLE_CLICK_TEST_OFF;
+
+/* normalization routines */
+/* All of our scales but double_click are on the range 1->10 as a result, we
+ * have a few routines to convert from whatever the mateconf key is to our range.
+ */
+static MateConfValue *
+double_click_from_mateconf (MateConfPropertyEditor *peditor, const MateConfValue *value)
+{
+ MateConfValue *new_value;
+
+ new_value = mateconf_value_new (MATECONF_VALUE_INT);
+ mateconf_value_set_int (new_value, CLAMP ((int) floor ((mateconf_value_get_int (value) + 50) / 100.0) * 100, 100, 1000));
+ return new_value;
+}
+
+static void
+get_default_mouse_info (int *default_numerator, int *default_denominator, int *default_threshold)
+{
+ int numerator, denominator;
+ int threshold;
+ int tmp_num, tmp_den, tmp_threshold;
+
+ /* Query X for the default value */
+ XGetPointerControl (GDK_DISPLAY (), &numerator, &denominator,
+ &threshold);
+ XChangePointerControl (GDK_DISPLAY (), True, True, -1, -1, -1);
+ XGetPointerControl (GDK_DISPLAY (), &tmp_num, &tmp_den, &tmp_threshold);
+ XChangePointerControl (GDK_DISPLAY (), True, True, numerator, denominator, threshold);
+
+ if (default_numerator)
+ *default_numerator = tmp_num;
+
+ if (default_denominator)
+ *default_denominator = tmp_den;
+
+ if (default_threshold)
+ *default_threshold = tmp_threshold;
+
+}
+
+static MateConfValue *
+motion_acceleration_from_mateconf (MateConfPropertyEditor *peditor,
+ const MateConfValue *value)
+{
+ MateConfValue *new_value;
+ gfloat motion_acceleration;
+
+ new_value = mateconf_value_new (MATECONF_VALUE_FLOAT);
+
+ if (mateconf_value_get_float (value) == -1.0) {
+ int numerator, denominator;
+
+ get_default_mouse_info (&numerator, &denominator, NULL);
+
+ motion_acceleration = CLAMP ((gfloat)(numerator / denominator), 0.2, 6.0);
+ }
+ else {
+ motion_acceleration = CLAMP (mateconf_value_get_float (value), 0.2, 6.0);
+ }
+
+ if (motion_acceleration >= 1)
+ mateconf_value_set_float (new_value, motion_acceleration + 4);
+ else
+ mateconf_value_set_float (new_value, motion_acceleration * 5);
+
+ return new_value;
+}
+
+static MateConfValue *
+motion_acceleration_to_mateconf (MateConfPropertyEditor *peditor,
+ const MateConfValue *value)
+{
+ MateConfValue *new_value;
+ gfloat motion_acceleration;
+
+ new_value = mateconf_value_new (MATECONF_VALUE_FLOAT);
+ motion_acceleration = CLAMP (mateconf_value_get_float (value), 1.0, 10.0);
+
+ if (motion_acceleration < 5)
+ mateconf_value_set_float (new_value, motion_acceleration / 5.0);
+ else
+ mateconf_value_set_float (new_value, motion_acceleration - 4);
+
+ return new_value;
+}
+
+static MateConfValue *
+threshold_from_mateconf (MateConfPropertyEditor *peditor,
+ const MateConfValue *value)
+{
+ MateConfValue *new_value;
+
+ new_value = mateconf_value_new (MATECONF_VALUE_FLOAT);
+
+ if (mateconf_value_get_int (value) == -1) {
+ int threshold;
+
+ get_default_mouse_info (NULL, NULL, &threshold);
+ mateconf_value_set_float (new_value, CLAMP (threshold, 1, 10));
+ }
+ else {
+ mateconf_value_set_float (new_value, CLAMP (mateconf_value_get_int (value), 1, 10));
+ }
+
+ return new_value;
+}
+
+static MateConfValue *
+drag_threshold_from_mateconf (MateConfPropertyEditor *peditor,
+ const MateConfValue *value)
+{
+ MateConfValue *new_value;
+
+ new_value = mateconf_value_new (MATECONF_VALUE_FLOAT);
+
+ mateconf_value_set_float (new_value, CLAMP (mateconf_value_get_int (value), 1, 10));
+
+ return new_value;
+}
+
+/* Double Click handling */
+
+struct test_data_t
+{
+ gint *timeout_id;
+ GtkWidget *image;
+};
+
+/* Timeout for the double click test */
+
+static gboolean
+test_maybe_timeout (struct test_data_t *data)
+{
+ double_click_state = DOUBLE_CLICK_TEST_OFF;
+
+ gtk_image_set_from_stock (GTK_IMAGE (data->image),
+ MOUSE_DBLCLCK_OFF, mouse_capplet_dblclck_icon_get_size());
+
+ *data->timeout_id = 0;
+
+ return FALSE;
+}
+
+/* Callback issued when the user clicks the double click testing area. */
+
+static gboolean
+event_box_button_press_event (GtkWidget *widget,
+ GdkEventButton *event,
+ MateConfChangeSet *changeset)
+{
+ gint double_click_time;
+ MateConfValue *value;
+ static struct test_data_t data;
+ static gint test_on_timeout_id = 0;
+ static gint test_maybe_timeout_id = 0;
+ static guint32 double_click_timestamp = 0;
+ GtkWidget *image;
+ MateConfClient *client;
+
+ if (event->type != GDK_BUTTON_PRESS)
+ return FALSE;
+
+ image = g_object_get_data (G_OBJECT (widget), "image");
+
+ if (!(changeset && mateconf_change_set_check_value (changeset, DOUBLE_CLICK_KEY, &value))) {
+ client = mateconf_client_get_default();
+ double_click_time = mateconf_client_get_int (client, DOUBLE_CLICK_KEY, NULL);
+ g_object_unref (client);
+
+ } else
+ double_click_time = mateconf_value_get_int (value);
+
+ if (test_maybe_timeout_id != 0)
+ g_source_remove (test_maybe_timeout_id);
+ if (test_on_timeout_id != 0)
+ g_source_remove (test_on_timeout_id);
+
+ switch (double_click_state) {
+ case DOUBLE_CLICK_TEST_OFF:
+ double_click_state = DOUBLE_CLICK_TEST_MAYBE;
+ data.image = image;
+ data.timeout_id = &test_maybe_timeout_id;
+ test_maybe_timeout_id = g_timeout_add (double_click_time, (GtkFunction) test_maybe_timeout, &data);
+ break;
+ case DOUBLE_CLICK_TEST_MAYBE:
+ if (event->time - double_click_timestamp < double_click_time) {
+ double_click_state = DOUBLE_CLICK_TEST_ON;
+ data.image = image;
+ data.timeout_id = &test_on_timeout_id;
+ test_on_timeout_id = g_timeout_add (2500, (GtkFunction) test_maybe_timeout, &data);
+ }
+ break;
+ case DOUBLE_CLICK_TEST_ON:
+ double_click_state = DOUBLE_CLICK_TEST_OFF;
+ break;
+ }
+
+ double_click_timestamp = event->time;
+
+ switch (double_click_state) {
+ case DOUBLE_CLICK_TEST_ON:
+ gtk_image_set_from_stock (GTK_IMAGE (image),
+ MOUSE_DBLCLCK_ON, mouse_capplet_dblclck_icon_get_size());
+ break;
+ case DOUBLE_CLICK_TEST_MAYBE:
+ gtk_image_set_from_stock (GTK_IMAGE (image),
+ MOUSE_DBLCLCK_MAYBE, mouse_capplet_dblclck_icon_get_size());
+ break;
+ case DOUBLE_CLICK_TEST_OFF:
+ gtk_image_set_from_stock (GTK_IMAGE (image),
+ MOUSE_DBLCLCK_OFF, mouse_capplet_dblclck_icon_get_size());
+ break;
+ }
+
+ return TRUE;
+}
+
+static void
+orientation_radio_button_release_event (GtkWidget *widget,
+ GdkEventButton *event)
+{
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
+}
+
+static MateConfValue *
+left_handed_from_mateconf (MateConfPropertyEditor *peditor,
+ const MateConfValue *value)
+{
+ MateConfValue *new_value;
+
+ new_value = mateconf_value_new (MATECONF_VALUE_INT);
+
+ mateconf_value_set_int (new_value, mateconf_value_get_bool (value));
+
+ return new_value;
+}
+
+static MateConfValue *
+left_handed_to_mateconf (MateConfPropertyEditor *peditor,
+ const MateConfValue *value)
+{
+ MateConfValue *new_value;
+
+ new_value = mateconf_value_new (MATECONF_VALUE_BOOL);
+
+ mateconf_value_set_bool (new_value, mateconf_value_get_int (value) == 1);
+
+ return new_value;
+}
+
+static void
+scrollmethod_changed_event (MateConfPropertyEditor *peditor,
+ const gchar *key,
+ const MateConfValue *value,
+ GtkBuilder *dialog)
+{
+ GtkToggleButton *disabled = GTK_TOGGLE_BUTTON (WID ("scroll_disabled_radio"));
+
+ gtk_widget_set_sensitive (WID ("horiz_scroll_toggle"),
+ !gtk_toggle_button_get_active (disabled));
+}
+
+static void
+synaptics_check_capabilities (GtkBuilder *dialog)
+{
+#ifdef HAVE_XINPUT
+ int numdevices, i;
+ XDeviceInfo *devicelist;
+ Atom realtype, prop;
+ int realformat;
+ unsigned long nitems, bytes_after;
+ unsigned char *data;
+
+ prop = XInternAtom (GDK_DISPLAY (), "Synaptics Capabilities", True);
+ if (!prop)
+ return;
+
+ devicelist = XListInputDevices (GDK_DISPLAY (), &numdevices);
+ for (i = 0; i < numdevices; i++) {
+ if (devicelist[i].use != IsXExtensionPointer)
+ continue;
+
+ gdk_error_trap_push ();
+ XDevice *device = XOpenDevice (GDK_DISPLAY (),
+ devicelist[i].id);
+ if (gdk_error_trap_pop ())
+ continue;
+
+ gdk_error_trap_push ();
+ if ((XGetDeviceProperty (GDK_DISPLAY (), device, prop, 0, 2, False,
+ XA_INTEGER, &realtype, &realformat, &nitems,
+ &bytes_after, &data) == Success) && (realtype != None)) {
+ /* Property data is booleans for has_left, has_middle,
+ * has_right, has_double, has_triple */
+ if (!data[0]) {
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (WID ("tap_to_click_toggle")), TRUE);
+ gtk_widget_set_sensitive (WID ("tap_to_click_toggle"), FALSE);
+ }
+
+ if (!data[3])
+ gtk_widget_set_sensitive (WID ("scroll_twofinger_radio"), FALSE);
+
+ XFree (data);
+ }
+ gdk_error_trap_pop ();
+
+ XCloseDevice (GDK_DISPLAY (), device);
+ }
+ XFreeDeviceList (devicelist);
+#endif
+}
+
+static gboolean
+find_synaptics (void)
+{
+ gboolean ret = FALSE;
+#ifdef HAVE_XINPUT
+ int numdevices, i;
+ XDeviceInfo *devicelist;
+ Atom realtype, prop;
+ int realformat;
+ unsigned long nitems, bytes_after;
+ unsigned char *data;
+ XExtensionVersion *version;
+
+ /* Input device properties require version 1.5 or higher */
+ version = XGetExtensionVersion (GDK_DISPLAY (), "XInputExtension");
+ if (!version->present ||
+ (version->major_version * 1000 + version->minor_version) < 1005) {
+ XFree (version);
+ return False;
+ }
+
+ prop = XInternAtom (GDK_DISPLAY (), "Synaptics Off", True);
+ if (!prop)
+ return False;
+
+ devicelist = XListInputDevices (GDK_DISPLAY (), &numdevices);
+ for (i = 0; i < numdevices; i++) {
+ if (devicelist[i].use != IsXExtensionPointer)
+ continue;
+
+ gdk_error_trap_push();
+ XDevice *device = XOpenDevice (GDK_DISPLAY (),
+ devicelist[i].id);
+ if (gdk_error_trap_pop ())
+ continue;
+
+ gdk_error_trap_push ();
+ if ((XGetDeviceProperty (GDK_DISPLAY (), device, prop, 0, 1, False,
+ XA_INTEGER, &realtype, &realformat, &nitems,
+ &bytes_after, &data) == Success) && (realtype != None)) {
+ XFree (data);
+ ret = TRUE;
+ }
+ gdk_error_trap_pop ();
+
+ XCloseDevice (GDK_DISPLAY (), device);
+
+ if (ret)
+ break;
+ }
+
+ XFree (version);
+ XFreeDeviceList (devicelist);
+#endif
+ return ret;
+}
+
+/* Set up the property editors in the dialog. */
+static void
+setup_dialog (GtkBuilder *dialog, MateConfChangeSet *changeset)
+{
+ GtkRadioButton *radio;
+ GObject *peditor;
+
+ /* Orientation radio buttons */
+ radio = GTK_RADIO_BUTTON (WID ("left_handed_radio"));
+ peditor = mateconf_peditor_new_select_radio
+ (changeset, "/desktop/mate/peripherals/mouse/left_handed", gtk_radio_button_get_group (radio),
+ "conv-to-widget-cb", left_handed_from_mateconf,
+ "conv-from-widget-cb", left_handed_to_mateconf,
+ NULL);
+ /* explicitly connect to button-release so that you can change orientation with either button */
+ g_signal_connect (WID ("right_handed_radio"), "button_release_event",
+ G_CALLBACK (orientation_radio_button_release_event), NULL);
+ g_signal_connect (WID ("left_handed_radio"), "button_release_event",
+ G_CALLBACK (orientation_radio_button_release_event), NULL);
+
+ /* Locate pointer toggle */
+ peditor = mateconf_peditor_new_boolean
+ (changeset, "/desktop/mate/peripherals/mouse/locate_pointer", WID ("locate_pointer_toggle"), NULL);
+
+ /* Double-click time */
+ peditor = mateconf_peditor_new_numeric_range
+ (changeset, DOUBLE_CLICK_KEY, WID ("delay_scale"),
+ "conv-to-widget-cb", double_click_from_mateconf,
+ NULL);
+ gtk_image_set_from_stock (GTK_IMAGE (WID ("double_click_image")), MOUSE_DBLCLCK_OFF, mouse_capplet_dblclck_icon_get_size ());
+ g_object_set_data (G_OBJECT (WID ("double_click_eventbox")), "image", WID ("double_click_image"));
+ g_signal_connect (WID ("double_click_eventbox"), "button_press_event",
+ G_CALLBACK (event_box_button_press_event), changeset);
+
+ /* speed */
+ mateconf_peditor_new_numeric_range
+ (changeset, "/desktop/mate/peripherals/mouse/motion_acceleration", WID ("accel_scale"),
+ "conv-to-widget-cb", motion_acceleration_from_mateconf,
+ "conv-from-widget-cb", motion_acceleration_to_mateconf,
+ NULL);
+
+ mateconf_peditor_new_numeric_range
+ (changeset, "/desktop/mate/peripherals/mouse/motion_threshold", WID ("sensitivity_scale"),
+ "conv-to-widget-cb", threshold_from_mateconf,
+ NULL);
+
+ /* DnD threshold */
+ mateconf_peditor_new_numeric_range
+ (changeset, "/desktop/mate/peripherals/mouse/drag_threshold", WID ("drag_threshold_scale"),
+ "conv-to-widget-cb", drag_threshold_from_mateconf,
+ NULL);
+
+ /* Trackpad page */
+ if (find_synaptics () == FALSE)
+ gtk_notebook_remove_page (GTK_NOTEBOOK (WID ("prefs_widget")), -1);
+ else {
+ mateconf_peditor_new_boolean
+ (changeset, "/desktop/mate/peripherals/touchpad/disable_while_typing", WID ("disable_w_typing_toggle"), NULL);
+ mateconf_peditor_new_boolean
+ (changeset, "/desktop/mate/peripherals/touchpad/tap_to_click", WID ("tap_to_click_toggle"), NULL);
+ mateconf_peditor_new_boolean
+ (changeset, "/desktop/mate/peripherals/touchpad/horiz_scroll_enabled", WID ("horiz_scroll_toggle"), NULL);
+ radio = GTK_RADIO_BUTTON (WID ("scroll_disabled_radio"));
+ peditor = mateconf_peditor_new_select_radio
+ (changeset, "/desktop/mate/peripherals/touchpad/scroll_method", gtk_radio_button_get_group (radio),
+ NULL);
+
+ synaptics_check_capabilities (dialog);
+ scrollmethod_changed_event (MATECONF_PROPERTY_EDITOR (peditor), NULL, NULL, dialog);
+ g_signal_connect (peditor, "value-changed",
+ G_CALLBACK (scrollmethod_changed_event), dialog);
+ }
+
+}
+
+/* Construct the dialog */
+
+static GtkBuilder *
+create_dialog (void)
+{
+ GtkBuilder *dialog;
+ GtkSizeGroup *size_group;
+ GError *error = NULL;
+
+ dialog = gtk_builder_new ();
+ gtk_builder_add_from_file (dialog, MATECC_UI_DIR "/mate-mouse-properties.ui", &error);
+ if (error != NULL) {
+ g_warning ("Error loading UI file: %s", error->message);
+ return NULL;
+ }
+
+ size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+ gtk_size_group_add_widget (size_group, WID ("acceleration_label"));
+ gtk_size_group_add_widget (size_group, WID ("sensitivity_label"));
+ gtk_size_group_add_widget (size_group, WID ("threshold_label"));
+ gtk_size_group_add_widget (size_group, WID ("timeout_label"));
+
+ size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+ gtk_size_group_add_widget (size_group, WID ("acceleration_fast_label"));
+ gtk_size_group_add_widget (size_group, WID ("sensitivity_high_label"));
+ gtk_size_group_add_widget (size_group, WID ("threshold_large_label"));
+ gtk_size_group_add_widget (size_group, WID ("timeout_long_label"));
+
+ size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+ gtk_size_group_add_widget (size_group, WID ("acceleration_slow_label"));
+ gtk_size_group_add_widget (size_group, WID ("sensitivity_low_label"));
+ gtk_size_group_add_widget (size_group, WID ("threshold_small_label"));
+ gtk_size_group_add_widget (size_group, WID ("timeout_short_label"));
+
+ size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+ gtk_size_group_add_widget (size_group, WID ("simulated_delay_label"));
+ gtk_size_group_add_widget (size_group, WID ("dwell_delay_label"));
+ gtk_size_group_add_widget (size_group, WID ("dwell_threshold_label"));
+
+ size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+ gtk_size_group_add_widget (size_group, WID ("simulated_delay_short_label"));
+ gtk_size_group_add_widget (size_group, WID ("dwell_delay_short_label"));
+ gtk_size_group_add_widget (size_group, WID ("dwell_threshold_small_label"));
+
+ size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+ gtk_size_group_add_widget (size_group, WID ("simulated_delay_long_label"));
+ gtk_size_group_add_widget (size_group, WID ("dwell_delay_long_label"));
+ gtk_size_group_add_widget (size_group, WID ("dwell_threshold_large_label"));
+
+ return dialog;
+}
+
+/* Callback issued when a button is clicked on the dialog */
+
+static void
+dialog_response_cb (GtkDialog *dialog, gint response_id, MateConfChangeSet *changeset)
+{
+ if (response_id == GTK_RESPONSE_HELP)
+ capplet_help (GTK_WINDOW (dialog),
+ "goscustperiph-5");
+ else
+ gtk_main_quit ();
+}
+
+int
+main (int argc, char **argv)
+{
+ MateConfClient *client;
+ GtkBuilder *dialog;
+ GtkWidget *dialog_win, *w;
+ gchar *start_page = NULL;
+
+ GOptionContext *context;
+ GOptionEntry cap_options[] = {
+ {"show-page", 'p', G_OPTION_FLAG_IN_MAIN,
+ G_OPTION_ARG_STRING,
+ &start_page,
+ /* TRANSLATORS: don't translate the terms in brackets */
+ N_("Specify the name of the page to show (general|accessibility)"),
+ N_("page") },
+ {NULL}
+ };
+
+ context = g_option_context_new (_("- MATE Mouse Preferences"));
+ g_option_context_add_main_entries (context, cap_options, GETTEXT_PACKAGE);
+ capplet_init (context, &argc, &argv);
+
+ capplet_init_stock_icons ();
+
+ activate_settings_daemon ();
+
+ client = mateconf_client_get_default ();
+ mateconf_client_add_dir (client, "/desktop/mate/peripherals/mouse", MATECONF_CLIENT_PRELOAD_ONELEVEL, NULL);
+ mateconf_client_add_dir (client, "/desktop/mate/peripherals/touchpad", MATECONF_CLIENT_PRELOAD_ONELEVEL, NULL);
+
+ dialog = create_dialog ();
+
+ if (dialog) {
+ setup_dialog (dialog, NULL);
+ setup_accessibility (dialog, client);
+
+ dialog_win = WID ("mouse_properties_dialog");
+ g_signal_connect (dialog_win, "response",
+ G_CALLBACK (dialog_response_cb), NULL);
+
+ if (start_page != NULL) {
+ gchar *page_name;
+
+ page_name = g_strconcat (start_page, "_vbox", NULL);
+ g_free (start_page);
+
+ w = WID (page_name);
+ if (w != NULL) {
+ GtkNotebook *nb;
+ gint pindex;
+
+ nb = GTK_NOTEBOOK (WID ("prefs_widget"));
+ pindex = gtk_notebook_page_num (nb, w);
+ if (pindex != -1)
+ gtk_notebook_set_current_page (nb, pindex);
+ }
+ g_free (page_name);
+ }
+
+ capplet_set_icon (dialog_win, "input-mouse");
+ gtk_widget_show (dialog_win);
+
+ gtk_main ();
+
+ g_object_unref (dialog);
+ }
+
+ g_object_unref (client);
+
+ return 0;
+}
diff --git a/capplets/mouse/mate-mouse-properties.ui b/capplets/mouse/mate-mouse-properties.ui
new file mode 100644
index 00000000..b855ff11
--- /dev/null
+++ b/capplets/mouse/mate-mouse-properties.ui
@@ -0,0 +1,1707 @@
+<?xml version="1.0"?>
+<interface>
+ <object class="GtkAdjustment" id="adjustment1">
+ <property name="upper">10</property>
+ <property name="lower">1</property>
+ <property name="page_increment">1</property>
+ <property name="step_increment">1</property>
+ <property name="page_size">0</property>
+ <property name="value">6</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment2">
+ <property name="upper">10</property>
+ <property name="lower">1</property>
+ <property name="page_increment">1</property>
+ <property name="step_increment">1</property>
+ <property name="page_size">0</property>
+ <property name="value">1</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment3">
+ <property name="upper">10</property>
+ <property name="lower">1</property>
+ <property name="page_increment">1</property>
+ <property name="step_increment">1</property>
+ <property name="page_size">0</property>
+ <property name="value">1</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment4">
+ <property name="upper">1000</property>
+ <property name="lower">100</property>
+ <property name="page_increment">100</property>
+ <property name="step_increment">100</property>
+ <property name="page_size">0</property>
+ <property name="value">400</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment5">
+ <property name="upper">3</property>
+ <property name="lower">0.5</property>
+ <property name="page_increment">0.10000000000000001</property>
+ <property name="step_increment">0.10000000000000001</property>
+ <property name="page_size">0</property>
+ <property name="value">1.2</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment6">
+ <property name="upper">3</property>
+ <property name="lower">0.20000000000000001</property>
+ <property name="page_increment">0.10000000000000001</property>
+ <property name="step_increment">0.10000000000000001</property>
+ <property name="page_size">0</property>
+ <property name="value">1.2</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment7">
+ <property name="upper">30</property>
+ <property name="lower">0</property>
+ <property name="page_increment">1</property>
+ <property name="step_increment">1</property>
+ <property name="page_size">0</property>
+ <property name="value">15</property>
+ </object>
+ <!-- interface-requires gtk+ 2.16 -->
+ <!-- interface-naming-policy toplevel-contextual -->
+ <object class="GtkDialog" id="mouse_properties_dialog">
+ <property name="border_width">5</property>
+ <property name="title" translatable="yes">Mouse Preferences</property>
+ <property name="type_hint">dialog</property>
+ <property name="has_separator">False</property>
+ <child internal-child="vbox">
+ <object class="GtkVBox" id="dialog-vbox1">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">2</property>
+ <child>
+ <object class="GtkNotebook" id="prefs_widget">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="border_width">5</property>
+ <child>
+ <object class="GtkVBox" id="general_vbox">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="border_width">12</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">18</property>
+ <child>
+ <object class="GtkVBox" id="orientation_vbox">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel" id="label27">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Mouse Orientation</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment1">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="top_padding">6</property>
+ <property name="left_padding">12</property>
+ <child>
+ <object class="GtkVBox" id="vbox29">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkRadioButton" id="right_handed_radio">
+ <property name="label" translatable="yes">_Right-handed</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="use_underline">True</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="left_handed_radio">
+ <property name="label" translatable="yes">_Left-handed</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="use_underline">True</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">right_handed_radio</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="locate_pointer_vbox">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel" id="label5">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Locate Pointer</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment4">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="top_padding">6</property>
+ <property name="left_padding">12</property>
+ <child>
+ <object class="GtkCheckButton" id="locate_pointer_toggle">
+ <property name="label" translatable="yes">Sh_ow position of pointer when the Control key is pressed</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="pointer_speed_vbox">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel" id="label29">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Pointer Speed</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment5">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="top_padding">6</property>
+ <property name="left_padding">12</property>
+ <child>
+ <object class="GtkTable" id="table2">
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">3</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="acceleration_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Acceleration:</property>
+ <property name="use_underline">True</property>
+ <property name="justify">center</property>
+ <property name="mnemonic_widget">accel_scale</property>
+ </object>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="sensitivity_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Sensitivity:</property>
+ <property name="use_underline">True</property>
+ <property name="justify">center</property>
+ <property name="mnemonic_widget">sensitivity_scale</property>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox1">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="acceleration_slow_label">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property comments="slow acceleration" name="label" translatable="yes">Slow</property>
+ <property name="justify">center</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ <attribute name="scale" value="0.83"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHScale" id="accel_scale">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="update_policy">discontinuous</property>
+ <property name="adjustment">adjustment1</property>
+ <property name="draw_value">False</property>
+ <property name="value_pos">right</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="acceleration_fast_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" comments="fast acceleration" translatable="yes">Fast</property>
+ <property name="justify">center</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ <attribute name="scale" value="0.83"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox3">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="sensitivity_low_label">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property comments="low sensitivity" name="label" translatable="yes">Low</property>
+ <property name="justify">center</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ <attribute name="scale" value="0.83"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHScale" id="sensitivity_scale">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="update_policy">discontinuous</property>
+ <property name="adjustment">adjustment2</property>
+ <property name="digits">0</property>
+ <property name="draw_value">False</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="sensitivity_high_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property comments="high sensitivity" name="label" translatable="yes">High</property>
+ <property name="justify">center</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ <attribute name="scale" value="0.83"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="dnd_vbox">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel" id="label8">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Drag and Drop</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment6">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="top_padding">6</property>
+ <property name="left_padding">12</property>
+ <child>
+ <object class="GtkVBox" id="vbox7">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkHBox" id="cursor_hbox2">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="threshold_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Thr_eshold:</property>
+ <property name="use_underline">True</property>
+ <property name="justify">center</property>
+ <property name="mnemonic_widget">drag_threshold_scale</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox9">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="threshold_small_label">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property comments="small threshold" name="label" translatable="yes">Small</property>
+ <property name="justify">center</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ <attribute name="scale" value="0.83"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHScale" id="drag_threshold_scale">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="update_policy">discontinuous</property>
+ <property name="adjustment">adjustment3</property>
+ <property name="digits">0</property>
+ <property name="draw_value">False</property>
+ <accessibility>
+
+ </accessibility>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="a11y-drag_threshold_scale1">
+ <property name="AtkObject::accessible-description" translatable="yes">Cursor blinks speed</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="threshold_large_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property comments="large threshold" name="label" translatable="yes">Large</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ <attribute name="scale" value="0.83"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="double_click_timeout_vbox">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel" id="label31">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Double-Click Timeout</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment7">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="top_padding">6</property>
+ <property name="left_padding">12</property>
+ <child>
+ <object class="GtkVBox" id="vbox32">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkHBox" id="cursor_hbox4">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="timeout_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Timeout:</property>
+ <property name="use_underline">True</property>
+ <property name="justify">center</property>
+ <property name="mnemonic_widget">delay_scale</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox21">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="timeout_short_label">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property name="label" translatable="yes">Short</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ <attribute name="scale" value="0.83"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHScale" id="delay_scale">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="update_policy">discontinuous</property>
+ <property name="adjustment">adjustment4</property>
+ <property name="draw_value">False</property>
+ <accessibility>
+
+ </accessibility>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="a11y-delay_scale1">
+ <property name="AtkObject::accessible-description" translatable="yes">Cursor blinks speed</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="timeout_long_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Long</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ <attribute name="scale" value="0.83"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox22">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="label33">
+ <property name="width_request">180</property>
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">To test your double-click settings, try to double-click on the light bulb.</property>
+ <property name="wrap">True</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEventBox" id="double_click_eventbox">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="visible_window">False</property>
+ <child>
+ <object class="GtkImage" id="double_click_image">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="stock">gtk-missing-image</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">General</property>
+ <property name="justify">center</property>
+ </object>
+ <packing>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="accessibility_vbox">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="border_width">12</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">18</property>
+ <child>
+ <object class="GtkVBox" id="simulated_secondary_vbox">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel" id="label21">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Simulated Secondary Click</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment8">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="top_padding">6</property>
+ <property name="left_padding">12</property>
+ <child>
+ <object class="GtkVBox" id="vbox18">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkCheckButton" id="delay_enable">
+ <property name="label" translatable="yes">_Trigger secondary click by holding down the primary button</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment11">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="left_padding">12</property>
+ <child>
+ <object class="GtkHBox" id="delay_box">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="simulated_delay_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Delay:</property>
+ <property name="use_underline">True</property>
+ <property name="justify">center</property>
+ <property name="mnemonic_widget">delay_time</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox12">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="simulated_delay_short_label">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property name="yalign">0.4699999988079071</property>
+ <property comments="short delay" name="label" translatable="yes">Short</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ <attribute name="scale" value="0.83"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHScale" id="delay_time">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="update_policy">discontinuous</property>
+ <property name="adjustment">adjustment5</property>
+ <property name="draw_value">False</property>
+ <accessibility>
+
+ </accessibility>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="a11y-delay_time1">
+ <property name="AtkObject::accessible-description" translatable="yes">Cursor blinks speed</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="simulated_delay_long_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property comments="long delay" name="label" translatable="yes">Long</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ <attribute name="scale" value="0.83"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="dwell_secondary_vbox">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel" id="label16">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="xalign">0</property>
+ <property comments="Dwell Click = Clicking without hardware buttons (by letting the pointer sit on the click target for a certain amount of time)" name="label" translatable="yes">Dwell Click</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment10">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="top_padding">6</property>
+ <property name="left_padding">12</property>
+ <child>
+ <object class="GtkVBox" id="vbox4">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkCheckButton" id="dwell_enable">
+ <property name="label" translatable="yes">_Initiate click when stopping pointer movement</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment12">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="left_padding">12</property>
+ <child>
+ <object class="GtkVBox" id="dwell_box">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkTable" id="table4">
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">3</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="dwell_threshold_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Motion threshold:</property>
+ <property name="use_underline">True</property>
+ <property name="justify">center</property>
+ <property name="mnemonic_widget">threshold</property>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="dwell_delay_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">D_elay:</property>
+ <property name="use_underline">True</property>
+ <property name="justify">center</property>
+ <property name="mnemonic_widget">dwell_time</property>
+ </object>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox4">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="dwell_delay_short_label">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property comments="short delay" name="label" translatable="yes">Short</property>
+ <property name="justify">center</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ <attribute name="scale" value="0.83"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHScale" id="dwell_time">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="update_policy">discontinuous</property>
+ <property name="adjustment">adjustment6</property>
+ <property name="draw_value">False</property>
+ <property name="value_pos">right</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="dwell_delay_long_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property comments="long delay" name="label" translatable="yes">Long</property>
+ <property name="justify">center</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ <attribute name="scale" value="0.83"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox5">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="dwell_threshold_small_label">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property comments="small threshold" name="label" translatable="yes">Small</property>
+ <property name="justify">center</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ <attribute name="scale" value="0.83"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHScale" id="threshold">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="update_policy">discontinuous</property>
+ <property name="adjustment">adjustment7</property>
+ <property name="digits">0</property>
+ <property name="draw_value">False</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="dwell_threshold_large_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property comments="large threshold" name="label" translatable="yes">Large</property>
+ <property name="justify">center</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ <attribute name="scale" value="0.83"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox5">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkVBox" id="vbox9">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkRadioButton" id="dwell_mode_ctw">
+ <property name="label" translatable="yes">Choose type of click _beforehand</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="use_underline">True</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment14">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="left_padding">12</property>
+ <child>
+ <object class="GtkVBox" id="box_ctw">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkCheckButton" id="dwell_show_ctw">
+ <property name="label" translatable="yes">Show click type _window</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox2">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkImage" id="image1">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="stock">gtk-dialog-info</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label2">
+ <property name="width_request">320</property>
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="xalign">0</property>
+ <property comments="Dwell Click = Clicking without hardware buttons (by letting the pointer sit on the click target for a certain amount of time)" name="label" translatable="yes">You can also use the Dwell Click panel applet to choose the click type.</property>
+ <property name="wrap">True</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox13">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkRadioButton" id="dwell_mode_gesture">
+ <property name="label" translatable="yes">Choose type of click with mo_use gestures</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="use_underline">True</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">dwell_mode_ctw</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment13">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="left_padding">12</property>
+ <child>
+ <object class="GtkTable" id="box_gesture">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="n_rows">4</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkComboBox" id="dwell_gest_secondary">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBox" id="dwell_gest_drag">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBox" id="dwell_gest_double">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBox" id="dwell_gest_single">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label15">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Seco_ndary click:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">dwell_gest_secondary</property>
+ </object>
+ <packing>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label13">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="xalign">0</property>
+ <property comments="click to initiate drag-and-drop (like normally click and hold)" name="label" translatable="yes">D_rag click:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">dwell_gest_drag</property>
+ </object>
+ <packing>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label12">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">D_ouble click:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">dwell_gest_double</property>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label10">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Single click:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">dwell_gest_single</property>
+ </object>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Accessibility</property>
+ <property name="justify">center</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox3">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="border_width">12</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">18</property>
+ <child>
+ <object class="GtkVBox" id="vbox15">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label18">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0</property>
+ <property name="label" translatable="yes">General</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox6">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <child>
+ <object class="GtkLabel" id="label19">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0</property>
+ <property name="label"> </property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="disable_w_typing_toggle">
+ <property name="label" translatable="yes">Disable _touchpad while typing</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="use_underline">True</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox11">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <child>
+ <object class="GtkLabel" id="label22">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0</property>
+ <property name="label"> </property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="tap_to_click_toggle">
+ <property name="label" translatable="yes">Enable _mouse clicks with touchpad</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="use_underline">True</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox19">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label34">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0</property>
+ <property name="label" translatable="yes">Scrolling</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox15">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <child>
+ <object class="GtkLabel" id="label35">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0</property>
+ <property name="label"> </property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox23">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkRadioButton" id="scroll_disabled_radio">
+ <property name="label" translatable="yes">_Disabled</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="scroll_edge_radio">
+ <property name="label" translatable="yes">_Edge scrolling</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">scroll_disabled_radio</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="scroll_twofinger_radio">
+ <property name="label" translatable="yes">Two-_finger scrolling</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">scroll_disabled_radio</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox16">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <child>
+ <object class="GtkLabel" id="label36">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0</property>
+ <property name="label"> </property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="horiz_scroll_toggle">
+ <property name="label" translatable="yes">Enable h_orizontal scrolling</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Touchpad</property>
+ <property name="justify">center</property>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <object class="GtkHButtonBox" id="dialog-action_area1">
+ <property name="visible">True</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="helpbutton1">
+ <property name="label">gtk-help</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="closebutton1">
+ <property name="label">gtk-close</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-11">helpbutton1</action-widget>
+ <action-widget response="2">closebutton1</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/capplets/mouse/mate-settings-mouse.desktop.in.in b/capplets/mouse/mate-settings-mouse.desktop.in.in
new file mode 100644
index 00000000..5fca5e02
--- /dev/null
+++ b/capplets/mouse/mate-settings-mouse.desktop.in.in
@@ -0,0 +1,14 @@
+[Desktop Entry]
+_Name=Mouse
+_Comment=Set your mouse preferences
+Exec=mate-mouse-properties
+Icon=input-mouse
+Terminal=false
+Type=Application
+StartupNotify=true
+Categories=MATE;GTK;Settings;HardwareSettings;
+OnlyShowIn=MATE;
+X-MATE-Bugzilla-Bugzilla=MATE
+X-MATE-Bugzilla-Product=mate-control-center
+X-MATE-Bugzilla-Component=mouse
+X-MATE-Bugzilla-Version=@VERSION@
diff --git a/capplets/network/Makefile.am b/capplets/network/Makefile.am
new file mode 100644
index 00000000..823dfc48
--- /dev/null
+++ b/capplets/network/Makefile.am
@@ -0,0 +1,50 @@
+# This is used in MATECC_CAPPLETS_CFLAGS
+cappletname = network
+
+bin_PROGRAMS = mate-network-properties
+
+mate_network_properties_SOURCES = mate-network-properties.c
+mate_network_properties_LDADD = $(MATECC_CAPPLETS_LIBS)
+
+@INTLTOOL_DESKTOP_RULE@
+
+uidir = $(pkgdatadir)/ui
+dist_ui_DATA = mate-network-properties.ui
+
+icons16dir = $(datadir)/icons/hicolor/16x16/apps
+dist_icons16_DATA = icons/16x16/mate-network-properties.png
+icons22dir = $(datadir)/icons/hicolor/22x22/apps
+dist_icons22_DATA = icons/22x22/mate-network-properties.png
+icons24dir = $(datadir)/icons/hicolor/24x24/apps
+dist_icons24_DATA = icons/24x24/mate-network-properties.png
+icons32dir = $(datadir)/icons/hicolor/32x32/apps
+dist_icons32_DATA = icons/32x32/mate-network-properties.png
+icons48dir = $(datadir)/icons/hicolor/48x48/apps
+dist_icons48_DATA = icons/48x48/mate-network-properties.png
+iconssvgdir = $(datadir)/icons/hicolor/scalable/apps
+dist_iconssvg_DATA = icons/scalable/mate-network-properties.svg
+
+desktopdir = $(datadir)/applications
+desktop_in_files = mate-network-properties.desktop.in
+desktop_DATA = $(desktop_in_files:.desktop.in=.desktop)
+
+INCLUDES = \
+ $(MATECC_CAPPLETS_CFLAGS) \
+ -DMATELOCALEDIR="\"$(datadir)/locale\"" \
+ -DMATECC_UI_DIR="\"$(uidir)\""
+
+gtk_update_icon_cache = gtk-update-icon-cache -f -t $(datadir)/icons/hicolor
+uninstall-hook: update-icon-cache
+install-data-hook: update-icon-cache
+update-icon-cache:
+ @-if test -z "$(DESTDIR)"; then \
+ echo "Updating Gtk icon cache."; \
+ $(gtk_update_icon_cache); \
+ else \
+ echo "*** Icon cache not updated. After install, run this:"; \
+ echo "*** $(gtk_update_icon_cache)"; \
+ fi
+
+CLEANFILES = $(MATECC_CAPPLETS_CLEANFILES) $(desktop_in_files) $(desktop_DATA)
+
+-include $(top_srcdir)/git.mk
diff --git a/capplets/network/icons/16x16/mate-network-properties.png b/capplets/network/icons/16x16/mate-network-properties.png
new file mode 100644
index 00000000..ebacb983
--- /dev/null
+++ b/capplets/network/icons/16x16/mate-network-properties.png
Binary files differ
diff --git a/capplets/network/icons/22x22/mate-network-properties.png b/capplets/network/icons/22x22/mate-network-properties.png
new file mode 100644
index 00000000..a5fb9e01
--- /dev/null
+++ b/capplets/network/icons/22x22/mate-network-properties.png
Binary files differ
diff --git a/capplets/network/icons/24x24/mate-network-properties.png b/capplets/network/icons/24x24/mate-network-properties.png
new file mode 100644
index 00000000..e743c831
--- /dev/null
+++ b/capplets/network/icons/24x24/mate-network-properties.png
Binary files differ
diff --git a/capplets/network/icons/32x32/mate-network-properties.png b/capplets/network/icons/32x32/mate-network-properties.png
new file mode 100644
index 00000000..826d99d8
--- /dev/null
+++ b/capplets/network/icons/32x32/mate-network-properties.png
Binary files differ
diff --git a/capplets/network/icons/48x48/mate-network-properties.png b/capplets/network/icons/48x48/mate-network-properties.png
new file mode 100644
index 00000000..e3a4ce28
--- /dev/null
+++ b/capplets/network/icons/48x48/mate-network-properties.png
Binary files differ
diff --git a/capplets/network/icons/scalable/mate-network-properties.svg b/capplets/network/icons/scalable/mate-network-properties.svg
new file mode 100644
index 00000000..71ef6762
--- /dev/null
+++ b/capplets/network/icons/scalable/mate-network-properties.svg
@@ -0,0 +1,628 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="48px"
+ height="48px"
+ id="svg7195"
+ sodipodi:version="0.32"
+ inkscape:version="0.45+devel"
+ sodipodi:docbase="/home/cornelius/Desktop"
+ sodipodi:docname="network-proxy-48.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ inkscape:export-filename="/home/cornelius/Desktop/network-proxy-48.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90">
+ <defs
+ id="defs7197">
+ <linearGradient
+ id="linearGradient5466"
+ inkscape:collect="always">
+ <stop
+ id="stop5468"
+ offset="0"
+ style="stop-color:#555753;stop-opacity:1" />
+ <stop
+ id="stop5470"
+ offset="1"
+ style="stop-color:#888a85;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5466"
+ id="linearGradient5538"
+ gradientUnits="userSpaceOnUse"
+ x1="37.870998"
+ y1="12.5"
+ x2="47.965992"
+ y2="13.076671"
+ gradientTransform="translate(-1,0)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient6393"
+ id="linearGradient5540"
+ gradientUnits="userSpaceOnUse"
+ x1="38.520752"
+ y1="12.5"
+ x2="47.863831"
+ y2="12.5"
+ gradientTransform="translate(-1,0)" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5060"
+ id="radialGradient5546"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-2.751545,0,0,1.969706,92.22831,-876.5339)"
+ cx="602.66046"
+ cy="488.07956"
+ fx="602.66046"
+ fy="488.07956"
+ r="117.14286" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient5060">
+ <stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0"
+ id="stop5062" />
+ <stop
+ style="stop-color:black;stop-opacity:0;"
+ offset="1"
+ id="stop5064" />
+ </linearGradient>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5060"
+ id="radialGradient5544"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(2.7515457,0,0,1.969706,-1568.5757,-873.7569)"
+ cx="605.71429"
+ cy="486.64789"
+ fx="605.71429"
+ fy="486.64789"
+ r="117.14286" />
+ <linearGradient
+ id="linearGradient5048">
+ <stop
+ style="stop-color:black;stop-opacity:0;"
+ offset="0"
+ id="stop5050" />
+ <stop
+ id="stop5056"
+ offset="0.5"
+ style="stop-color:black;stop-opacity:1;" />
+ <stop
+ style="stop-color:black;stop-opacity:0;"
+ offset="1"
+ id="stop5052" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5048"
+ id="linearGradient5542"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(3.4289406,0,0,1.969706,-1977.4912,-872.8854)"
+ x1="302.85715"
+ y1="366.64789"
+ x2="302.85715"
+ y2="609.50507" />
+ <linearGradient
+ id="linearGradient5459"
+ inkscape:collect="always">
+ <stop
+ id="stop5461"
+ offset="0"
+ style="stop-color:#555753;stop-opacity:1" />
+ <stop
+ id="stop5463"
+ offset="1"
+ style="stop-color:#888a85;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5459"
+ id="linearGradient5548"
+ gradientUnits="userSpaceOnUse"
+ x1="24.399277"
+ y1="35.275932"
+ x2="31.843159"
+ y2="47.757107"
+ gradientTransform="translate(-1,0)" />
+ <linearGradient
+ id="linearGradient5429"
+ inkscape:collect="always">
+ <stop
+ id="stop5431"
+ offset="0"
+ style="stop-color:#555753;stop-opacity:1" />
+ <stop
+ id="stop5433"
+ offset="1"
+ style="stop-color:#888a85;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5429"
+ id="linearGradient5550"
+ gradientUnits="userSpaceOnUse"
+ x1="24.399277"
+ y1="35.275932"
+ x2="44.067654"
+ y2="47.80442"
+ gradientTransform="translate(-1,0)" />
+ <linearGradient
+ id="linearGradient5423"
+ inkscape:collect="always">
+ <stop
+ id="stop5425"
+ offset="0"
+ style="stop-color:#555753;stop-opacity:1" />
+ <stop
+ id="stop5427"
+ offset="1"
+ style="stop-color:#888a85;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5423"
+ id="linearGradient5552"
+ gradientUnits="userSpaceOnUse"
+ x1="24.399277"
+ y1="35.275932"
+ x2="50"
+ y2="41.644268"
+ gradientTransform="translate(-1,0)" />
+ <linearGradient
+ id="linearGradient5447"
+ inkscape:collect="always">
+ <stop
+ id="stop5449"
+ offset="0"
+ style="stop-color:#555753;stop-opacity:1" />
+ <stop
+ id="stop5451"
+ offset="1"
+ style="stop-color:#888a85;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5447"
+ id="linearGradient5554"
+ gradientUnits="userSpaceOnUse"
+ x1="24.399277"
+ y1="35.275932"
+ x2="17.209641"
+ y2="47.548927"
+ gradientTransform="translate(-1,0)" />
+ <linearGradient
+ id="linearGradient5441"
+ inkscape:collect="always">
+ <stop
+ id="stop5443"
+ offset="0"
+ style="stop-color:#555753;stop-opacity:1" />
+ <stop
+ id="stop5445"
+ offset="1"
+ style="stop-color:#888a85;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5441"
+ id="linearGradient5556"
+ gradientUnits="userSpaceOnUse"
+ x1="24.399277"
+ y1="35.275932"
+ x2="6.1469398"
+ y2="46.668907"
+ gradientTransform="translate(-1,0)" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient6294">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1"
+ offset="0"
+ id="stop6296" />
+ <stop
+ style="stop-color:#eeeeec;stop-opacity:1"
+ offset="1"
+ id="stop6298" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient6294"
+ id="linearGradient5558"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.375,0,0,1.2857143,-10.1875,-3.2857142)"
+ x1="26.820854"
+ y1="5.9706759"
+ x2="26.820854"
+ y2="12.407513" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient6427">
+ <stop
+ style="stop-color:#d3d7cf;stop-opacity:1;"
+ offset="0"
+ id="stop6429" />
+ <stop
+ style="stop-color:#d3d7cf;stop-opacity:0;"
+ offset="1"
+ id="stop6431" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient6427"
+ id="linearGradient5560"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(-1,1)"
+ x1="41.570694"
+ y1="32.504398"
+ x2="18.827377"
+ y2="6" />
+ <linearGradient
+ id="linearGradient5435"
+ inkscape:collect="always">
+ <stop
+ id="stop5437"
+ offset="0"
+ style="stop-color:#555753;stop-opacity:1" />
+ <stop
+ id="stop5439"
+ offset="1"
+ style="stop-color:#888a85;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5435"
+ id="linearGradient5562"
+ gradientUnits="userSpaceOnUse"
+ x1="22.280706"
+ y1="35"
+ x2="2.1575336"
+ y2="41.171135"
+ gradientTransform="translate(-1,0)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient6393"
+ id="linearGradient5564"
+ gradientUnits="userSpaceOnUse"
+ x1="27.060818"
+ y1="36.950813"
+ x2="43.95985"
+ y2="47.034103"
+ gradientTransform="translate(-1,0)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient6393"
+ id="linearGradient5566"
+ gradientUnits="userSpaceOnUse"
+ x1="24.408333"
+ y1="35.758526"
+ x2="-0.58516204"
+ y2="42"
+ gradientTransform="translate(-1,0)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient6393"
+ id="linearGradient5568"
+ gradientUnits="userSpaceOnUse"
+ x1="24.408333"
+ y1="35.758526"
+ x2="6.735868"
+ y2="46.911091"
+ gradientTransform="translate(-1,0)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient6393"
+ id="linearGradient5570"
+ gradientUnits="userSpaceOnUse"
+ x1="25.702541"
+ y1="38.042225"
+ x2="32.307709"
+ y2="48.084454"
+ gradientTransform="translate(-1,0)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient6393"
+ id="linearGradient5572"
+ gradientUnits="userSpaceOnUse"
+ x1="24.408333"
+ y1="35.758526"
+ x2="16.728512"
+ y2="48.084454"
+ gradientTransform="translate(-1,0)" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient6393">
+ <stop
+ style="stop-color:#eeeeec;stop-opacity:1;"
+ offset="0"
+ id="stop6395" />
+ <stop
+ style="stop-color:#eeeeec;stop-opacity:0;"
+ offset="1"
+ id="stop6397" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient6393"
+ id="linearGradient5574"
+ gradientUnits="userSpaceOnUse"
+ x1="27.727142"
+ y1="35"
+ x2="49"
+ y2="41.063202"
+ gradientTransform="translate(-1,0)" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="7"
+ inkscape:cx="24"
+ inkscape:cy="24"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ inkscape:grid-bbox="true"
+ inkscape:document-units="px"
+ inkscape:window-width="872"
+ inkscape:window-height="623"
+ inkscape:window-x="0"
+ inkscape:window-y="26" />
+ <metadata
+ id="metadata7200">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title>Network proxy</dc:title>
+ <dc:date>16.02.2007</dc:date>
+ <dc:creator>
+ <cc:Agent>
+ <dc:title>Josef Vybíral</dc:title>
+ </cc:Agent>
+ </dc:creator>
+ <dc:rights>
+ <cc:Agent>
+ <dc:title>Josef Vybíral</dc:title>
+ </cc:Agent>
+ </dc:rights>
+ <dc:source>http://blog.vybiral.info</dc:source>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>network</rdf:li>
+ <rdf:li>proxy</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:contributor>
+ <cc:Agent>
+ <dc:title>Jakub Steiner</dc:title>
+ </cc:Agent>
+ </dc:contributor>
+ <cc:license
+ rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" />
+ </cc:Work>
+ <cc:License
+ rdf:about="http://creativecommons.org/licenses/GPL/2.0/">
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Reproduction" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Distribution" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/Notice" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/ShareAlike" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/SourceCode" />
+ </cc:License>
+ </rdf:RDF>
+ </metadata>
+ <g
+ id="layer1"
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer">
+ <path
+ style="opacity:1;color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient5538);stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="M 37.0038,12.5 L 47.0038,12.5"
+ id="path5472" />
+ <path
+ id="path5474"
+ d="M 37.0038,12.5 L 47.0038,12.5"
+ style="opacity:1;color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient5540);stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+ <rect
+ ry="0.5064261"
+ rx="0.5064261"
+ y="9.5"
+ x="34.5"
+ height="6"
+ width="2.0000012"
+ id="rect5476"
+ style="opacity:1;color:#000000;fill:#729fcf;fill-opacity:1;fill-rule:evenodd;stroke:#3465a4;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+ <g
+ style="opacity:0.31004363;display:inline"
+ transform="matrix(-1.2388921e-2,0,0,1.6597884e-2,14.35481,26.561532)"
+ id="g5478">
+ <rect
+ style="opacity:0.40206185;color:#000000;fill:url(#linearGradient5542);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ id="rect5480"
+ width="1655.6886"
+ height="478.35718"
+ x="-1566.019"
+ y="-150.69685" />
+ <path
+ style="opacity:0.40206185;color:#000000;fill:url(#radialGradient5544);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 89.669502,-151.55183 C 89.669502,-151.55183 89.669502,326.77896 89.669502,326.77896 C 231.36729,327.67941 432.22584,219.6093 432.22576,87.582782 C 432.22576,-44.443755 274.10167,-151.55181 89.669502,-151.55183 z"
+ id="path5482"
+ sodipodi:nodetypes="cccc" />
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path5484"
+ d="M -1566.0191,-154.32884 C -1566.0191,-154.32884 -1566.0191,324.00195 -1566.0191,324.00195 C -1707.7169,324.9024 -1908.5753,216.83229 -1908.5753,84.805778 C -1908.5753,-47.220759 -1750.4513,-154.32882 -1566.0191,-154.32884 z"
+ style="opacity:0.40206185;color:#000000;fill:url(#radialGradient5546);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ </g>
+ <path
+ sodipodi:nodetypes="ccc"
+ id="path5486"
+ d="M 23.53622,24.5 L 23.53622,35.5 L 30.80771,47.584452"
+ style="opacity:1;color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient5548);stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+ <path
+ style="opacity:1;color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient5550);stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="M 23.53622,24.5 L 23.53622,35.5 L 42.48548,47.385737"
+ id="path5488"
+ sodipodi:nodetypes="ccc" />
+ <path
+ sodipodi:nodetypes="ccc"
+ id="path5490"
+ d="M 23.53622,24.5 L 23.53622,34.5 L 47.5,41.5"
+ style="opacity:1;color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient5552);stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+ <path
+ style="opacity:1;color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient5554);stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="M 23.5,24.5 L 23.5,35.5 L 16.22851,47.584452"
+ id="path5492"
+ sodipodi:nodetypes="ccc" />
+ <path
+ sodipodi:nodetypes="ccc"
+ id="path5494"
+ d="M 23.5,24.5 L 23.5,35.5 L 4.55074,47.385737"
+ style="opacity:1;color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient5556);stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+ <path
+ sodipodi:nodetypes="ccccccccc"
+ id="path5496"
+ d="M 15.09302,2.5000001 L 31.90698,2.5000001 L 34.5,6.2103543 L 34.5,28.313413 C 34.5,28.944378 33.95677,29.500001 33.28198,29.500001 L 13.71802,29.500001 C 13.04323,29.500001 12.5,28.992041 12.5,28.361076 L 12.5,6.2103543 L 15.09302,2.5000001 z"
+ style="color:#000000;fill:url(#linearGradient5558);fill-opacity:1;fill-rule:evenodd;stroke:#555753;stroke-width:1.00000024px;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+ <rect
+ ry="1"
+ rx="1"
+ y="7"
+ x="15"
+ height="20"
+ width="17"
+ id="rect5498"
+ style="opacity:0.83842797;color:#000000;fill:url(#linearGradient5560);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+ <path
+ style="color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000024px;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="M 15.53595,3.5 L 31.46767,3.5 L 33.5,6.4892262 L 33.5,27.777117 C 33.5,28.42284 33.44002,28.499987 32.73895,28.499987 L 14.34783,28.499987 C 13.64676,28.499987 13.5,28.51138 13.5,27.865657 L 13.5,6.4892262 L 15.53595,3.5 z"
+ id="path5500"
+ sodipodi:nodetypes="ccccccccc" />
+ <path
+ transform="matrix(-1.4831624,0,0,1.5007696,54.7879,-9.838124)"
+ d="M 23.070641,24.879318 A 1.9989744,1.9989744 0 1 1 19.072692,24.879318 A 1.9989744,1.9989744 0 1 1 23.070641,24.879318 z"
+ sodipodi:ry="1.9989744"
+ sodipodi:rx="1.9989744"
+ sodipodi:cy="24.879318"
+ sodipodi:cx="21.071667"
+ id="path5502"
+ style="color:#000000;fill:#ad7fa8;fill-opacity:1;fill-rule:evenodd;stroke:#5c3566;stroke-width:0.67026824px;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ sodipodi:type="arc" />
+ <path
+ sodipodi:type="arc"
+ style="color:#000000;fill:#ad7fa8;fill-opacity:1;fill-rule:evenodd;stroke:#5c3566;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="path5504"
+ sodipodi:cx="21.071667"
+ sodipodi:cy="24.879318"
+ sodipodi:rx="1.9989744"
+ sodipodi:ry="1.9989744"
+ d="M 23.070641,24.879318 A 1.9989744,1.9989744 0 1 1 19.072692,24.879318 A 1.9989744,1.9989744 0 1 1 23.070641,24.879318 z"
+ transform="matrix(-1,0,0,1,44.60686,3.6196562)" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:url(#linearGradient5562);stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 23.5,28.5 L 23.5,34.5 L -0.46378,41.5"
+ id="path5506"
+ sodipodi:nodetypes="ccc" />
+ <path
+ sodipodi:nodetypes="ccc"
+ id="path5508"
+ d="M 23.53622,28.5 L 23.53622,35.5 L 42.45985,47.518214"
+ style="opacity:1;color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient5564);stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+ <path
+ sodipodi:nodetypes="ccc"
+ id="path5510"
+ d="M 23.5,28.5 L 23.5,34.5 L -0.46378,41.5"
+ style="fill:none;fill-rule:evenodd;stroke:url(#linearGradient5566);stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ style="opacity:1;color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient5568);stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="M 23.5,28.5 L 23.5,35.5 L 4.57637,47.518214"
+ id="path5512"
+ sodipodi:nodetypes="ccc" />
+ <path
+ style="opacity:1;color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient5570);stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="M 23.53622,28.5 L 23.53622,35.5 L 30.80771,47.584452"
+ id="path5514"
+ sodipodi:nodetypes="ccc" />
+ <path
+ sodipodi:nodetypes="ccc"
+ id="path5516"
+ d="M 23.5,28.5 C 23.5,31.25 23.5,35.5 23.5,35.5 L 16.22851,47.584452"
+ style="opacity:1;color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient5572);stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+ <path
+ style="opacity:1;color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient5574);stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="M 23.53622,28.5 L 23.53622,34.5 L 47.5,41.5"
+ id="path5518"
+ sodipodi:nodetypes="ccc" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path5520"
+ d="M 17.5,12.5 L 29.5,12.5"
+ style="fill:none;fill-rule:evenodd;stroke:#babdb6;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#babdb6;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 17.5,14.5 L 29.5,14.5"
+ id="path5522"
+ sodipodi:nodetypes="cc" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path5524"
+ d="M 17.5,16.5 L 29.5,16.5"
+ style="fill:none;fill-rule:evenodd;stroke:#babdb6;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#babdb6;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 17.5,18.5 L 29.5,18.5"
+ id="path5526"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 17.5,13.5 L 29.5,13.5"
+ id="path5528"
+ sodipodi:nodetypes="cc" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path5530"
+ d="M 17.5,15.5 L 29.5,15.5"
+ style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 17.5,17.5 L 29.5,17.5"
+ id="path5532"
+ sodipodi:nodetypes="cc" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path5534"
+ d="M 17.5,19.5 L 29.5,19.5"
+ style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <path
+ transform="matrix(0.7916045,0,0,0.7916044,2.47836,5.9823878)"
+ d="M 18.976194,24.655764 A 1.2632571,1.2632571 0 1 1 16.449679,24.655764 A 1.2632571,1.2632571 0 1 1 18.976194,24.655764 z"
+ sodipodi:ry="1.2632571"
+ sodipodi:rx="1.2632571"
+ sodipodi:cy="24.655764"
+ sodipodi:cx="17.712936"
+ id="path5536"
+ style="opacity:0.83842797;color:#000000;fill:#73d216;fill-opacity:1;fill-rule:evenodd;stroke:#4e9a06;stroke-width:1.26325715;stroke-linecap:square;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ sodipodi:type="arc" />
+ </g>
+</svg>
diff --git a/capplets/network/mate-network-properties.c b/capplets/network/mate-network-properties.c
new file mode 100644
index 00000000..3fcc04dc
--- /dev/null
+++ b/capplets/network/mate-network-properties.c
@@ -0,0 +1,1397 @@
+/* mate-network-properties.c: network preferences capplet
+ *
+ * Copyright (C) 2002 Sun Microsystems Inc.
+ *
+ * Written by: Mark McLoughlin <[email protected]>
+ *
+ * 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, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <mateconf/mateconf-client.h>
+#include <glib/gi18n.h>
+
+#include "capplet-util.h"
+#include "mateconf-property-editor.h"
+
+enum ProxyMode
+{
+ PROXYMODE_NONE,
+ PROXYMODE_MANUAL,
+ PROXYMODE_AUTO
+};
+
+static GEnumValue proxytype_values[] = {
+ { PROXYMODE_NONE, "PROXYMODE_NONE", "none"},
+ { PROXYMODE_MANUAL, "PROXYMODE_MANUAL", "manual"},
+ { PROXYMODE_AUTO, "PROXYMODE_AUTO", "auto"},
+ { 0, NULL, NULL }
+};
+
+enum {
+ COL_NAME,
+ COL_STYLE
+};
+
+#define USE_PROXY_KEY "/system/http_proxy/use_http_proxy"
+#define USE_SAME_PROXY_KEY "/system/http_proxy/use_same_proxy"
+#define HTTP_PROXY_HOST_KEY "/system/http_proxy/host"
+#define HTTP_PROXY_PORT_KEY "/system/http_proxy/port"
+#define HTTP_USE_AUTH_KEY "/system/http_proxy/use_authentication"
+#define HTTP_AUTH_USER_KEY "/system/http_proxy/authentication_user"
+#define HTTP_AUTH_PASSWD_KEY "/system/http_proxy/authentication_password"
+#define IGNORE_HOSTS_KEY "/system/http_proxy/ignore_hosts"
+#define PROXY_MODE_KEY "/system/proxy/mode"
+#define SECURE_PROXY_HOST_KEY "/system/proxy/secure_host"
+#define OLD_SECURE_PROXY_HOST_KEY "/system/proxy/old_secure_host"
+#define SECURE_PROXY_PORT_KEY "/system/proxy/secure_port"
+#define OLD_SECURE_PROXY_PORT_KEY "/system/proxy/old_secure_port"
+#define FTP_PROXY_HOST_KEY "/system/proxy/ftp_host"
+#define OLD_FTP_PROXY_HOST_KEY "/system/proxy/old_ftp_host"
+#define FTP_PROXY_PORT_KEY "/system/proxy/ftp_port"
+#define OLD_FTP_PROXY_PORT_KEY "/system/proxy/old_ftp_port"
+#define SOCKS_PROXY_HOST_KEY "/system/proxy/socks_host"
+#define OLD_SOCKS_PROXY_HOST_KEY "/system/proxy/old_socks_host"
+#define SOCKS_PROXY_PORT_KEY "/system/proxy/socks_port"
+#define OLD_SOCKS_PROXY_PORT_KEY "/system/proxy/old_socks_port"
+#define PROXY_AUTOCONFIG_URL_KEY "/system/proxy/autoconfig_url"
+
+#define LOCATION_DIR "/apps/control-center/network"
+#define CURRENT_LOCATION "/apps/control-center/network/current_location"
+
+#define MATECC_GNP_UI_FILE (MATECC_UI_DIR "/mate-network-properties.ui")
+
+static GtkWidget *details_dialog = NULL;
+static GSList *ignore_hosts = NULL;
+static GtkTreeModel *model = NULL;
+
+static GtkTreeModel *
+create_listmodel(void)
+{
+ GtkListStore *store;
+
+ store = gtk_list_store_new(1, G_TYPE_STRING);
+
+ return GTK_TREE_MODEL(store);
+}
+
+static GtkTreeModel *
+populate_listmodel(GtkListStore *store, GSList *list)
+{
+ GtkTreeIter iter;
+ GSList *pointer;
+
+ gtk_list_store_clear(store);
+
+ pointer = list;
+ while(pointer)
+ {
+ gtk_list_store_append(store, &iter);
+ gtk_list_store_set(store, &iter, 0, (char *) pointer->data, -1);
+ pointer = g_slist_next(pointer);
+ }
+
+ return GTK_TREE_MODEL(store);
+}
+
+static GtkWidget *
+config_treeview(GtkTreeView *tree, GtkTreeModel *model)
+{
+ GtkCellRenderer *renderer;
+
+ renderer = gtk_cell_renderer_text_new();
+ gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(tree),
+ -1, "Hosts", renderer,
+ "text", 0, NULL);
+
+ gtk_tree_view_set_model(GTK_TREE_VIEW(tree), model);
+
+ return GTK_WIDGET(tree);
+}
+
+static GtkWidget*
+_gtk_builder_get_widget (GtkBuilder *builder, const gchar *name)
+{
+ return GTK_WIDGET (gtk_builder_get_object (builder, name));
+}
+
+
+static void
+cb_add_url (GtkButton *button, gpointer data)
+{
+ GtkBuilder *builder = GTK_BUILDER (data);
+ gchar *new_url = NULL;
+ MateConfClient *client;
+
+ new_url = g_strdup (gtk_entry_get_text (GTK_ENTRY (gtk_builder_get_object (builder, "entry_url"))));
+ if (strlen (new_url) == 0)
+ return;
+ ignore_hosts = g_slist_append(ignore_hosts, new_url);
+ populate_listmodel(GTK_LIST_STORE(model), ignore_hosts);
+ gtk_entry_set_text(GTK_ENTRY (gtk_builder_get_object (builder,
+ "entry_url")), "");
+
+ client = mateconf_client_get_default ();
+ mateconf_client_set_list (client, IGNORE_HOSTS_KEY, MATECONF_VALUE_STRING, ignore_hosts, NULL);
+ g_object_unref (client);
+}
+
+static void
+cb_remove_url (GtkButton *button, gpointer data)
+{
+ GtkBuilder *builder = GTK_BUILDER (data);
+ GtkTreeSelection *selection;
+ GtkTreeIter iter;
+ MateConfClient *client;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (gtk_builder_get_object (builder, "treeview_ignore_host")));
+ if (gtk_tree_selection_get_selected(selection, &model, &iter))
+ {
+ gchar *url;
+ GSList *pointer;
+
+ gtk_tree_model_get (model, &iter, 0, &url, -1);
+
+ pointer = ignore_hosts;
+ while(pointer)
+ {
+ if(strcmp(url, (char *) pointer->data) == 0)
+ {
+ g_free (pointer->data);
+ ignore_hosts = g_slist_delete_link(ignore_hosts, pointer);
+ break;
+ }
+ pointer = g_slist_next(pointer);
+ }
+
+ g_free(url);
+ populate_listmodel(GTK_LIST_STORE(model), ignore_hosts);
+
+ client = mateconf_client_get_default ();
+ mateconf_client_set_list(client, IGNORE_HOSTS_KEY, MATECONF_VALUE_STRING, ignore_hosts, NULL);
+ g_object_unref (client);
+ }
+}
+
+static void
+cb_dialog_response (GtkDialog *dialog, gint response_id)
+{
+ if (response_id == GTK_RESPONSE_HELP)
+ capplet_help (GTK_WINDOW (dialog),
+ "goscustdesk-50");
+ else if (response_id == GTK_RESPONSE_CLOSE || response_id == GTK_RESPONSE_DELETE_EVENT)
+ {
+ if (ignore_hosts) {
+ g_slist_foreach (ignore_hosts, (GFunc) g_free, NULL);
+ g_slist_free (ignore_hosts);
+ }
+
+ gtk_main_quit ();
+ }
+}
+
+static void
+cb_details_dialog_response (GtkDialog *dialog, gint response_id)
+{
+ if (response_id == GTK_RESPONSE_HELP)
+ capplet_help (GTK_WINDOW (dialog),
+ "goscustdesk-50");
+ else {
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+ details_dialog = NULL;
+ }
+}
+
+static void
+cb_use_auth_toggled (GtkToggleButton *toggle,
+ GtkWidget *table)
+{
+ gtk_widget_set_sensitive (table, gtk_toggle_button_get_active (toggle));
+}
+
+static void
+cb_http_details_button_clicked (GtkWidget *button,
+ GtkWidget *parent)
+{
+ GtkBuilder *builder;
+ gchar *builder_widgets[] = { "details_dialog", NULL };
+ GError *error = NULL;
+ GtkWidget *widget;
+ MateConfPropertyEditor *peditor;
+
+ if (details_dialog != NULL) {
+ gtk_window_present (GTK_WINDOW (details_dialog));
+ gtk_widget_grab_focus (details_dialog);
+ return;
+ }
+
+ builder = gtk_builder_new ();
+ if (gtk_builder_add_objects_from_file (builder, MATECC_GNP_UI_FILE,
+ builder_widgets, &error) == 0) {
+ g_warning ("Could not load details dialog: %s", error->message);
+ g_error_free (error);
+ g_object_unref (builder);
+ return;
+ }
+
+ details_dialog = widget = _gtk_builder_get_widget (builder,
+ "details_dialog");
+
+ gtk_window_set_transient_for (GTK_WINDOW (widget), GTK_WINDOW (parent));
+
+ g_signal_connect (gtk_builder_get_object (builder, "use_auth_checkbutton"),
+ "toggled",
+ G_CALLBACK (cb_use_auth_toggled),
+ _gtk_builder_get_widget (builder, "auth_table"));
+
+ peditor = MATECONF_PROPERTY_EDITOR (mateconf_peditor_new_boolean (
+ NULL, HTTP_USE_AUTH_KEY,
+ _gtk_builder_get_widget (builder, "use_auth_checkbutton"),
+ NULL));
+ peditor = MATECONF_PROPERTY_EDITOR (mateconf_peditor_new_string (
+ NULL, HTTP_AUTH_USER_KEY,
+ _gtk_builder_get_widget (builder, "username_entry"),
+ NULL));
+ peditor = MATECONF_PROPERTY_EDITOR (mateconf_peditor_new_string (
+ NULL, HTTP_AUTH_PASSWD_KEY,
+ _gtk_builder_get_widget (builder, "password_entry"),
+ NULL));
+
+ g_signal_connect (widget, "response",
+ G_CALLBACK (cb_details_dialog_response), NULL);
+
+ capplet_set_icon (widget, "mate-network-properties");
+
+ gtk_widget_show_all (widget);
+}
+
+static gchar *
+copy_location_create_key (const gchar *from, const gchar *what)
+{
+ if (from[0] == '\0') return g_strdup (what);
+ else return g_strconcat (from, what + strlen ("/system"), NULL);
+}
+
+static void
+copy_location (const gchar *from, const gchar *to, MateConfClient *client)
+{
+ int ti;
+ gboolean tb;
+ GSList *tl;
+ gchar *tstr, *dest, *src;
+
+ if (from[0] != '\0' && !mateconf_client_dir_exists (client, from, NULL))
+ return;
+
+ /* USE_PROXY */
+ dest = copy_location_create_key (to, USE_PROXY_KEY);
+ src = copy_location_create_key (from, USE_PROXY_KEY);
+
+ tb = mateconf_client_get_bool (client, src, NULL);
+ mateconf_client_set_bool (client, dest, tb, NULL);
+
+ g_free (dest);
+ g_free (src);
+
+ /* USE_SAME_PROXY */
+ dest = copy_location_create_key (to, USE_SAME_PROXY_KEY);
+ src = copy_location_create_key (from, USE_SAME_PROXY_KEY);
+
+ tb = mateconf_client_get_bool (client, src, NULL);
+ mateconf_client_set_bool (client, dest, tb, NULL);
+
+ g_free (dest);
+ g_free (src);
+
+ /* HTTP_PROXY_HOST */
+ dest = copy_location_create_key (to, HTTP_PROXY_HOST_KEY);
+ src = copy_location_create_key (from, HTTP_PROXY_HOST_KEY);
+
+ tstr = mateconf_client_get_string (client, src, NULL);
+ if (tstr != NULL)
+ {
+ mateconf_client_set_string (client, dest, tstr, NULL);
+ g_free (tstr);
+ }
+
+ g_free (dest);
+ g_free (src);
+
+ /* HTTP_PROXY_PORT */
+ dest = copy_location_create_key (to, HTTP_PROXY_PORT_KEY);
+ src = copy_location_create_key (from, HTTP_PROXY_PORT_KEY);
+
+ ti = mateconf_client_get_int (client, src, NULL);
+ mateconf_client_set_int (client, dest, ti, NULL);
+
+ g_free (dest);
+ g_free (src);
+
+ /* HTTP_USE_AUTH */
+ dest = copy_location_create_key (to, HTTP_USE_AUTH_KEY);
+ src = copy_location_create_key (from, HTTP_USE_AUTH_KEY);
+
+ tb = mateconf_client_get_bool (client, src, NULL);
+ mateconf_client_set_bool (client, dest, tb, NULL);
+
+ g_free (dest);
+ g_free (src);
+
+ /* HTTP_AUTH_USER */
+ dest = copy_location_create_key (to, HTTP_AUTH_USER_KEY);
+ src = copy_location_create_key (from, HTTP_AUTH_USER_KEY);
+
+ tstr = mateconf_client_get_string (client, src, NULL);
+ if (tstr != NULL)
+ {
+ mateconf_client_set_string (client, dest, tstr, NULL);
+ g_free (tstr);
+ }
+
+ g_free (dest);
+ g_free (src);
+
+ /* HTTP_AUTH_PASSWD */
+ dest = copy_location_create_key (to, HTTP_AUTH_PASSWD_KEY);
+ src = copy_location_create_key (from, HTTP_AUTH_PASSWD_KEY);
+
+ tstr = mateconf_client_get_string (client, src, NULL);
+ if (tstr != NULL)
+ {
+ mateconf_client_set_string (client, dest, tstr, NULL);
+ g_free (tstr);
+ }
+
+ g_free (dest);
+ g_free (src);
+
+ /* IGNORE_HOSTS */
+ dest = copy_location_create_key (to, IGNORE_HOSTS_KEY);
+ src = copy_location_create_key (from, IGNORE_HOSTS_KEY);
+
+ tl = mateconf_client_get_list (client, src, MATECONF_VALUE_STRING, NULL);
+ mateconf_client_set_list (client, dest, MATECONF_VALUE_STRING, tl, NULL);
+ g_slist_foreach (tl, (GFunc) g_free, NULL);
+ g_slist_free (tl);
+
+ g_free (dest);
+ g_free (src);
+
+ /* PROXY_MODE */
+ dest = copy_location_create_key (to, PROXY_MODE_KEY);
+ src = copy_location_create_key (from, PROXY_MODE_KEY);
+
+ tstr = mateconf_client_get_string (client, src, NULL);
+ if (tstr != NULL)
+ {
+ mateconf_client_set_string (client, dest, tstr, NULL);
+ g_free (tstr);
+ }
+
+ g_free (dest);
+ g_free (src);
+
+ /* SECURE_PROXY_HOST */
+ dest = copy_location_create_key (to, SECURE_PROXY_HOST_KEY);
+ src = copy_location_create_key (from, SECURE_PROXY_HOST_KEY);
+
+ tstr = mateconf_client_get_string (client, src, NULL);
+ if (tstr != NULL)
+ {
+ mateconf_client_set_string (client, dest, tstr, NULL);
+ g_free (tstr);
+ }
+
+ g_free (dest);
+ g_free (src);
+
+ /* OLD_SECURE_PROXY_HOST */
+ dest = copy_location_create_key (to, OLD_SECURE_PROXY_HOST_KEY);
+ src = copy_location_create_key (from, OLD_SECURE_PROXY_HOST_KEY);
+
+ tstr = mateconf_client_get_string (client, src, NULL);
+ if (tstr != NULL)
+ {
+ mateconf_client_set_string (client, dest, tstr, NULL);
+ g_free (tstr);
+ }
+
+ g_free (dest);
+ g_free (src);
+
+ /* SECURE_PROXY_PORT */
+ dest = copy_location_create_key (to, SECURE_PROXY_PORT_KEY);
+ src = copy_location_create_key (from, SECURE_PROXY_PORT_KEY);
+
+ ti = mateconf_client_get_int (client, src, NULL);
+ mateconf_client_set_int (client, dest, ti, NULL);
+
+ g_free (dest);
+ g_free (src);
+
+ /* OLD_SECURE_PROXY_PORT */
+ dest = copy_location_create_key (to, OLD_SECURE_PROXY_PORT_KEY);
+ src = copy_location_create_key (from, OLD_SECURE_PROXY_PORT_KEY);
+
+ ti = mateconf_client_get_int (client, src, NULL);
+ mateconf_client_set_int (client, dest, ti, NULL);
+
+ g_free (dest);
+ g_free (src);
+
+ /* FTP_PROXY_HOST */
+ dest = copy_location_create_key (to, FTP_PROXY_HOST_KEY);
+ src = copy_location_create_key (from, FTP_PROXY_HOST_KEY);
+
+ tstr = mateconf_client_get_string (client, src, NULL);
+ if (tstr != NULL)
+ {
+ mateconf_client_set_string (client, dest, tstr, NULL);
+ g_free (tstr);
+ }
+
+ g_free (dest);
+ g_free (src);
+
+ /* OLD_FTP_PROXY_HOST */
+ dest = copy_location_create_key (to, OLD_FTP_PROXY_HOST_KEY);
+ src = copy_location_create_key (from, OLD_FTP_PROXY_HOST_KEY);
+
+ tstr = mateconf_client_get_string (client, src, NULL);
+ if (tstr != NULL)
+ {
+ mateconf_client_set_string (client, dest, tstr, NULL);
+ g_free (tstr);
+ }
+
+ g_free (dest);
+ g_free (src);
+
+ /* FTP_PROXY_PORT */
+ dest = copy_location_create_key (to, FTP_PROXY_PORT_KEY);
+ src = copy_location_create_key (from, FTP_PROXY_PORT_KEY);
+
+ ti = mateconf_client_get_int (client, src, NULL);
+ mateconf_client_set_int (client, dest, ti, NULL);
+
+ g_free (dest);
+ g_free (src);
+
+ /* OLD_FTP_PROXY_PORT */
+ dest = copy_location_create_key (to, OLD_FTP_PROXY_PORT_KEY);
+ src = copy_location_create_key (from, OLD_FTP_PROXY_PORT_KEY);
+
+ ti = mateconf_client_get_int (client, src, NULL);
+ mateconf_client_set_int (client, dest, ti, NULL);
+
+ g_free (dest);
+ g_free (src);
+
+ /* SOCKS_PROXY_HOST */
+ dest = copy_location_create_key (to, SOCKS_PROXY_HOST_KEY);
+ src = copy_location_create_key (from, SOCKS_PROXY_HOST_KEY);
+
+ tstr = mateconf_client_get_string (client, src, NULL);
+ if (tstr != NULL)
+ {
+ mateconf_client_set_string (client, dest, tstr, NULL);
+ g_free (tstr);
+ }
+
+ g_free (dest);
+ g_free (src);
+
+ /* OLD_SOCKS_PROXY_HOST */
+ dest = copy_location_create_key (to, OLD_SOCKS_PROXY_HOST_KEY);
+ src = copy_location_create_key (from, OLD_SOCKS_PROXY_HOST_KEY);
+
+ tstr = mateconf_client_get_string (client, src, NULL);
+ if (tstr != NULL)
+ {
+ mateconf_client_set_string (client, dest, tstr, NULL);
+ g_free (tstr);
+ }
+
+ g_free (dest);
+ g_free (src);
+
+ /* SOCKS_PROXY_PORT */
+ dest = copy_location_create_key (to, SOCKS_PROXY_PORT_KEY);
+ src = copy_location_create_key (from, SOCKS_PROXY_PORT_KEY);
+
+ ti = mateconf_client_get_int (client, src, NULL);
+ mateconf_client_set_int (client, dest, ti, NULL);
+
+ g_free (dest);
+ g_free (src);
+
+ /* OLD_SOCKS_PROXY_PORT */
+ dest = copy_location_create_key (to, OLD_SOCKS_PROXY_PORT_KEY);
+ src = copy_location_create_key (from, OLD_SOCKS_PROXY_PORT_KEY);
+
+ ti = mateconf_client_get_int (client, src, NULL);
+ mateconf_client_set_int (client, dest, ti, NULL);
+
+ g_free (dest);
+ g_free (src);
+
+ /* PROXY_AUTOCONFIG_URL */
+ dest = copy_location_create_key (to, PROXY_AUTOCONFIG_URL_KEY);
+ src = copy_location_create_key (from, PROXY_AUTOCONFIG_URL_KEY);
+
+ tstr = mateconf_client_get_string (client, src, NULL);
+ if (tstr != NULL)
+ {
+ mateconf_client_set_string (client, dest, tstr, NULL);
+ g_free (tstr);
+ }
+
+ g_free (dest);
+ g_free (src);
+}
+
+static gchar *
+get_current_location (MateConfClient *client)
+{
+ gchar *result;
+
+ result = mateconf_client_get_string (client, CURRENT_LOCATION, NULL);
+
+ if (result == NULL || result[0] == '\0')
+ {
+ g_free (result);
+ result = g_strdup (_("Default"));
+ }
+
+ return result;
+}
+
+static gboolean
+location_combo_separator (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ gchar *name;
+ gboolean ret;
+
+ gtk_tree_model_get (model, iter, COL_NAME, &name, -1);
+
+ ret = name == NULL || name[0] == '\0';
+
+ g_free (name);
+
+ return ret;
+}
+
+static void
+update_locations (MateConfClient *client,
+ GtkBuilder *builder);
+
+static void
+cb_location_changed (GtkWidget *location,
+ GtkBuilder *builder);
+
+static void
+cb_current_location (MateConfClient *client,
+ guint cnxn_id,
+ MateConfEntry *entry,
+ GtkBuilder *builder)
+{
+ MateConfValue *value;
+ const gchar *newval;
+
+ value = mateconf_entry_get_value (entry);
+ if (value == NULL)
+ return;
+
+ newval = mateconf_value_get_string (value);
+ if (newval == NULL)
+ return;
+
+ /* prevent the current settings from being saved by blocking
+ * the signal handler */
+ g_signal_handlers_block_by_func (gtk_builder_get_object (builder, "location_combobox"),
+ cb_location_changed, builder);
+ update_locations (client, builder);
+ g_signal_handlers_unblock_by_func (gtk_builder_get_object (builder, "location_combobox"),
+ cb_location_changed, builder);
+}
+
+static void
+update_locations (MateConfClient *client,
+ GtkBuilder *builder)
+{
+ int i, select;
+ gchar *current;
+ GtkComboBox *location = GTK_COMBO_BOX (gtk_builder_get_object (builder, "location_combobox"));
+ GSList *list = mateconf_client_all_dirs (client, LOCATION_DIR, NULL);
+ GtkTreeIter titer;
+ GtkListStore *store;
+ GSList *iter, *last;
+
+ store = GTK_LIST_STORE (gtk_combo_box_get_model (location));
+ gtk_list_store_clear (store);
+
+ current = get_current_location (client);
+
+ list = g_slist_append (list, g_strconcat (LOCATION_DIR"/", current, NULL));
+ list = g_slist_sort (list, (GCompareFunc) strcmp);
+
+ select = -1;
+
+ for (i = 0, iter = list, last = NULL; iter != NULL; last = iter, iter = g_slist_next (iter), ++i)
+ {
+ if (last == NULL || strcmp (last->data, iter->data) != 0)
+ {
+ gchar *locp, *key_name;
+
+ locp = iter->data + strlen (LOCATION_DIR) + 1;
+ key_name = mateconf_unescape_key (locp, -1);
+
+ gtk_list_store_append (store, &titer);
+ gtk_list_store_set (store, &titer,
+ COL_NAME, key_name,
+ COL_STYLE, PANGO_STYLE_NORMAL, -1);
+
+ g_free (key_name);
+
+ if (strcmp (locp, current) == 0)
+ select = i;
+ }
+ }
+ if (select == -1)
+ {
+ gtk_list_store_append (store, &titer);
+ gtk_list_store_set (store, &titer,
+ COL_NAME , current,
+ COL_STYLE, PANGO_STYLE_NORMAL, -1);
+ select = i++;
+ }
+ gtk_widget_set_sensitive (_gtk_builder_get_widget (builder,
+ "delete_button"),
+ i > 1);
+
+ gtk_list_store_append (store, &titer);
+ gtk_list_store_set (store, &titer,
+ COL_NAME, NULL,
+ COL_STYLE, PANGO_STYLE_NORMAL, -1);
+
+ gtk_list_store_append (store, &titer);
+ gtk_list_store_set (store, &titer,
+ COL_NAME, _("New Location..."),
+ COL_STYLE, PANGO_STYLE_ITALIC, -1);
+
+ gtk_combo_box_set_row_separator_func (location, location_combo_separator, NULL, NULL);
+ gtk_combo_box_set_active (location, select);
+ g_free (current);
+ g_slist_foreach (list, (GFunc) mateconf_entry_free, NULL);
+ g_slist_free (list);
+}
+
+static void
+cb_location_new_text_changed (GtkEntry *entry, GtkBuilder *builder)
+{
+ gboolean exists;
+ gchar *current, *esc, *key;
+ const gchar *name;
+ MateConfClient *client;
+
+ client = mateconf_client_get_default ();
+
+ name = gtk_entry_get_text (entry);
+ if (name != NULL && name[0] != '\0')
+ {
+ esc = mateconf_escape_key (name, -1);
+
+ key = g_strconcat (LOCATION_DIR "/", esc, NULL);
+ g_free (esc);
+
+ current = get_current_location (client);
+
+ exists = (strcmp (current, name) == 0) ||
+ mateconf_client_dir_exists (client, key, NULL);
+ g_free (key);
+ } else exists = FALSE;
+
+ g_object_unref (client);
+
+ if (exists)
+ gtk_widget_show (_gtk_builder_get_widget (builder,
+ "error_label"));
+ else
+ gtk_widget_hide (_gtk_builder_get_widget (builder,
+ "error_label"));
+
+ gtk_widget_set_sensitive (_gtk_builder_get_widget (builder,
+ "new_location"),
+ !exists);
+}
+
+static void
+location_new (GtkBuilder *capplet_builder, GtkWidget *parent)
+{
+ GtkBuilder *builder;
+ GError *error = NULL;
+ gchar *builder_widgets[] = { "location_new_dialog",
+ "new_location_btn_img", NULL };
+ GtkWidget *askdialog;
+ const gchar *name;
+ int response;
+ MateConfClient *client;
+
+ client = mateconf_client_get_default ();
+
+ builder = gtk_builder_new ();
+ if (gtk_builder_add_objects_from_file (builder, MATECC_GNP_UI_FILE,
+ builder_widgets, &error) == 0) {
+ g_warning ("Could not load location dialog: %s",
+ error->message);
+ g_error_free (error);
+ g_object_unref (builder);
+ return;
+ }
+
+ askdialog = _gtk_builder_get_widget (builder, "location_new_dialog");
+ gtk_window_set_transient_for (GTK_WINDOW (askdialog), GTK_WINDOW (parent));
+ g_signal_connect (askdialog, "response",
+ G_CALLBACK (gtk_widget_hide), NULL);
+ g_signal_connect (gtk_builder_get_object (builder, "text"), "changed",
+ G_CALLBACK (cb_location_new_text_changed), builder);
+ response = gtk_dialog_run (GTK_DIALOG (askdialog));
+ name = gtk_entry_get_text (GTK_ENTRY (gtk_builder_get_object (builder, "text")));
+ g_object_unref (builder);
+
+ if (response == GTK_RESPONSE_OK && name[0] != '\0')
+ {
+ gboolean exists;
+ gchar *current, *esc, *key;
+ esc = mateconf_escape_key (name, -1);
+ key = g_strconcat (LOCATION_DIR "/", esc, NULL);
+ g_free (esc);
+
+ current = get_current_location (client);
+
+ exists = (strcmp (current, name) == 0) ||
+ mateconf_client_dir_exists (client, key, NULL);
+
+ g_free (key);
+
+ if (!exists)
+ {
+ esc = mateconf_escape_key (current, -1);
+ g_free (current);
+ key = g_strconcat (LOCATION_DIR "/", esc, NULL);
+ g_free (esc);
+
+ copy_location ("", key, client);
+ g_free (key);
+
+ mateconf_client_set_string (client, CURRENT_LOCATION, name, NULL);
+ update_locations (client, capplet_builder);
+ }
+ else
+ {
+ GtkWidget *err = gtk_message_dialog_new (GTK_WINDOW (askdialog),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ _("Location already exists"));
+ gtk_dialog_run (GTK_DIALOG (err));
+ gtk_widget_destroy (err);
+
+ /* switch back to the currently selected location */
+ mateconf_client_notify (client, CURRENT_LOCATION);
+ }
+ }
+ else
+ {
+ /* switch back to the currently selected location */
+ mateconf_client_notify (client, CURRENT_LOCATION);
+ }
+ gtk_widget_destroy (askdialog);
+ g_object_unref (client);
+}
+
+static void
+cb_location_changed (GtkWidget *location,
+ GtkBuilder *builder)
+{
+ gchar *current;
+ gchar *name = gtk_combo_box_get_active_text (GTK_COMBO_BOX (location));
+ MateConfClient *client;
+
+ if (name == NULL)
+ return;
+
+ client = mateconf_client_get_default ();
+
+ current = get_current_location (client);
+
+ if (strcmp (current, name) != 0)
+ {
+ if (strcmp (name, _("New Location...")) == 0)
+ {
+ location_new (builder, _gtk_builder_get_widget (builder, "network_dialog"));
+ }
+ else
+ {
+ gchar *key, *esc;
+
+ /* save current settings */
+ esc = mateconf_escape_key (current, -1);
+ key = g_strconcat (LOCATION_DIR "/", esc, NULL);
+ g_free (esc);
+
+ copy_location ("", key, client);
+ g_free (key);
+
+ /* load settings */
+ esc = mateconf_escape_key (name, -1);
+ key = g_strconcat (LOCATION_DIR "/", esc, NULL);
+ g_free (esc);
+
+ copy_location (key, "", client);
+ mateconf_client_recursive_unset (client, key,
+ MATECONF_UNSET_INCLUDING_SCHEMA_NAMES, NULL);
+ g_free (key);
+
+ mateconf_client_set_string (client, CURRENT_LOCATION, name, NULL);
+ }
+ }
+
+ g_free (current);
+ g_free (name);
+ g_object_unref (client);
+}
+
+static void
+cb_delete_button_clicked (GtkWidget *button,
+ GtkBuilder *builder)
+{
+ MateConfClient *client;
+ GtkComboBox *box = GTK_COMBO_BOX (gtk_builder_get_object (builder,
+ "location_combobox"));
+ int active = gtk_combo_box_get_active (box);
+ gchar *current, *key, *esc;
+
+ /* prevent the current settings from being saved by blocking
+ * the signal handler */
+ g_signal_handlers_block_by_func (box, cb_location_changed, builder);
+ gtk_combo_box_set_active (box, (active == 0) ? 1 : 0);
+ gtk_combo_box_remove_text (box, active);
+ g_signal_handlers_unblock_by_func (box, cb_location_changed, builder);
+
+ /* set the new location */
+ client = mateconf_client_get_default ();
+ current = gtk_combo_box_get_active_text (box);
+
+ esc = mateconf_escape_key (current, -1);
+ key = g_strconcat (LOCATION_DIR "/", esc, NULL);
+ g_free (esc);
+
+ copy_location (key, "", client);
+ mateconf_client_recursive_unset (client, key,
+ MATECONF_UNSET_INCLUDING_SCHEMA_NAMES, NULL);
+ mateconf_client_suggest_sync (client, NULL);
+ g_free (key);
+
+ mateconf_client_set_string (client, CURRENT_LOCATION, current, NULL);
+
+ g_free (current);
+
+ g_object_unref (client);
+}
+
+/* When using the same proxy for all protocols, updates every host_entry
+ * as the user types along */
+static void
+synchronize_hosts (GtkEntry *widget,
+ GtkBuilder *builder)
+{
+ const gchar *hosts[] = {
+ "secure_host_entry",
+ "ftp_host_entry",
+ "socks_host_entry",
+ NULL };
+ const gchar **host, *http_host;
+
+ http_host = gtk_entry_get_text (widget);
+
+ for (host = hosts; *host != NULL; ++host)
+ {
+ widget = GTK_ENTRY (gtk_builder_get_object (builder, *host));
+ gtk_entry_set_text (widget, http_host);
+ }
+}
+
+/* When using the same proxy for all protocols, copies the value of the
+ * http port to the other spinbuttons */
+static void
+synchronize_ports (GtkSpinButton *widget,
+ GtkBuilder *builder)
+{
+ const gchar *ports[] = {
+ "secure_port_spinbutton",
+ "ftp_port_spinbutton",
+ "socks_port_spinbutton",
+ NULL };
+ gdouble http_port;
+ const gchar **port;
+
+ http_port = gtk_spin_button_get_value (widget);
+
+ for (port = ports; *port != NULL; ++port)
+ {
+ widget = GTK_SPIN_BUTTON (
+ gtk_builder_get_object (builder, *port));
+ gtk_spin_button_set_value (widget, http_port);
+ }
+}
+
+/* Synchronizes all hosts and ports */
+static void
+synchronize_entries (GtkBuilder *builder)
+{
+ g_signal_connect (
+ gtk_builder_get_object (builder, "http_host_entry"),
+ "changed",
+ G_CALLBACK (synchronize_hosts),
+ builder);
+ g_signal_connect (
+ gtk_builder_get_object (builder, "http_port_spinbutton"),
+ "value-changed",
+ G_CALLBACK (synchronize_ports),
+ builder);
+}
+
+/* Unsynchronize hosts and ports */
+static void
+unsynchronize_entries (GtkBuilder *builder)
+{
+ g_signal_handlers_disconnect_by_func (
+ gtk_builder_get_object (builder, "http_host_entry"),
+ synchronize_hosts,
+ builder);
+ g_signal_handlers_disconnect_by_func (
+ gtk_builder_get_object (builder, "http_port_spinbutton"),
+ synchronize_ports,
+ builder);
+}
+
+static void
+cb_use_same_proxy_checkbutton_clicked (GtkWidget *checkbutton,
+ GtkBuilder *builder)
+{
+ MateConfClient *client;
+ gboolean same_proxy;
+ gchar *http_proxy;
+ gint http_port;
+ gchar *host;
+
+ client = mateconf_client_get_default ();
+ same_proxy = mateconf_client_get_bool (client, USE_SAME_PROXY_KEY, NULL);
+
+ http_proxy = mateconf_client_get_string (client, HTTP_PROXY_HOST_KEY, NULL);
+ http_port = mateconf_client_get_int (client, HTTP_PROXY_PORT_KEY, NULL);
+
+ if (same_proxy)
+ {
+ /* Save the old values */
+ host = mateconf_client_get_string (client, SECURE_PROXY_HOST_KEY, NULL);
+ mateconf_client_set_string (client, OLD_SECURE_PROXY_HOST_KEY, host, NULL);
+ mateconf_client_set_int (client, OLD_SECURE_PROXY_PORT_KEY,
+ mateconf_client_get_int (client, SECURE_PROXY_PORT_KEY, NULL), NULL);
+ g_free (host);
+
+ host = mateconf_client_get_string (client, FTP_PROXY_HOST_KEY, NULL);
+ mateconf_client_set_string (client, OLD_FTP_PROXY_HOST_KEY, host, NULL);
+ mateconf_client_set_int (client, OLD_FTP_PROXY_PORT_KEY,
+ mateconf_client_get_int (client, FTP_PROXY_PORT_KEY, NULL), NULL);
+ g_free (host);
+
+ host = mateconf_client_get_string (client, SOCKS_PROXY_HOST_KEY, NULL);
+ mateconf_client_set_string (client, OLD_SOCKS_PROXY_HOST_KEY, host, NULL);
+ mateconf_client_set_int (client, OLD_SOCKS_PROXY_PORT_KEY,
+ mateconf_client_get_int (client, SOCKS_PROXY_PORT_KEY, NULL), NULL);
+ g_free (host);
+
+ /* Set the new values */
+ mateconf_client_set_string (client, SECURE_PROXY_HOST_KEY, http_proxy, NULL);
+ mateconf_client_set_int (client, SECURE_PROXY_PORT_KEY, http_port, NULL);
+
+ mateconf_client_set_string (client, FTP_PROXY_HOST_KEY, http_proxy, NULL);
+ mateconf_client_set_int (client, FTP_PROXY_PORT_KEY, http_port, NULL);
+
+ mateconf_client_set_string (client, SOCKS_PROXY_HOST_KEY, http_proxy, NULL);
+ mateconf_client_set_int (client, SOCKS_PROXY_PORT_KEY, http_port, NULL);
+
+ /* Synchronize entries */
+ synchronize_entries (builder);
+ }
+ else
+ {
+ host = mateconf_client_get_string (client, OLD_SECURE_PROXY_HOST_KEY, NULL);
+ mateconf_client_set_string (client, SECURE_PROXY_HOST_KEY, host, NULL);
+ mateconf_client_set_int (client, SECURE_PROXY_PORT_KEY,
+ mateconf_client_get_int (client, OLD_SECURE_PROXY_PORT_KEY, NULL), NULL);
+ g_free (host);
+
+ host = mateconf_client_get_string (client, OLD_FTP_PROXY_HOST_KEY, NULL);
+ mateconf_client_set_string (client, FTP_PROXY_HOST_KEY, host, NULL);
+ mateconf_client_set_int (client, FTP_PROXY_PORT_KEY,
+ mateconf_client_get_int (client, OLD_FTP_PROXY_PORT_KEY, NULL), NULL);
+ g_free (host);
+
+ host = mateconf_client_get_string (client, OLD_SOCKS_PROXY_HOST_KEY, NULL);
+ mateconf_client_set_string (client, SOCKS_PROXY_HOST_KEY, host, NULL);
+ mateconf_client_set_int (client, SOCKS_PROXY_PORT_KEY,
+ mateconf_client_get_int (client, OLD_SOCKS_PROXY_PORT_KEY, NULL), NULL);
+ g_free (host);
+
+ /* Hosts and ports should not be synchronized any more */
+ unsynchronize_entries (builder);
+ }
+
+ /* Set the proxy entries insensitive if we are using the same proxy for all */
+ gtk_widget_set_sensitive (_gtk_builder_get_widget (builder,
+ "secure_host_entry"),
+ !same_proxy);
+ gtk_widget_set_sensitive (_gtk_builder_get_widget (builder,
+ "secure_port_spinbutton"),
+ !same_proxy);
+ gtk_widget_set_sensitive (_gtk_builder_get_widget (builder,
+ "ftp_host_entry"),
+ !same_proxy);
+ gtk_widget_set_sensitive (_gtk_builder_get_widget (builder,
+ "ftp_port_spinbutton"),
+ !same_proxy);
+ gtk_widget_set_sensitive (_gtk_builder_get_widget (builder,
+ "socks_host_entry"),
+ !same_proxy);
+ gtk_widget_set_sensitive (_gtk_builder_get_widget (builder,
+ "socks_port_spinbutton"),
+ !same_proxy);
+
+ g_object_unref (client);
+}
+
+static gchar *
+get_hostname_from_uri (const gchar *uri)
+{
+ const gchar *start, *end;
+ gchar *host;
+
+ if (uri == NULL)
+ return NULL;
+
+ /* skip the scheme part */
+ start = strchr (uri, ':');
+ if (start == NULL)
+ return NULL;
+
+ /* forward until after the last '/' */
+ do {
+ ++start;
+ } while (*start == '/');
+
+ if (*start == '\0')
+ return NULL;
+
+ /* maybe we have a port? */
+ end = strchr (start, ':');
+ if (end == NULL)
+ end = strchr (start, '/');
+
+ if (end != NULL)
+ host = g_strndup (start, end - start);
+ else
+ host = g_strdup (start);
+
+ return host;
+}
+
+static MateConfValue *
+extract_proxy_host (MateConfPropertyEditor *peditor, const MateConfValue *orig)
+{
+ char const *entered_text = mateconf_value_get_string (orig);
+ MateConfValue *res = NULL;
+
+ if (entered_text != NULL) {
+ gchar *host = get_hostname_from_uri (entered_text);
+
+ if (host != NULL) {
+ res = mateconf_value_new (MATECONF_VALUE_STRING);
+ mateconf_value_set_string (res, host);
+ g_free (host);
+ }
+ }
+
+ return (res != NULL) ? res : mateconf_value_copy (orig);
+}
+
+static void
+proxy_mode_radiobutton_clicked_cb (GtkWidget *widget,
+ GtkBuilder *builder)
+{
+ GSList *mode_group;
+ int mode;
+ MateConfClient *client;
+
+ if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(widget)))
+ return;
+
+ mode_group = g_slist_copy (gtk_radio_button_get_group
+ (GTK_RADIO_BUTTON (gtk_builder_get_object (builder, "none_radiobutton"))));
+ mode_group = g_slist_reverse (mode_group);
+ mode = g_slist_index (mode_group, widget);
+ g_slist_free (mode_group);
+
+ gtk_widget_set_sensitive (_gtk_builder_get_widget (builder, "manual_box"),
+ mode == PROXYMODE_MANUAL);
+ gtk_widget_set_sensitive (_gtk_builder_get_widget (builder, "same_proxy_checkbutton"),
+ mode == PROXYMODE_MANUAL);
+ gtk_widget_set_sensitive (_gtk_builder_get_widget (builder, "auto_box"),
+ mode == PROXYMODE_AUTO);
+ client = mateconf_client_get_default ();
+ mateconf_client_set_bool (client, USE_PROXY_KEY,
+ mode == PROXYMODE_AUTO || mode == PROXYMODE_MANUAL, NULL);
+ g_object_unref (client);
+}
+
+static void
+connect_sensitivity_signals (GtkBuilder *builder, GSList *mode_group)
+{
+ for (; mode_group != NULL; mode_group = mode_group->next)
+ {
+ g_signal_connect (G_OBJECT (mode_group->data), "clicked",
+ G_CALLBACK(proxy_mode_radiobutton_clicked_cb),
+ builder);
+ }
+}
+
+static void
+cb_ignore_hosts_mateconf_changed (MateConfClient *client, guint cnxn_id,
+ MateConfEntry *entry, gpointer user_data)
+{
+ g_slist_foreach (ignore_hosts, (GFunc) g_free, NULL);
+ g_slist_free (ignore_hosts);
+
+ ignore_hosts = mateconf_client_get_list (client, IGNORE_HOSTS_KEY,
+ MATECONF_VALUE_STRING, NULL);
+
+ populate_listmodel (GTK_LIST_STORE (model), ignore_hosts);
+}
+
+static void
+setup_dialog (GtkBuilder *builder)
+{
+ MateConfPropertyEditor *peditor;
+ GSList *mode_group;
+ GType mode_type = 0;
+ MateConfClient *client;
+ gint port_value;
+ GtkWidget *location_box, *same_proxy_toggle;
+ GtkCellRenderer *location_renderer;
+ GtkListStore *store;
+
+ mode_type = g_enum_register_static ("NetworkPreferencesProxyType",
+ proxytype_values);
+
+ client = mateconf_client_get_default ();
+
+ /* Locations */
+ location_box = _gtk_builder_get_widget (builder, "location_combobox");
+ store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT);
+ gtk_combo_box_set_model (GTK_COMBO_BOX (location_box), GTK_TREE_MODEL (store));
+
+ update_locations (client, builder);
+ mateconf_client_add_dir (client, LOCATION_DIR, MATECONF_CLIENT_PRELOAD_ONELEVEL, NULL);
+ mateconf_client_notify_add (client, CURRENT_LOCATION, (MateConfClientNotifyFunc) cb_current_location, builder, NULL, NULL);
+
+ mateconf_client_notify_add (client, IGNORE_HOSTS_KEY, cb_ignore_hosts_mateconf_changed, NULL, NULL, NULL);
+
+ g_signal_connect (location_box, "changed", G_CALLBACK (cb_location_changed), builder);
+ g_signal_connect (gtk_builder_get_object (builder, "delete_button"), "clicked", G_CALLBACK (cb_delete_button_clicked), builder);
+
+ location_renderer = gtk_cell_renderer_text_new ();
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (location_box), location_renderer, TRUE);
+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (location_box),
+ location_renderer,
+ "text", COL_NAME,
+ "style", COL_STYLE, NULL);
+
+ /* Mode */
+ mode_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (gtk_builder_get_object (builder, "none_radiobutton")));
+ connect_sensitivity_signals (builder, mode_group);
+
+ peditor = MATECONF_PROPERTY_EDITOR (mateconf_peditor_new_select_radio_with_enum (NULL,
+ PROXY_MODE_KEY, mode_group, mode_type,
+ TRUE, NULL));
+
+ /* Use same proxy for all protocols */
+ same_proxy_toggle = _gtk_builder_get_widget (builder, "same_proxy_checkbutton");
+ peditor = MATECONF_PROPERTY_EDITOR (mateconf_peditor_new_boolean (NULL,
+ USE_SAME_PROXY_KEY, same_proxy_toggle, NULL));
+
+ g_signal_connect (same_proxy_toggle,
+ "toggled",
+ G_CALLBACK (cb_use_same_proxy_checkbutton_clicked),
+ builder);
+
+ /* Http */
+ port_value = mateconf_client_get_int (client, HTTP_PROXY_PORT_KEY, NULL);
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "http_port_spinbutton")), (gdouble) port_value);
+ peditor = MATECONF_PROPERTY_EDITOR (mateconf_peditor_new_string (
+ NULL, HTTP_PROXY_HOST_KEY, _gtk_builder_get_widget (builder, "http_host_entry"),
+ "conv-from-widget-cb", extract_proxy_host,
+ NULL));
+ peditor = MATECONF_PROPERTY_EDITOR (mateconf_peditor_new_integer (
+ NULL, HTTP_PROXY_PORT_KEY,
+ _gtk_builder_get_widget (builder, "http_port_spinbutton"),
+ NULL));
+ g_signal_connect (gtk_builder_get_object (builder, "details_button"),
+ "clicked",
+ G_CALLBACK (cb_http_details_button_clicked),
+ _gtk_builder_get_widget (builder, "network_dialog"));
+
+ /* Secure */
+ port_value = mateconf_client_get_int (client, SECURE_PROXY_PORT_KEY, NULL);
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "secure_port_spinbutton")), (gdouble) port_value);
+ peditor = MATECONF_PROPERTY_EDITOR (mateconf_peditor_new_string (
+ NULL, SECURE_PROXY_HOST_KEY,
+ _gtk_builder_get_widget (builder, "secure_host_entry"),
+ "conv-from-widget-cb", extract_proxy_host,
+ NULL));
+ peditor = MATECONF_PROPERTY_EDITOR (mateconf_peditor_new_integer (
+ NULL, SECURE_PROXY_PORT_KEY,
+ _gtk_builder_get_widget (builder, "secure_port_spinbutton"),
+ NULL));
+
+ /* Ftp */
+ port_value = mateconf_client_get_int (client, FTP_PROXY_PORT_KEY, NULL);
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "ftp_port_spinbutton")), (gdouble) port_value);
+ peditor = MATECONF_PROPERTY_EDITOR (mateconf_peditor_new_string (
+ NULL, FTP_PROXY_HOST_KEY,
+ _gtk_builder_get_widget (builder, "ftp_host_entry"),
+ "conv-from-widget-cb", extract_proxy_host,
+ NULL));
+ peditor = MATECONF_PROPERTY_EDITOR (mateconf_peditor_new_integer (
+ NULL, FTP_PROXY_PORT_KEY,
+ _gtk_builder_get_widget (builder, "ftp_port_spinbutton"),
+ NULL));
+
+ /* Socks */
+ port_value = mateconf_client_get_int (client, SOCKS_PROXY_PORT_KEY, NULL);
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON (gtk_builder_get_object (builder, "socks_port_spinbutton")), (gdouble) port_value);
+ peditor = MATECONF_PROPERTY_EDITOR (mateconf_peditor_new_string (
+ NULL, SOCKS_PROXY_HOST_KEY,
+ _gtk_builder_get_widget (builder, "socks_host_entry"),
+ "conv-from-widget-cb", extract_proxy_host,
+ NULL));
+ peditor = MATECONF_PROPERTY_EDITOR (mateconf_peditor_new_integer (
+ NULL, SOCKS_PROXY_PORT_KEY,
+ _gtk_builder_get_widget (builder, "socks_port_spinbutton"),
+ NULL));
+
+ /* Set the proxy entries insensitive if we are using the same proxy for all,
+ and make sure they are all synchronized */
+ if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (same_proxy_toggle)))
+ {
+ gtk_widget_set_sensitive (_gtk_builder_get_widget (builder, "secure_host_entry"), FALSE);
+ gtk_widget_set_sensitive (_gtk_builder_get_widget (builder, "secure_port_spinbutton"), FALSE);
+ gtk_widget_set_sensitive (_gtk_builder_get_widget (builder, "ftp_host_entry"), FALSE);
+ gtk_widget_set_sensitive (_gtk_builder_get_widget (builder, "ftp_port_spinbutton"), FALSE);
+ gtk_widget_set_sensitive (_gtk_builder_get_widget (builder, "socks_host_entry"), FALSE);
+ gtk_widget_set_sensitive (_gtk_builder_get_widget (builder, "socks_port_spinbutton"), FALSE);
+
+ synchronize_entries (builder);
+ }
+
+ /* Autoconfiguration */
+ peditor = MATECONF_PROPERTY_EDITOR (mateconf_peditor_new_string (
+ NULL, PROXY_AUTOCONFIG_URL_KEY,
+ _gtk_builder_get_widget (builder, "autoconfig_entry"),
+ NULL));
+
+ g_signal_connect (gtk_builder_get_object (builder, "network_dialog"),
+ "response", G_CALLBACK (cb_dialog_response), NULL);
+
+
+ ignore_hosts = mateconf_client_get_list(client, IGNORE_HOSTS_KEY, MATECONF_VALUE_STRING, NULL);
+ g_object_unref (client);
+
+ model = create_listmodel();
+ populate_listmodel(GTK_LIST_STORE(model), ignore_hosts);
+ config_treeview(GTK_TREE_VIEW(gtk_builder_get_object (builder, "treeview_ignore_host")), model);
+
+ g_signal_connect (gtk_builder_get_object (builder, "button_add_url"),
+ "clicked", G_CALLBACK (cb_add_url), builder);
+ g_signal_connect (gtk_builder_get_object (builder, "entry_url"),
+ "activate", G_CALLBACK (cb_add_url), builder);
+ g_signal_connect (gtk_builder_get_object (builder, "button_remove_url"),
+ "clicked", G_CALLBACK (cb_remove_url), builder);
+}
+
+int
+main (int argc, char **argv)
+{
+ GtkBuilder *builder;
+ GError *error = NULL;
+ gchar *builder_widgets[] = {"network_dialog", "adjustment1",
+ "adjustment2", "adjustment3", "adjustment4",
+ "delete_button_img", NULL};
+ MateConfClient *client;
+ GtkWidget *widget;
+
+ bindtextdomain (GETTEXT_PACKAGE, MATELOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+ textdomain (GETTEXT_PACKAGE);
+
+ gtk_init (&argc, &argv);
+
+ client = mateconf_client_get_default ();
+ mateconf_client_add_dir (client, "/system/http_proxy",
+ MATECONF_CLIENT_PRELOAD_ONELEVEL, NULL);
+ mateconf_client_add_dir (client, "/system/proxy",
+ MATECONF_CLIENT_PRELOAD_ONELEVEL, NULL);
+
+ builder = gtk_builder_new ();
+ if (gtk_builder_add_objects_from_file (builder, MATECC_GNP_UI_FILE,
+ builder_widgets, &error) == 0) {
+ g_warning ("Could not load main dialog: %s",
+ error->message);
+ g_error_free (error);
+ g_object_unref (builder);
+ g_object_unref (client);
+ return (EXIT_FAILURE);
+ }
+
+ setup_dialog (builder);
+ widget = _gtk_builder_get_widget (builder, "network_dialog");
+ capplet_set_icon (widget, "mate-network-properties");
+ gtk_widget_show_all (widget);
+ gtk_main ();
+
+ g_object_unref (builder);
+ g_object_unref (client);
+
+ return 0;
+}
diff --git a/capplets/network/mate-network-properties.desktop.in.in b/capplets/network/mate-network-properties.desktop.in.in
new file mode 100644
index 00000000..e16b3d09
--- /dev/null
+++ b/capplets/network/mate-network-properties.desktop.in.in
@@ -0,0 +1,14 @@
+[Desktop Entry]
+_Name=Network Proxy
+_Comment=Set your network proxy preferences
+Exec=mate-network-properties
+Icon=mate-network-properties
+Terminal=false
+Type=Application
+StartupNotify=true
+Categories=MATE;GTK;Settings;X-MATE-NetworkSettings;
+OnlyShowIn=MATE;
+X-MATE-Bugzilla-Bugzilla=MATE
+X-MATE-Bugzilla-Product=mate-control-center
+X-MATE-Bugzilla-Component=network preferences
+X-MATE-Bugzilla-Version=@VERSION@
diff --git a/capplets/network/mate-network-properties.ui b/capplets/network/mate-network-properties.ui
new file mode 100644
index 00000000..29c3c3e1
--- /dev/null
+++ b/capplets/network/mate-network-properties.ui
@@ -0,0 +1,1056 @@
+<?xml version="1.0"?>
+<interface>
+ <requires lib="gtk+" version="2.16"/>
+ <!-- interface-naming-policy toplevel-contextual -->
+ <object class="GtkDialog" id="network_dialog">
+ <property name="border_width">5</property>
+ <property name="title" translatable="yes">Network Proxy Preferences</property>
+ <property name="resizable">False</property>
+ <property name="type_hint">dialog</property>
+ <property name="has_separator">False</property>
+ <child internal-child="vbox">
+ <object class="GtkVBox" id="dialog-vbox1">
+ <property name="visible">True</property>
+ <property name="spacing">2</property>
+ <child>
+ <object class="GtkAlignment" id="alignment1">
+ <property name="xscale">0</property>
+ <child>
+ <object class="GtkHBox" id="hbox2">
+ <property name="visible">True</property>
+ <property name="spacing">3</property>
+ <child>
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property name="label" translatable="yes">Location:</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBox" id="location_combobox">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkNotebook" id="notebook1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="border_width">5</property>
+ <child>
+ <object class="GtkVBox" id="vbox1">
+ <property name="visible">True</property>
+ <property name="border_width">12</property>
+ <property name="spacing">18</property>
+ <child>
+ <object class="GtkRadioButton" id="none_radiobutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <child>
+ <object class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Di_rect internet connection&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="no_direct_vbox">
+ <property name="visible">True</property>
+ <property name="spacing">18</property>
+ <child>
+ <object class="GtkVBox" id="manual_vbox">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkRadioButton" id="manual_radiobutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">none_radiobutton</property>
+ <child>
+ <object class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;_Manual proxy configuration&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="same_proxy_checkbutton">
+ <property name="label" translatable="yes">_Use the same proxy for all protocols</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="manual_box">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <child>
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="label"> </property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkTable" id="manual_table">
+ <property name="visible">True</property>
+ <property name="n_rows">4</property>
+ <property name="n_columns">5</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label6">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">H_TTP proxy:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">http_host_entry</property>
+ </object>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label7">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Secure HTTP proxy:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">secure_host_entry</property>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label8">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_FTP proxy:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">ftp_host_entry</property>
+ </object>
+ <packing>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label9">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">S_ocks host:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">socks_host_entry</property>
+ </object>
+ <packing>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="http_host_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="secure_host_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="ftp_host_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="socks_host_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label10">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Port:</property>
+ <accessibility>
+ <relation type="label-for" target="http_port_spinbutton"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label11">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Port:</property>
+ <accessibility>
+ <relation type="label-for" target="secure_port_spinbutton"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label12">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Port:</property>
+ <accessibility>
+ <relation type="label-for" target="ftp_port_spinbutton"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label13">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Port:</property>
+ <accessibility>
+ <relation type="label-for" target="socks_port_spinbutton"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="http_port_spinbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="adjustment">adjustment4</property>
+ <property name="climb_rate">1</property>
+ <accessibility>
+ <relation type="labelled-by" target="label10"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="right_attach">4</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="secure_port_spinbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="adjustment">adjustment3</property>
+ <property name="climb_rate">1</property>
+ <accessibility>
+ <relation type="labelled-by" target="label11"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="right_attach">4</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="ftp_port_spinbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="adjustment">adjustment2</property>
+ <property name="climb_rate">1</property>
+ <accessibility>
+ <relation type="labelled-by" target="label12"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="right_attach">4</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="socks_port_spinbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="adjustment">adjustment1</property>
+ <property name="climb_rate">1</property>
+ <accessibility>
+ <relation type="labelled-by" target="label13"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="right_attach">4</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="details_button">
+ <property name="label" translatable="yes">_Details</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">4</property>
+ <property name="right_attach">5</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox2">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkRadioButton" id="auto_radiobutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="yalign">0.47</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">none_radiobutton</property>
+ <child>
+ <object class="GtkLabel" id="label5">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;_Automatic proxy configuration&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox1">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkLabel" id="label17">
+ <property name="visible">True</property>
+ <property name="label"> </property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="auto_box">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="label18">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Autoconfiguration _URL:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">autoconfig_entry</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="autoconfig_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="label20">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Proxy Configuration</property>
+ </object>
+ <packing>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox4">
+ <property name="visible">True</property>
+ <property name="border_width">12</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label_ignore_host">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Ignore Host List</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox4">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkLabel" id="label22">
+ <property name="visible">True</property>
+ <property name="label"> </property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkTable" id="table1">
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkEntry" id="entry_url">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="button_add_url">
+ <property name="label">gtk-add</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="scrolledwindow1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">automatic</property>
+ <property name="vscrollbar_policy">automatic</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkTreeView" id="treeview_ignore_host">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_visible">False</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment2">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0</property>
+ <property name="yscale">0</property>
+ <child>
+ <object class="GtkHBox" id="hbox3">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkButton" id="button_remove_url">
+ <property name="label">gtk-remove</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="label21">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Ignored Hosts</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <object class="GtkHButtonBox" id="dialog-action_area1">
+ <property name="visible">True</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="helpbutton1">
+ <property name="label">gtk-help</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="delete_button">
+ <property name="label" translatable="yes">_Delete Location</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="image">delete_button_img</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="closebutton1">
+ <property name="label">gtk-close</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-11">helpbutton1</action-widget>
+ <action-widget response="0">delete_button</action-widget>
+ <action-widget response="-7">closebutton1</action-widget>
+ </action-widgets>
+ </object>
+ <object class="GtkDialog" id="details_dialog">
+ <property name="border_width">5</property>
+ <property name="title" translatable="yes">HTTP Proxy Details</property>
+ <property name="resizable">False</property>
+ <property name="type_hint">dialog</property>
+ <property name="has_separator">False</property>
+ <child internal-child="vbox">
+ <object class="GtkVBox" id="dialog-vbox2">
+ <property name="visible">True</property>
+ <property name="spacing">2</property>
+ <child>
+ <object class="GtkVBox" id="vbox3">
+ <property name="visible">True</property>
+ <property name="border_width">5</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkCheckButton" id="use_auth_checkbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ <child>
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;_Use authentication&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox3">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkLabel" id="label19">
+ <property name="visible">True</property>
+ <property name="label"> </property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkTable" id="auth_table">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label15">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">U_sername:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">username_entry</property>
+ </object>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label16">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Password:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">password_entry</property>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="password_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="visibility">False</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="username_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <object class="GtkHButtonBox" id="dialog-action_area2">
+ <property name="visible">True</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="helpbutton2">
+ <property name="label">gtk-help</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="closebutton2">
+ <property name="label">gtk-close</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-11">helpbutton2</action-widget>
+ <action-widget response="-7">closebutton2</action-widget>
+ </action-widgets>
+ </object>
+ <object class="GtkDialog" id="location_new_dialog">
+ <property name="border_width">6</property>
+ <property name="title" translatable="yes">Create New Location</property>
+ <property name="resizable">False</property>
+ <property name="modal">True</property>
+ <property name="destroy_with_parent">True</property>
+ <property name="type_hint">dialog</property>
+ <property name="has_separator">False</property>
+ <child internal-child="vbox">
+ <object class="GtkVBox" id="dialog-vbox1">
+ <property name="visible">True</property>
+ <property name="homogeneous">True</property>
+ <child>
+ <object class="GtkHBox" id="hbox5">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkLabel" id="label19">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Location name:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">text</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="text">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="activates_default">True</property>
+ </object>
+ <packing>
+ <property name="padding">6</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="error_label">
+ <property name="label" translatable="yes">The location already exists.</property>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <object class="GtkHButtonBox" id="dialog-action_area1">
+ <property name="visible">True</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="new_location">
+ <property name="label" translatable="yes">C_reate</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="image">new_location_btn_img</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="button2">
+ <property name="label">gtk-cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-5">new_location</action-widget>
+ <action-widget response="-6">button2</action-widget>
+ </action-widgets>
+ </object>
+ <object class="GtkAdjustment" id="adjustment1">
+ <property name="upper">65535</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment2">
+ <property name="upper">65535</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment3">
+ <property name="upper">65535</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment4">
+ <property name="upper">65535</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkImage" id="new_location_btn_img">
+ <property name="visible">True</property>
+ <property name="stock">gtk-add</property>
+ </object>
+ <object class="GtkImage" id="delete_button_img">
+ <property name="visible">True</property>
+ <property name="stock">gtk-delete</property>
+ </object>
+</interface>
diff --git a/capplets/windows/Makefile.am b/capplets/windows/Makefile.am
new file mode 100644
index 00000000..a88ad37a
--- /dev/null
+++ b/capplets/windows/Makefile.am
@@ -0,0 +1,32 @@
+# This is used in MATECC_CAPPLETS_CFLAGS
+cappletname = window
+
+bin_PROGRAMS = mate-window-properties
+
+mate_window_properties_LDADD = $(MATECC_CAPPLETS_LIBS) \
+ $(top_builddir)/libwindow-settings/libmate-window-settings.la
+
+mate_window_properties_SOURCES = \
+ mate-window-properties.c
+
+@INTLTOOL_DESKTOP_RULE@
+
+uidir = $(pkgdatadir)/ui
+ui_DATA = mate-window-properties.ui
+
+desktopdir = $(datadir)/applications
+Desktop_in_files = window-properties.desktop.in
+desktop_DATA = $(Desktop_in_files:.desktop.in=.desktop)
+
+INCLUDES = $(MATECC_CAPPLETS_CFLAGS) \
+ -I$(top_srcdir)/libwindow-settings \
+ -DMATE_WINDOW_MANAGER_MODULE_PATH=\""$(libdir)/window-manager-settings"\" \
+ -DUIDIR=\""$(uidir)"\" \
+ -DMATELOCALEDIR="\"$(datadir)/locale\"" \
+ -DPIXMAPDIR=\""$(pixmapdir)"\"
+
+CLEANFILES = $(MATECC_CAPPLETS_CLEANFILES) $(Desktop_in_files) $(desktop_DATA)
+EXTRA_DIST = $(ui_DATA)
+
+
+-include $(top_srcdir)/git.mk
diff --git a/capplets/windows/mate-window-properties.c b/capplets/windows/mate-window-properties.c
new file mode 100644
index 00000000..74c8a207
--- /dev/null
+++ b/capplets/windows/mate-window-properties.c
@@ -0,0 +1,636 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+/* mate-window-properties.c
+ * Copyright (C) 2002 Seth Nickell
+ * Copyright (C) 2002 Red Hat, Inc.
+ *
+ * Written by: Seth Nickell <[email protected]>
+ * Havoc Pennington <[email protected]>
+ *
+ * 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, 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <glib/gi18n.h>
+#include <string.h>
+#include <mate-wm-manager.h>
+
+#include "capplet-util.h"
+#include "mateconf-property-editor.h"
+
+typedef struct
+{
+ int number;
+ char *name;
+ const char *value; /* machine-readable name for storing config */
+ GtkWidget *radio;
+} MouseClickModifier;
+
+static MateWindowManager *current_wm; /* may be NULL */
+static GtkWidget *dialog_win;
+static GObject *focus_mode_checkbutton;
+static GObject *autoraise_checkbutton;
+static GObject *autoraise_delay_slider;
+static GtkWidget *autoraise_delay_hbox;
+static GObject *double_click_titlebar_optionmenu;
+static GObject *alt_click_hbox;
+
+static MateWMSettings *settings;
+static const MateWMDoubleClickAction *double_click_actions = NULL;
+static int n_double_click_actions = 0;
+
+static MouseClickModifier *mouse_modifiers = NULL;
+static int n_mouse_modifiers = 0;
+
+static void reload_mouse_modifiers (void);
+
+static void
+mouse_focus_toggled_callback (GtkWidget *button,
+ void *data)
+{
+ MateWMSettings new_settings;
+
+ new_settings.flags = MATE_WM_SETTING_MOUSE_FOCUS;
+ new_settings.focus_follows_mouse =
+ gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
+
+ if (current_wm != NULL && new_settings.focus_follows_mouse != settings->focus_follows_mouse)
+ mate_window_manager_change_settings (current_wm, &new_settings);
+}
+
+static void
+autoraise_toggled_callback (GtkWidget *button,
+ void *data)
+{
+ MateWMSettings new_settings;
+
+ new_settings.flags = MATE_WM_SETTING_AUTORAISE;
+ new_settings.autoraise =
+ gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
+
+ if (current_wm != NULL && new_settings.autoraise != settings->autoraise)
+ mate_window_manager_change_settings (current_wm, &new_settings);
+
+}
+
+static void
+autoraise_delay_value_changed_callback (GtkWidget *slider,
+ void *data)
+{
+ MateWMSettings new_settings;
+
+ new_settings.flags = MATE_WM_SETTING_AUTORAISE_DELAY;
+ new_settings.autoraise_delay =
+ gtk_range_get_value (GTK_RANGE (slider)) * 1000;
+
+ if (current_wm != NULL && new_settings.autoraise_delay != settings->autoraise_delay)
+ mate_window_manager_change_settings (current_wm, &new_settings);
+}
+
+static void
+double_click_titlebar_changed_callback (GtkWidget *optionmenu,
+ void *data)
+{
+ MateWMSettings new_settings;
+
+ new_settings.flags = MATE_WM_SETTING_DOUBLE_CLICK_ACTION;
+ new_settings.double_click_action =
+ gtk_combo_box_get_active (GTK_COMBO_BOX (optionmenu));
+
+ if (current_wm != NULL && new_settings.double_click_action != settings->double_click_action)
+ mate_window_manager_change_settings (current_wm, &new_settings);
+}
+
+static void
+alt_click_radio_toggled_callback (GtkWidget *radio,
+ void *data)
+{
+ MateWMSettings new_settings;
+ gboolean active;
+ MouseClickModifier *modifier = data;
+
+ new_settings.flags = MATE_WM_SETTING_MOUSE_MOVE_MODIFIER;
+ active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (radio));
+
+ if (active && current_wm != NULL) {
+ new_settings.mouse_move_modifier = modifier->value;
+
+ if ((settings->mouse_move_modifier == NULL) ||
+ (strcmp (new_settings.mouse_move_modifier,
+ settings->mouse_move_modifier) != 0))
+ mate_window_manager_change_settings (current_wm, &new_settings);
+ }
+}
+
+static void
+update_sensitivity (void)
+{
+ gtk_widget_set_sensitive (GTK_WIDGET (autoraise_checkbutton),
+ settings->focus_follows_mouse);
+
+ gtk_widget_set_sensitive (autoraise_delay_hbox,
+ settings->focus_follows_mouse && settings->autoraise);
+
+ gtk_widget_set_sensitive (GTK_WIDGET (double_click_titlebar_optionmenu),
+ n_double_click_actions > 1);
+
+ /* disable the whole dialog while no WM is running, or
+ * a WM we don't understand is running. We should probably do
+ * something better. I don't want to just launch the config tool
+ * as we would on startup though, because then you'd get weirdness
+ * in the gap time between old and new WM.
+ */
+ gtk_widget_set_sensitive (dialog_win, current_wm != NULL);
+}
+
+static void
+init_settings_struct (MateWMSettings *settings)
+{
+ /* Init fields that weren't initialized */
+ if ((settings->flags & MATE_WM_SETTING_MOUSE_FOCUS) == 0)
+ settings->focus_follows_mouse = FALSE;
+
+ if ((settings->flags & MATE_WM_SETTING_AUTORAISE) == 0)
+ settings->autoraise = FALSE;
+
+ if ((settings->flags & MATE_WM_SETTING_AUTORAISE_DELAY) == 0)
+ settings->autoraise_delay = 1000;
+
+ if ((settings->flags & MATE_WM_SETTING_MOUSE_MOVE_MODIFIER) == 0)
+ settings->mouse_move_modifier = "Super";
+
+ if ((settings->flags & MATE_WM_SETTING_DOUBLE_CLICK_ACTION) == 0)
+ settings->double_click_action = 0;
+}
+
+static void
+set_alt_click_value (const MateWMSettings *settings)
+{
+ gboolean match_found = FALSE;
+ int i;
+
+ /* We look for a matching modifier and set it. */
+ if (settings->mouse_move_modifier != NULL) {
+ for (i = 0; i < n_mouse_modifiers; i ++)
+ if (strcmp (mouse_modifiers[i].value,
+ settings->mouse_move_modifier) == 0) {
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mouse_modifiers[i].radio),
+ TRUE);
+ match_found = TRUE;
+ break;
+ }
+ }
+
+ /* No matching modifier was found; we set all the toggle buttons to be
+ * insensitive. */
+ for (i = 0; i < n_mouse_modifiers; i++) {
+ gtk_toggle_button_set_inconsistent (GTK_TOGGLE_BUTTON (mouse_modifiers[i].radio),
+ ! match_found);
+ }
+}
+
+static void
+reload_settings (void)
+{
+ MateWMSettings new_settings;
+
+ g_assert (n_mouse_modifiers > 0);
+
+ if (current_wm != NULL) {
+ new_settings.flags = MATE_WM_SETTING_MOUSE_FOCUS |
+ MATE_WM_SETTING_AUTORAISE |
+ MATE_WM_SETTING_AUTORAISE_DELAY |
+ MATE_WM_SETTING_MOUSE_MOVE_MODIFIER |
+ MATE_WM_SETTING_DOUBLE_CLICK_ACTION;
+
+ /* this will clear any flags that don't get filled in */
+ mate_window_manager_get_settings (current_wm, &new_settings);
+ } else {
+ new_settings.flags = 0;
+ }
+
+ init_settings_struct (&new_settings);
+
+ if (new_settings.focus_follows_mouse != settings->focus_follows_mouse)
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (focus_mode_checkbutton),
+ new_settings.focus_follows_mouse);
+
+ if (new_settings.autoraise != settings->autoraise)
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (autoraise_checkbutton),
+ new_settings.autoraise);
+
+ if (new_settings.autoraise_delay != settings->autoraise_delay)
+ gtk_range_set_value (GTK_RANGE (autoraise_delay_slider),
+ new_settings.autoraise_delay / 1000.0);
+
+ if (n_double_click_actions > 0 &&
+ new_settings.double_click_action != settings->double_click_action) {
+ gtk_combo_box_set_active (GTK_COMBO_BOX (double_click_titlebar_optionmenu),
+ new_settings.double_click_action);
+ }
+
+ if (settings->mouse_move_modifier == NULL ||
+ new_settings.mouse_move_modifier == NULL ||
+ strcmp (settings->mouse_move_modifier,
+ new_settings.mouse_move_modifier) != 0) {
+ set_alt_click_value (&new_settings);
+ }
+
+ mate_wm_settings_free (settings);
+ settings = mate_wm_settings_copy (&new_settings);
+
+ update_sensitivity ();
+}
+
+static void
+wm_settings_changed_callback (MateWindowManager *wm,
+ void *data)
+{
+ reload_settings ();
+}
+
+static void
+update_wm (GdkScreen *screen,
+ gboolean load_settings)
+{
+ int i;
+
+ g_assert (n_mouse_modifiers > 0);
+
+ if (current_wm != NULL) {
+ g_signal_handlers_disconnect_by_func (G_OBJECT (current_wm),
+ G_CALLBACK (wm_settings_changed_callback),
+ NULL);
+ current_wm = NULL;
+ double_click_actions = NULL;
+ n_double_click_actions = 0;
+ }
+
+ current_wm = mate_wm_manager_get_current (screen);
+
+ if (current_wm != NULL) {
+ g_signal_connect (G_OBJECT (current_wm), "settings_changed",
+ G_CALLBACK (wm_settings_changed_callback), NULL);
+
+ mate_window_manager_get_double_click_actions (current_wm,
+ &double_click_actions,
+ &n_double_click_actions);
+
+ }
+
+ for (i = 0; i < n_double_click_actions; i++) {
+ gtk_combo_box_append_text (GTK_COMBO_BOX (double_click_titlebar_optionmenu),
+ double_click_actions[i].human_readable_name);
+ }
+
+ if (load_settings)
+ reload_settings ();
+}
+
+static void
+wm_changed_callback (GdkScreen *screen,
+ void *data)
+{
+ update_wm (screen, TRUE);
+}
+
+static void
+response_cb (GtkWidget *dialog_win,
+ int response_id,
+ void *data)
+{
+
+ if (response_id == GTK_RESPONSE_HELP) {
+ capplet_help (GTK_WINDOW (dialog_win),
+ "goscustdesk-58");
+ } else {
+ gtk_widget_destroy (dialog_win);
+ }
+}
+
+static void
+try_spawn_config_tool (GdkScreen *screen)
+{
+ GError *error;
+
+ error = NULL;
+ mate_wm_manager_spawn_config_tool_for_current (screen, &error);
+
+ if (error != NULL) {
+ GtkWidget *no_tool_dialog;
+ char *str;
+ char *escaped;
+
+ escaped = g_markup_escape_text (error->message, -1);
+
+ str = g_strdup_printf ("<b>%s</b>\n\n%s",
+ _("Cannot start the preferences application for your window manager"),
+ escaped);
+ g_free (escaped);
+
+ no_tool_dialog =
+ gtk_message_dialog_new (NULL,
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ " ");
+ gtk_window_set_title (GTK_WINDOW (no_tool_dialog), "");
+ gtk_window_set_resizable (GTK_WINDOW (no_tool_dialog), FALSE);
+
+ gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (no_tool_dialog), str);
+
+ g_free (str);
+
+ gtk_dialog_run (GTK_DIALOG (no_tool_dialog));
+
+ gtk_widget_destroy (no_tool_dialog);
+ g_error_free (error);
+
+ exit (1);
+ }
+
+ /* exit, let the config tool handle it */
+ exit (0);
+}
+
+int
+main (int argc, char **argv)
+{
+ GdkScreen *screen;
+ MateWMSettings new_settings;
+ GtkBuilder *builder;
+ GError *error = NULL;
+ int rc = 0;
+ int i;
+
+ bindtextdomain (GETTEXT_PACKAGE, MATELOCALEDIR);
+ bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
+ textdomain (GETTEXT_PACKAGE);
+
+ gtk_init (&argc, &argv);
+
+ mate_wm_manager_init ();
+
+ screen = gdk_display_get_default_screen (gdk_display_get_default ());
+
+ current_wm = mate_wm_manager_get_current (screen);
+
+ if (current_wm == NULL) {
+ try_spawn_config_tool (screen);
+ goto out;
+ }
+
+ builder = gtk_builder_new ();
+ gtk_builder_set_translation_domain (builder, GETTEXT_PACKAGE);
+
+ if (gtk_builder_add_from_file (builder, UIDIR "/mate-window-properties.ui", &error) == 0) {
+ g_warning ("Could not parse UI file: %s", error->message);
+ g_error_free (error);
+ g_object_unref (builder);
+ rc = 1;
+ goto out;
+ }
+
+ dialog_win = GTK_WIDGET (gtk_builder_get_object (builder,
+ "main-dialog"));
+ focus_mode_checkbutton = gtk_builder_get_object (builder,
+ "focus-mode-checkbutton");
+ autoraise_checkbutton = gtk_builder_get_object (builder,
+ "autoraise-checkbutton");
+ autoraise_delay_slider = gtk_builder_get_object (builder,
+ "autoraise-delay-slider");
+ autoraise_delay_hbox = GTK_WIDGET (gtk_builder_get_object (builder,
+ "autoraise-delay-hbox"));
+ double_click_titlebar_optionmenu = gtk_builder_get_object (builder,
+ "double-click-titlebar-optionmenu");
+ alt_click_hbox = gtk_builder_get_object (builder, "alt-click-box");
+
+ gtk_range_set_range (GTK_RANGE (autoraise_delay_slider),
+ 0, 10);
+
+ gtk_range_set_increments (GTK_RANGE (autoraise_delay_slider),
+ 0.2, 1.0);
+
+ new_settings.flags = 0;
+ init_settings_struct (&new_settings);
+ settings = mate_wm_settings_copy (&new_settings);
+
+ reload_mouse_modifiers ();
+ update_wm (screen, FALSE);
+
+ set_alt_click_value (&new_settings);
+ gtk_range_set_value (GTK_RANGE (autoraise_delay_slider),
+ new_settings.autoraise_delay / 1000.0);
+ gtk_combo_box_set_active (GTK_COMBO_BOX (double_click_titlebar_optionmenu),
+ new_settings.double_click_action);
+
+ reload_settings (); /* must come before below signal connections */
+
+ g_signal_connect (G_OBJECT (dialog_win), "response",
+ G_CALLBACK (response_cb), NULL);
+
+ g_signal_connect (G_OBJECT (dialog_win), "destroy",
+ G_CALLBACK (gtk_main_quit), NULL);
+
+
+ g_signal_connect (focus_mode_checkbutton, "toggled",
+ G_CALLBACK (mouse_focus_toggled_callback), NULL);
+
+ g_signal_connect (autoraise_checkbutton, "toggled",
+ G_CALLBACK (autoraise_toggled_callback), NULL);
+
+ g_signal_connect (autoraise_delay_slider, "value_changed",
+ G_CALLBACK (autoraise_delay_value_changed_callback), NULL);
+
+ g_signal_connect (double_click_titlebar_optionmenu, "changed",
+ G_CALLBACK (double_click_titlebar_changed_callback), NULL);
+
+ g_signal_connect (G_OBJECT (screen), "window_manager_changed",
+ G_CALLBACK (wm_changed_callback), NULL);
+
+ i = 0;
+ while (i < n_mouse_modifiers) {
+ g_signal_connect (G_OBJECT (mouse_modifiers[i].radio), "toggled",
+ G_CALLBACK (alt_click_radio_toggled_callback),
+ &mouse_modifiers[i]);
+ ++i;
+ }
+
+ capplet_set_icon (dialog_win, "preferences-system-windows");
+ gtk_widget_show (dialog_win);
+
+ gtk_main ();
+
+ g_object_unref (builder);
+
+out:
+ return rc;
+}
+
+#include <X11/Xlib.h>
+#include <X11/keysym.h>
+#include <gdk/gdkx.h>
+
+static void
+fill_radio (GtkRadioButton *group,
+ MouseClickModifier *modifier)
+{
+ modifier->radio =
+ gtk_radio_button_new_with_mnemonic_from_widget (group,
+ modifier->name);
+ gtk_box_pack_start (GTK_BOX (alt_click_hbox),
+ modifier->radio, FALSE, FALSE, 0);
+
+ gtk_widget_show (modifier->radio);
+}
+
+static void
+reload_mouse_modifiers (void)
+{
+ XModifierKeymap *modmap;
+ KeySym *keymap;
+ int keysyms_per_keycode;
+ int map_size;
+ int i;
+ gboolean have_meta;
+ gboolean have_hyper;
+ gboolean have_super;
+ int min_keycode, max_keycode;
+ int mod_meta, mod_super, mod_hyper;
+
+ XDisplayKeycodes (gdk_display,
+ &min_keycode,
+ &max_keycode);
+
+ keymap = XGetKeyboardMapping (gdk_display,
+ min_keycode,
+ max_keycode - min_keycode,
+ &keysyms_per_keycode);
+
+ modmap = XGetModifierMapping (gdk_display);
+
+ have_super = FALSE;
+ have_meta = FALSE;
+ have_hyper = FALSE;
+
+ /* there are 8 modifiers, and the first 3 are shift, shift lock,
+ * and control
+ */
+ map_size = 8 * modmap->max_keypermod;
+ i = 3 * modmap->max_keypermod;
+ mod_meta = mod_super = mod_hyper = 0;
+ while (i < map_size) {
+ /* get the key code at this point in the map,
+ * see if its keysym is one we're interested in
+ */
+ int keycode = modmap->modifiermap[i];
+
+ if (keycode >= min_keycode &&
+ keycode <= max_keycode) {
+ int j = 0;
+ KeySym *syms = keymap + (keycode - min_keycode) * keysyms_per_keycode;
+
+ while (j < keysyms_per_keycode) {
+ if (syms[j] == XK_Super_L ||
+ syms[j] == XK_Super_R)
+ mod_super = i / modmap->max_keypermod;
+ else if (syms[j] == XK_Hyper_L ||
+ syms[j] == XK_Hyper_R)
+ mod_hyper = i / modmap->max_keypermod;
+ else if ((syms[j] == XK_Meta_L ||
+ syms[j] == XK_Meta_R))
+ mod_meta = i / modmap->max_keypermod;
+ ++j;
+ }
+ }
+
+ ++i;
+ }
+
+ if ((1 << mod_meta) != Mod1Mask)
+ have_meta = TRUE;
+ if (mod_super != 0 &&
+ mod_super != mod_meta)
+ have_super = TRUE;
+ if (mod_hyper != 0 &&
+ mod_hyper != mod_meta &&
+ mod_hyper != mod_super)
+ have_hyper = TRUE;
+
+ XFreeModifiermap (modmap);
+ XFree (keymap);
+
+ i = 0;
+ while (i < n_mouse_modifiers) {
+ g_free (mouse_modifiers[i].name);
+ if (mouse_modifiers[i].radio)
+ gtk_widget_destroy (mouse_modifiers[i].radio);
+ ++i;
+ }
+ g_free (mouse_modifiers);
+ mouse_modifiers = NULL;
+
+ n_mouse_modifiers = 1; /* alt */
+ if (have_super)
+ ++n_mouse_modifiers;
+ if (have_hyper)
+ ++n_mouse_modifiers;
+ if (have_meta)
+ ++n_mouse_modifiers;
+
+ mouse_modifiers = g_new0 (MouseClickModifier, n_mouse_modifiers);
+
+ i = 0;
+
+ mouse_modifiers[i].number = i;
+ mouse_modifiers[i].name = g_strdup (_("_Alt"));
+ mouse_modifiers[i].value = "Alt";
+ ++i;
+
+ if (have_hyper) {
+ mouse_modifiers[i].number = i;
+ mouse_modifiers[i].name = g_strdup (_("H_yper"));
+ mouse_modifiers[i].value = "Hyper";
+ ++i;
+ }
+
+ if (have_super) {
+ mouse_modifiers[i].number = i;
+ mouse_modifiers[i].name = g_strdup (_("S_uper (or \"Windows logo\")"));
+ mouse_modifiers[i].value = "Super";
+ ++i;
+ }
+
+ if (have_meta) {
+ mouse_modifiers[i].number = i;
+ mouse_modifiers[i].name = g_strdup (_("_Meta"));
+ mouse_modifiers[i].value = "Meta";
+ ++i;
+ }
+
+ g_assert (i == n_mouse_modifiers);
+
+ i = 0;
+ while (i < n_mouse_modifiers) {
+ fill_radio (i == 0 ? NULL : GTK_RADIO_BUTTON (mouse_modifiers[i-1].radio),
+ &mouse_modifiers[i]);
+ ++i;
+ }
+}
diff --git a/capplets/windows/mate-window-properties.ui b/capplets/windows/mate-window-properties.ui
new file mode 100644
index 00000000..dee6e1aa
--- /dev/null
+++ b/capplets/windows/mate-window-properties.ui
@@ -0,0 +1,387 @@
+<?xml version="1.0"?>
+<interface>
+ <requires lib="gtk+" version="2.16"/>
+ <!-- interface-naming-policy toplevel-contextual -->
+ <object class="GtkDialog" id="main-dialog">
+ <property name="border_width">5</property>
+ <property name="title" translatable="yes">Window Preferences</property>
+ <property name="resizable">False</property>
+ <property name="type_hint">dialog</property>
+ <property name="has_separator">False</property>
+ <child internal-child="vbox">
+ <object class="GtkVBox" id="dialog-vbox1">
+ <property name="visible">True</property>
+ <property name="spacing">2</property>
+ <child>
+ <object class="GtkVBox" id="vbox1">
+ <property name="visible">True</property>
+ <property name="border_width">5</property>
+ <property name="spacing">18</property>
+ <child>
+ <object class="GtkVBox" id="vbox2">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Window Selection</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment1">
+ <property name="visible">True</property>
+ <property name="left_padding">12</property>
+ <child>
+ <object class="GtkVBox" id="vbox3">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkCheckButton" id="focus-mode-checkbutton">
+ <property name="label" translatable="yes">_Select windows when the mouse moves over them</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment2">
+ <property name="visible">True</property>
+ <property name="left_padding">12</property>
+ <child>
+ <object class="GtkVBox" id="vbox4">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkCheckButton" id="autoraise-checkbutton">
+ <property name="label" translatable="yes">_Raise selected windows after an interval</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="autoraise-delay-hbox">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="autoraise-delay-label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Interval before raising:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">autoraise-delay-slider</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox10">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkHScale" id="autoraise-delay-slider">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="adjustment">adjustment1</property>
+ <property name="value_pos">right</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="xpad">4</property>
+ <property name="label" translatable="yes">seconds</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox5">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Titlebar Action</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment3">
+ <property name="visible">True</property>
+ <property name="left_padding">12</property>
+ <child>
+ <object class="GtkVBox" id="vbox8">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkHBox" id="double-click-titlebar-hbox">
+ <property name="visible">True</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="double-click-label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Double-click titlebar to perform this action:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">double-click-titlebar-optionmenu</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBox" id="double-click-titlebar-optionmenu">
+ <property name="visible">True</property>
+ <property name="model">liststore1</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderertext1"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox6">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label5">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Movement Key</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment4">
+ <property name="visible">True</property>
+ <property name="left_padding">12</property>
+ <child>
+ <object class="GtkVBox" id="vbox7">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="alt-click-label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">To move a window, press-and-hold this key then grab the window:</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment5">
+ <property name="visible">True</property>
+ <property name="left_padding">12</property>
+ <child>
+ <object class="GtkVBox" id="alt-click-box">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <object class="GtkHButtonBox" id="dialog-action_area1">
+ <property name="visible">True</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="helpbutton1">
+ <property name="label">gtk-help</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="closebutton1">
+ <property name="label">gtk-close</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-11">helpbutton1</action-widget>
+ <action-widget response="-7">closebutton1</action-widget>
+ </action-widgets>
+ </object>
+ <object class="GtkAdjustment" id="adjustment1">
+ <property name="value">7.7000000000000002</property>
+ <property name="upper">10</property>
+ <property name="step_increment">0.20000000000000001</property>
+ <property name="page_increment">1</property>
+ </object>
+ <object class="GtkListStore" id="liststore1">
+ <columns>
+ <!-- column-name item text -->
+ <column type="gchararray"/>
+ </columns>
+ </object>
+</interface>
diff --git a/capplets/windows/window-properties.desktop.in.in b/capplets/windows/window-properties.desktop.in.in
new file mode 100644
index 00000000..afa170b3
--- /dev/null
+++ b/capplets/windows/window-properties.desktop.in.in
@@ -0,0 +1,14 @@
+[Desktop Entry]
+_Name=Windows
+_Comment=Set your window properties
+Exec=mate-window-properties
+Icon=preferences-system-windows
+Terminal=false
+Type=Application
+StartupNotify=true
+Categories=MATE;GTK;Settings;DesktopSettings;
+OnlyShowIn=MATE;
+X-MATE-Bugzilla-Bugzilla=MATE
+X-MATE-Bugzilla-Product=mate-control-center
+X-MATE-Bugzilla-Component=Window preferences
+X-MATE-Bugzilla-Version=@VERSION@