summaryrefslogtreecommitdiff
path: root/capplets/appearance
diff options
context:
space:
mode:
Diffstat (limited to 'capplets/appearance')
-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
44 files changed, 10998 insertions, 0 deletions
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);