diff options
author | Jonathan Blandford <jrb@gnome.org> | 2002-11-01 16:09:43 +0000 |
---|---|---|
committer | Jonathan Blandford <jrb@src.gnome.org> | 2002-11-01 16:09:43 +0000 |
commit | 9405d72d2fad085232190a18dab54ac04010646e (patch) | |
tree | 4863c36ee69ab0fadd7c53e1f4370e88a26f9b17 /capplets | |
parent | ce78d4d67079af0b23ceb9990dc56797574e20ce (diff) | |
download | gnome-control-center-9405d72d2fad085232190a18dab54ac04010646e.tar.gz |
Rewrote to handle metathemes and icon themes. The WM stuff was previously
Fri Nov 1 11:01:16 2002 Jonathan Blandford <jrb@gnome.org>
* gnome-theme-manager.c: Rewrote to handle metathemes and icon
themes. The WM stuff was previously broken, too.
* gnome-theme-installer.[ch]: Extract this code out to it's own
file.
Fri Nov 1 11:03:34 2002 Jonathan Blandford <jrb@gnome.org>
* gnome-theme-info.[ch]: Moved theme-common, and gave more
features.
Diffstat (limited to 'capplets')
-rw-r--r-- | capplets/common/ChangeLog | 5 | ||||
-rw-r--r-- | capplets/common/Makefile.am | 1 | ||||
-rw-r--r-- | capplets/common/gnome-theme-info.c | 646 | ||||
-rw-r--r-- | capplets/common/gnome-theme-info.h | 103 | ||||
-rw-r--r-- | capplets/theme-switcher/ChangeLog | 8 | ||||
-rw-r--r-- | capplets/theme-switcher/Makefile.am | 12 | ||||
-rw-r--r-- | capplets/theme-switcher/gnome-theme-installer.c | 183 | ||||
-rw-r--r-- | capplets/theme-switcher/gnome-theme-installer.h | 29 | ||||
-rw-r--r-- | capplets/theme-switcher/gnome-theme-manager.c | 827 | ||||
-rw-r--r-- | capplets/theme-switcher/theme-properties.glade | 392 |
10 files changed, 2193 insertions, 13 deletions
diff --git a/capplets/common/ChangeLog b/capplets/common/ChangeLog index 8cd3b09fe..b78ca5a95 100644 --- a/capplets/common/ChangeLog +++ b/capplets/common/ChangeLog @@ -1,3 +1,8 @@ +Fri Nov 1 11:03:34 2002 Jonathan Blandford <jrb@gnome.org> + + * gnome-theme-info.[ch]: Moved theme-common, and gave more + features. + 2002-10-21 Jody Goldberg <jody@gnome.org> * Release 2.1.1 diff --git a/capplets/common/Makefile.am b/capplets/common/Makefile.am index 0ae16f431..86e79557d 100644 --- a/capplets/common/Makefile.am +++ b/capplets/common/Makefile.am @@ -18,6 +18,7 @@ libcommon_la_SOURCES = \ gconf-property-editor-marshal.c gconf-property-editor-marshal.h \ file-transfer-dialog.c file-transfer-dialog.h \ theme-common.c theme-common.h \ + gnome-theme-info.c gnome-theme-info.h \ wm-common.c wm-common.h libcommon_la_LIBADD = $(top_builddir)/libbackground/libbackground.la diff --git a/capplets/common/gnome-theme-info.c b/capplets/common/gnome-theme-info.c new file mode 100644 index 000000000..36691044a --- /dev/null +++ b/capplets/common/gnome-theme-info.c @@ -0,0 +1,646 @@ +#include <config.h> + +#include <gnome.h> +#include <glade/glade.h> +#include <gconf/gconf-client.h> + +#include <sys/stat.h> +#include <sys/types.h> +#include <dirent.h> +#include <libgnomevfs/gnome-vfs-ops.h> +#include <glib-object.h> +#include <libgnome/gnome-desktop-item.h> +#include "gnome-theme-info.h" + +typedef struct _ThemeCallbackData +{ + GFunc func; + gpointer data; +} ThemeCallbackData; + + +GHashTable *theme_hash = NULL; +GHashTable *icon_theme_hash = NULL; +GHashTable *meta_theme_hash = NULL; +GList *callbacks = NULL; + + +const gchar *gtk2_suffix = "gtk-2.0"; +const gchar *key_suffix = "gtk-2.0-key"; +const gchar *metacity_suffix = "metacity-1"; +const gchar *icon_theme_file = "index.theme"; +const gchar *meta_theme_file = "theme.desktop"; + +static GnomeThemeMetaInfo * +read_meta_theme (const gchar *meta_theme_file) +{ + GnomeThemeMetaInfo *meta_theme_info; + GnomeDesktopItem *meta_theme_ditem; + const gchar *str; + + meta_theme_ditem = gnome_desktop_item_new_from_file (meta_theme_file, 0, NULL); + if (meta_theme_ditem == NULL) + return NULL; + + meta_theme_info = gnome_theme_meta_info_new (); + meta_theme_info->path = g_strdup (meta_theme_file); + + str = gnome_desktop_item_get_string (meta_theme_ditem, "Name"); + if (str == NULL) + { + gnome_theme_meta_info_free (meta_theme_info); + return NULL; + } + meta_theme_info->name = g_strdup (str); + + str = gnome_desktop_item_get_string (meta_theme_ditem, "Comment"); + if (str != NULL) + meta_theme_info->comment = g_strdup (str); + + str = gnome_desktop_item_get_string (meta_theme_ditem, "Icon"); + if (str != NULL) + meta_theme_info->icon_file = g_strdup (str); + + str = gnome_desktop_item_get_string (meta_theme_ditem, "X-GNOME-Metatheme/gtk-2.0"); + if (str == NULL) + { + gnome_theme_meta_info_free (meta_theme_info); + return NULL; + } + meta_theme_info->gtk_theme_name = g_strdup (str); + + str = gnome_desktop_item_get_string (meta_theme_ditem, "X-GNOME-Metatheme/metacity"); + if (str == NULL) + { + gnome_theme_meta_info_free (meta_theme_info); + return NULL; + } + meta_theme_info->metacity_theme_name = g_strdup (str); + + str = gnome_desktop_item_get_string (meta_theme_ditem, "X-GNOME-Metatheme/icon"); + if (str == NULL) + { + gnome_theme_meta_info_free (meta_theme_info); + return NULL; + } + meta_theme_info->icon_theme_name = g_strdup (str); + + str = gnome_desktop_item_get_string (meta_theme_ditem, "X-GNOME-Metatheme/font"); + if (str != NULL) + meta_theme_info->font = g_strdup (str); + + str = gnome_desktop_item_get_string (meta_theme_ditem, "X-GNOME-Metatheme/background"); + if (str != NULL) + meta_theme_info->background = g_strdup (str); + + return meta_theme_info; +} + +static GnomeThemeIconInfo * +read_icon_theme (const gchar *icon_theme_file) +{ + GnomeThemeIconInfo *icon_theme_info; + GnomeDesktopItem *icon_theme_ditem; + const gchar *name; + + icon_theme_ditem = gnome_desktop_item_new_from_file (icon_theme_file, 0, NULL); + if (icon_theme_ditem == NULL) + return NULL; + + name = gnome_desktop_item_get_string (icon_theme_ditem, "Icon Theme/Name"); + if (name == NULL) + return NULL; + + icon_theme_info = gnome_theme_icon_info_new (); + icon_theme_info->name = g_strdup (name); + icon_theme_info->path = g_strdup (icon_theme_file); + + return icon_theme_info; +} + +static void +update_theme_dir (const gchar *theme_dir) +{ + GnomeThemeInfo *info = NULL; + gboolean changed = FALSE; + gboolean has_gtk = FALSE; + gboolean has_keybinding = FALSE; + gboolean has_metacity = FALSE; + gchar *tmp; + + tmp = g_build_filename (theme_dir, meta_theme_file, NULL); + if (g_file_test (tmp, G_FILE_TEST_IS_REGULAR)) + { + GnomeThemeMetaInfo *meta_theme_info; + + meta_theme_info = read_meta_theme (tmp); + if (meta_theme_info != NULL) + g_hash_table_insert (meta_theme_hash, meta_theme_info->name, meta_theme_info); + } + g_free (tmp); + + tmp = g_build_filename (theme_dir, gtk2_suffix, NULL); + if (g_file_test (tmp, G_FILE_TEST_IS_DIR)) + { + has_gtk = TRUE; + } + g_free (tmp); + + tmp = g_build_filename (theme_dir, key_suffix, NULL); + if (g_file_test (tmp, G_FILE_TEST_IS_DIR)) + { + has_keybinding = TRUE; + } + g_free (tmp); + + tmp = g_build_filename (theme_dir, metacity_suffix, NULL); + if (g_file_test (tmp, G_FILE_TEST_IS_DIR)) + { + has_metacity = TRUE; + } + g_free (tmp); + + info = gnome_theme_info_find_by_dir (theme_dir); + + if (info) + { + if (!has_gtk && ! has_keybinding && ! has_metacity) + { + g_hash_table_remove (theme_hash, info->name); + gnome_theme_info_free (info); + changed = TRUE; + } + else if ((info->has_keybinding != has_keybinding) || + (info->has_gtk != has_gtk) || + (info->has_metacity != has_metacity)) + { + info->has_keybinding = has_keybinding; + info->has_gtk = has_gtk; + info->has_metacity = has_metacity; + changed = TRUE; + } + } + else + { + if (has_gtk || has_keybinding || has_metacity) + { + info = gnome_theme_info_new (); + info->path = g_strdup (theme_dir); + info->name = g_strdup (strrchr (theme_dir, '/') + 1); + info->has_gtk = has_gtk; + info->has_keybinding = has_keybinding; + info->has_metacity = has_metacity; + + g_hash_table_insert (theme_hash, info->name, info); + changed = TRUE; + } + } + if (changed) + { + GList *list; + + for (list = callbacks; list; list = list->next) + { + ThemeCallbackData *callback_data = list->data; + + (* callback_data->func) ((gpointer)theme_dir, callback_data->data); + } + } + +} + + +static void +update_icon_theme_dir (const gchar *theme_dir) +{ + GnomeThemeIconInfo *icon_theme_info = NULL; + gboolean changed = FALSE; + gchar *tmp; + + tmp = g_build_filename (theme_dir, icon_theme_file, NULL); + if (g_file_test (tmp, G_FILE_TEST_IS_REGULAR)) + { + icon_theme_info = read_icon_theme (tmp); + } + + g_free (tmp); + + if (icon_theme_info) + { + g_hash_table_insert (icon_theme_hash, icon_theme_info->name, icon_theme_info); + changed = TRUE; + } + + if (changed) + { + GList *list; + + for (list = callbacks; list; list = list->next) + { + ThemeCallbackData *callback_data = list->data; + + (* callback_data->func) ((gpointer)theme_dir, callback_data->data); + } + } +} + +static void +top_theme_dir_changed_callback (GnomeVFSMonitorHandle *handle, + const gchar *monitor_uri, + const gchar *info_uri, + GnomeVFSMonitorEventType event_type, + gpointer user_data) +{ + GFreeFunc *func = user_data; + + switch (event_type) + { + case GNOME_VFS_MONITOR_EVENT_CHANGED: + case GNOME_VFS_MONITOR_EVENT_CREATED: + case GNOME_VFS_MONITOR_EVENT_DELETED: + if (!strncmp (info_uri, "file://", strlen ("file://"))) + (*func) ((char *)info_uri + strlen ("file://")); + else + (*func) ((char *)info_uri); + break; + default: + break; + } +} + + +static void +themes_common_list_add_dir (const char *dirname) +{ + GnomeVFSMonitorHandle *handle = NULL; + DIR *dir; + struct dirent *de; + + g_return_if_fail (dirname != NULL); + + dir = opendir (dirname); + + gnome_vfs_monitor_add (&handle, + dirname, + GNOME_VFS_MONITOR_DIRECTORY, + top_theme_dir_changed_callback, + update_theme_dir); + + if (!dir) + return; + + while ((de = readdir (dir))) + { + char *tmp; + + if (de->d_name[0] == '.') + continue; + + tmp = g_build_filename (dirname, de->d_name, NULL); + update_theme_dir (tmp); + g_free (tmp); + } + closedir (dir); +} + +static void +icon_themes_add_dir (const char *dirname) +{ + GnomeVFSMonitorHandle *handle = NULL; + DIR *dir; + struct dirent *de; + + g_return_if_fail (dirname != NULL); + + dir = opendir (dirname); + gnome_vfs_monitor_add (&handle, + dirname, + GNOME_VFS_MONITOR_DIRECTORY, + top_theme_dir_changed_callback, + update_icon_theme_dir); + + if (!dir) + return; + + while ((de = readdir (dir))) + { + char *tmp; + + if (de->d_name[0] == '.') + continue; + + tmp = g_build_filename (dirname, de->d_name, NULL); + update_icon_theme_dir (tmp); + g_free (tmp); + } + closedir (dir); +} + +static void +gnome_theme_info_init (void) +{ + static gboolean initted = FALSE; + gchar *dir; + GnomeVFSURI *uri; + + if (initted) + return; + initted = TRUE; + + theme_hash = g_hash_table_new (g_str_hash, g_str_equal); + icon_theme_hash = g_hash_table_new (g_str_hash, g_str_equal); + meta_theme_hash = g_hash_table_new (g_str_hash, g_str_equal); + + dir = g_build_filename (g_get_home_dir (), ".themes", NULL); + + /* Make sure ~/.themes exists */ + uri = gnome_vfs_uri_new (dir); + if (!gnome_vfs_uri_exists (uri)) + gnome_vfs_make_directory_for_uri (uri, 0775); + gnome_vfs_uri_unref (uri); + + themes_common_list_add_dir (dir); + g_free (dir); + + dir = gtk_rc_get_theme_dir (); + themes_common_list_add_dir (dir); + g_free (dir); + + /* handle icon themes */ + dir = g_build_filename (g_get_home_dir (), ".icons", NULL); + + /* Make sure ~/.themes exists */ + uri = gnome_vfs_uri_new (dir); + if (!gnome_vfs_uri_exists (uri)) + gnome_vfs_make_directory_for_uri (uri, 0775); + gnome_vfs_uri_unref (uri); + + icon_themes_add_dir (dir); + g_free (dir); + + dir = gtk_rc_get_theme_dir (); + icon_themes_add_dir (dir); + g_free (dir); + + /* Finally, the weird backup for icon themes */ + icon_themes_add_dir ("/usr/share/icons"); +} + + +/* Public functions + */ + +/* Generic Themes */ +GnomeThemeInfo * +gnome_theme_info_new (void) +{ + GnomeThemeInfo *theme_info; + + theme_info = g_new0 (GnomeThemeInfo, 1); + + return theme_info; +} + +void +gnome_theme_info_free (GnomeThemeInfo *theme_info) +{ + g_free (theme_info->path); + g_free (theme_info->name); + g_free (theme_info); +} + +GnomeThemeInfo * +gnome_theme_info_find (const gchar *theme_name) +{ + gnome_theme_info_init (); + + return g_hash_table_lookup (theme_hash, theme_name); +} + + +struct GnomeThemeInfoHashData +{ + gconstpointer user_data; + GList *list; +}; + +static void +gnome_theme_info_find_by_type_helper (gpointer key, + gpointer value, + gpointer user_data) +{ + GnomeThemeInfo *theme_info = value; + struct GnomeThemeInfoHashData *hash_data = user_data; + guint elements = GPOINTER_TO_INT (hash_data->user_data); + gboolean add_theme = FALSE; + + if (elements & GNOME_THEME_METACITY && + theme_info->has_metacity) + add_theme = TRUE; + if (elements & GNOME_THEME_GTK_2 && + theme_info->has_gtk) + add_theme = TRUE; + if (elements & GNOME_THEME_GTK_2_KEYBINDING && + theme_info->has_keybinding) + add_theme = TRUE; + + if (add_theme) + hash_data->list = g_list_prepend (hash_data->list, theme_info); +} + + +static void +gnome_theme_info_find_by_dir_helper (gpointer key, + gpointer value, + gpointer user_data) +{ + GnomeThemeInfo *theme_info = value; + struct GnomeThemeInfoHashData *hash_data = user_data; + + if (! strcmp (hash_data->user_data, theme_info->path)) + hash_data->list = g_list_prepend (hash_data->list, theme_info); +} + +GList * +gnome_theme_info_find_by_type (guint elements) +{ + struct GnomeThemeInfoHashData data; + data.user_data = GINT_TO_POINTER (elements); + data.list = NULL; + + gnome_theme_info_init (); + + g_hash_table_foreach (theme_hash, + gnome_theme_info_find_by_type_helper, + &data); + + return data.list; +} + + +GnomeThemeInfo * +gnome_theme_info_find_by_dir (const gchar *theme_dir) +{ + struct GnomeThemeInfoHashData data; + GnomeThemeInfo *retval = NULL; + + data.user_data = theme_dir; + data.list = NULL; + + gnome_theme_info_init (); + + g_hash_table_foreach (theme_hash, + gnome_theme_info_find_by_dir_helper, + &data); + + if (data.list) + { + retval = data.list->data; + g_list_free (data.list); + } + + return retval; +} + +/* Icon themes */ +GnomeThemeIconInfo * +gnome_theme_icon_info_new (void) +{ + GnomeThemeIconInfo *icon_theme_info; + + icon_theme_info = g_new0 (GnomeThemeIconInfo, 1); + + return icon_theme_info; +} + +void +gnome_theme_icon_info_free (GnomeThemeIconInfo *icon_theme_info) +{ + g_free (icon_theme_info); +} + +GnomeThemeInfo * +gnome_theme_icon_info_find (const gchar *icon_theme_name) +{ + g_return_val_if_fail (icon_theme_name != NULL, NULL); + + gnome_theme_info_init (); + + return g_hash_table_lookup (icon_theme_hash, icon_theme_name); + +} + + + + + +static void +gnome_theme_icon_info_find_all_helper (gpointer key, + gpointer value, + gpointer user_data) +{ + GnomeThemeIconInfo *theme_info = value; + struct GnomeThemeInfoHashData *hash_data = user_data; + + hash_data->list = g_list_prepend (hash_data->list, theme_info); +} + +GList * +gnome_theme_icon_info_find_all (void) +{ + + struct GnomeThemeInfoHashData data; + data.list = NULL; + + gnome_theme_info_init (); + + g_hash_table_foreach (icon_theme_hash, + gnome_theme_icon_info_find_all_helper, + &data); + + return data.list; +} + + +/* Meta themes*/ +GnomeThemeMetaInfo * +gnome_theme_meta_info_new (void) +{ + GnomeThemeMetaInfo *meta_theme_info; + + meta_theme_info = g_new0 (GnomeThemeMetaInfo, 1); + + return meta_theme_info; +} + +void +gnome_theme_meta_info_free (GnomeThemeMetaInfo *meta_theme_info) +{ + g_free (meta_theme_info->path); + g_free (meta_theme_info->name); + g_free (meta_theme_info->comment); + g_free (meta_theme_info->font); + g_free (meta_theme_info->background); + g_free (meta_theme_info->gtk_theme_name); + g_free (meta_theme_info->icon_theme_name); + g_free (meta_theme_info->metacity_theme_name); + + g_free (meta_theme_info); +} + +GnomeThemeMetaInfo * +gnome_theme_meta_info_find (const char *meta_theme_name) +{ + g_return_val_if_fail (meta_theme_name != NULL, NULL); + + gnome_theme_info_init (); + + return g_hash_table_lookup (meta_theme_hash, meta_theme_name); +} + + + + +static void +gnome_theme_meta_info_find_all_helper (gpointer key, + gpointer value, + gpointer user_data) +{ + GnomeThemeMetaInfo *theme_info = value; + struct GnomeThemeInfoHashData *hash_data = user_data; + + hash_data->list = g_list_prepend (hash_data->list, theme_info); +} + +GList * +gnome_theme_meta_info_find_all (void) +{ + + struct GnomeThemeInfoHashData data; + data.list = NULL; + + gnome_theme_info_init (); + + g_hash_table_foreach (meta_theme_hash, + gnome_theme_meta_info_find_all_helper, + &data); + + return data.list; +} + + +void +gnome_theme_info_register_theme_change (GFunc func, + gpointer data) +{ + ThemeCallbackData *callback_data; + + g_return_if_fail (func != NULL); + + callback_data = g_new0 (ThemeCallbackData, 1); + callback_data->func = func; + callback_data->data = data; + + callbacks = g_list_prepend (callbacks, callback_data); +} + diff --git a/capplets/common/gnome-theme-info.h b/capplets/common/gnome-theme-info.h new file mode 100644 index 000000000..2063396cf --- /dev/null +++ b/capplets/common/gnome-theme-info.h @@ -0,0 +1,103 @@ +/* gnome-theme-info.h - GNOME Theme information + + Copyright (C) 2002 Jonathan Blandford <jrb@gnome.org> + All rights reserved. + + This file is part of the Gnome Library. + + The Gnome Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Gnome Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Gnome Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ +/* + @NOTATION@ + */ + +#ifndef GNOME_THEME_INFO_H +#define GNOME_THEME_INFO_H + +#include <glib.h> + + +typedef enum { + GNOME_THEME_METACITY = 1 << 0, + GNOME_THEME_GTK_2 = 1 << 1, + GNOME_THEME_GTK_2_KEYBINDING = 1 << 2, +} GnomeThemeElement; + +typedef struct _GnomeThemeInfo GnomeThemeInfo; +struct _GnomeThemeInfo +{ + gchar *path; + gchar *name; + guint has_gtk : 1; + guint has_keybinding : 1; + guint has_metacity : 1; + guint user_writable : 1; +}; + +typedef struct _GnomeThemeIconInfo GnomeThemeIconInfo; +struct _GnomeThemeIconInfo +{ + gchar *path; + gchar *name; +}; + +typedef struct _GnomeThemeMetaInfo GnomeThemeMetaInfo; +struct _GnomeThemeMetaInfo +{ + gchar *path; + gchar *name; + gchar *font; + gchar *comment; + gchar *icon_file; + gchar *background; + gchar *gtk_theme_name; + gchar *icon_theme_name; + gchar *metacity_theme_name; + GnomeThemeInfo *gtk_theme; + GnomeThemeInfo *icon_theme; + GnomeThemeInfo *metacity_theme; +}; + + +/* Generic Themes */ +GnomeThemeInfo *gnome_theme_info_new (void); +void gnome_theme_info_free (GnomeThemeInfo *theme_info); +GnomeThemeInfo *gnome_theme_info_find (const gchar *theme_name); +GList *gnome_theme_info_find_by_type (guint elements); +GnomeThemeInfo *gnome_theme_info_find_by_dir (const gchar *theme_dir); + + + +/* Icon Themes */ +GnomeThemeIconInfo *gnome_theme_icon_info_new (void); +void gnome_theme_icon_info_free (GnomeThemeIconInfo *icon_theme_info); +GnomeThemeInfo *gnome_theme_icon_info_find (const gchar *icon_theme_name); +GList *gnome_theme_icon_info_find_all (void); + + +/* Meta themes*/ +GnomeThemeMetaInfo *gnome_theme_meta_info_new (void); +void gnome_theme_meta_info_free (GnomeThemeMetaInfo *meta_theme_info); +GnomeThemeMetaInfo *gnome_theme_meta_info_find (const char *meta_theme_name); +GList *gnome_theme_meta_info_find_all (void); + + + +/* Theme monitoring */ +void gnome_theme_info_register_theme_change (GFunc func, + gpointer data); + + +#endif /* GNOME_THEME_INFO_H */ diff --git a/capplets/theme-switcher/ChangeLog b/capplets/theme-switcher/ChangeLog index 021561d51..33fc73850 100644 --- a/capplets/theme-switcher/ChangeLog +++ b/capplets/theme-switcher/ChangeLog @@ -1,3 +1,11 @@ +Fri Nov 1 11:01:16 2002 Jonathan Blandford <jrb@gnome.org> + + * gnome-theme-manager.c: Rewrote to handle metathemes and icon + themes. The WM stuff was previously broken, too. + + * gnome-theme-installer.[ch]: Extract this code out to it's own + file. + 2002-10-26 Havoc Pennington <hp@pobox.com> * theme-switcher.c (window_read_themes): adapt to gnome-wm-manager diff --git a/capplets/theme-switcher/Makefile.am b/capplets/theme-switcher/Makefile.am index 364556ab7..8df1db6dc 100644 --- a/capplets/theme-switcher/Makefile.am +++ b/capplets/theme-switcher/Makefile.am @@ -1,12 +1,14 @@ -bin_PROGRAMS = gnome-theme-properties +bin_PROGRAMS = gnome-theme-manager -gnome_theme_properties_LDADD = \ +gnome_theme_manager_LDADD = \ $(GNOMECC_CAPPLETS_LIBS) \ $(top_builddir)/libwindow-settings/libgnome-window-settings.la -gnome_theme_properties_SOURCES = \ - theme-switcher.c -gnome_theme_properties_LDFLAGS = -export-dynamic +gnome_theme_manager_SOURCES = \ + gnome-theme-manager.c \ + gnome-theme-installer.c + +gnome_theme_manager_LDFLAGS = -export-dynamic @INTLTOOL_DESKTOP_RULE@ diff --git a/capplets/theme-switcher/gnome-theme-installer.c b/capplets/theme-switcher/gnome-theme-installer.c new file mode 100644 index 000000000..335723cd2 --- /dev/null +++ b/capplets/theme-switcher/gnome-theme-installer.c @@ -0,0 +1,183 @@ + +#include <config.h> + +#include <string.h> +#include <libwindow-settings/gnome-wm-manager.h> +#include "gnome-theme-installer.h" +#include <gtk/gtk.h> +#include <gconf/gconf-client.h> +#include <glade/glade.h> +#include <libgnomevfs/gnome-vfs-async-ops.h> +#include <libgnomevfs/gnome-vfs-ops.h> +#include <libgnomevfs/gnome-vfs-utils.h> + +#include "gnome-theme-info.h" +#include "capplet-util.h" +#include "activate-settings-daemon.h" +#include "gconf-property-editor.h" +#include "file-transfer-dialog.h" +#include "gnome-theme-installer.h" + + +static void +transfer_cancel_cb (GtkWidget *dlg, gchar *path) +{ + gnome_vfs_unlink (path); + g_free (path); + gtk_widget_destroy (dlg); +} + +/* 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 +transfer_done_targz_idle_cb (gpointer data) +{ + int status; + gchar *command; + gchar *path = data; + + /* this should be something more clever and nonblocking */ + command = g_strdup_printf ("sh -c 'gzip -d -c < \"%s\" | tar xf - -C \"%s/.themes\"'", + path, g_get_home_dir ()); + if (g_spawn_command_line_sync (command, NULL, NULL, &status, NULL) && status == 0) + gnome_vfs_unlink (path); + g_free (command); + g_free (path); + + return FALSE; +} + + +/* 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 +transfer_done_tarbz2_idle_cb (gpointer data) +{ + int status; + gchar *command; + gchar *path = data; + + /* this should be something more clever and nonblocking */ + command = g_strdup_printf ("sh -c 'bzip2 -d -c < \"%s\" | tar xf - -C \"%s/.themes\"'", + path, g_get_home_dir ()); + if (g_spawn_command_line_sync (command, NULL, NULL, &status, NULL) && status == 0) + gnome_vfs_unlink (path); + g_free (command); + g_free (path); + + return FALSE; +} + +static void +transfer_done_cb (GtkWidget *dlg, gchar *path) +{ + int len = strlen (path); + if (path && len > 7 && !strcmp (path + len - 7, ".tar.gz")) + g_idle_add (transfer_done_targz_idle_cb, path); + if (path && len > 8 && !strcmp (path + len - 8, ".tar.bz2")) + g_idle_add (transfer_done_tarbz2_idle_cb, path); + gtk_widget_destroy (dlg); +} + +static void +install_dialog_response (GtkWidget *widget, int response_id, gpointer data) +{ + GladeXML *dialog = data; + GtkWidget *dlg; + gchar *filename, *path, *base; + GList *src, *target; + GnomeVFSURI *src_uri; + const gchar *raw; + + if (response_id == GTK_RESPONSE_HELP) { + capplet_help (GTK_WINDOW (widget), + "wgoscustdesk.xml", + "goscustdesk-12"); + return; + } + + if (response_id == 0) { + raw = gtk_entry_get_text (GTK_ENTRY (gnome_file_entry_gtk_entry (GNOME_FILE_ENTRY (WID ("install_theme_picker"))))); + if (raw == NULL || strlen (raw) <= 0) + return; + + if (strncmp (raw, "http://", 7) && strncmp (raw, "ftp://", 6) && *raw != '/') + filename = gnome_file_entry_get_full_path (GNOME_FILE_ENTRY (WID ("install_theme_picker")), TRUE); + else + filename = g_strdup (raw); + if (filename == NULL) + return; + + src_uri = gnome_vfs_uri_new (filename); + base = gnome_vfs_uri_extract_short_name (src_uri); + src = g_list_append (NULL, src_uri); + path = g_build_filename (g_get_home_dir (), ".themes", + base, NULL); + target = g_list_append (NULL, gnome_vfs_uri_new (path)); + + dlg = file_transfer_dialog_new (); + file_transfer_dialog_wrap_async_xfer (FILE_TRANSFER_DIALOG (dlg), + src, target, + GNOME_VFS_XFER_RECURSIVE, + GNOME_VFS_XFER_ERROR_MODE_QUERY, + GNOME_VFS_XFER_OVERWRITE_MODE_QUERY, + GNOME_VFS_PRIORITY_DEFAULT); + gnome_vfs_uri_list_unref (src); + gnome_vfs_uri_list_unref (target); + g_free (base); + g_free (filename); + g_signal_connect (G_OBJECT (dlg), "cancel", + G_CALLBACK (transfer_cancel_cb), path); + g_signal_connect (G_OBJECT (dlg), "done", + G_CALLBACK (transfer_done_cb), path); + gtk_widget_show (dlg); + } +} + +void +gnome_theme_installer_run (GtkWidget *parent, gchar *filename) +{ + static gboolean running_theme_install = FALSE; + GladeXML *dialog; + GtkWidget *widget; + + if (running_theme_install) + return; + + running_theme_install = TRUE; + + dialog = glade_xml_new (GLADEDIR "/theme-install.glade", NULL, NULL); + widget = WID ("install_dialog"); + + g_signal_connect (G_OBJECT (widget), "response", + G_CALLBACK (install_dialog_response), dialog); + gtk_window_set_transient_for (GTK_WINDOW (widget), parent); + gtk_window_set_position (GTK_WINDOW (widget), GTK_WIN_POS_CENTER_ON_PARENT); + if (filename) + gnome_file_entry_set_filename (GNOME_FILE_ENTRY (WID ("install_theme_picker")), filename); + + while (gtk_dialog_run (GTK_DIALOG (widget)) == GTK_RESPONSE_HELP) + ; + + gtk_widget_destroy (widget); + g_object_unref (G_OBJECT (dialog)); + + running_theme_install = FALSE; +} + diff --git a/capplets/theme-switcher/gnome-theme-installer.h b/capplets/theme-switcher/gnome-theme-installer.h new file mode 100644 index 000000000..b23ff2557 --- /dev/null +++ b/capplets/theme-switcher/gnome-theme-installer.h @@ -0,0 +1,29 @@ +/* gnome-theme-installer.h + * Copyright (C) 2002 Jonathan Blandford + * + * Written by: Jonathan Blandford <jrb@gnome.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef GNOME_THEME_INSTALLER_H +#define GNOME_THEME_INSTALLER_H + +#include <gtk/gtk.h> + +void gnome_theme_installer_run (GtkWidget *parent, gchar *filename); + +#endif /* GNOME_THEME_INSTALLER_H */ diff --git a/capplets/theme-switcher/gnome-theme-manager.c b/capplets/theme-switcher/gnome-theme-manager.c new file mode 100644 index 000000000..307c3134e --- /dev/null +++ b/capplets/theme-switcher/gnome-theme-manager.c @@ -0,0 +1,827 @@ +/* This program was written with lots of love under the GPL by Jonathan + * Blandford <jrb@gnome.org> + */ + +#include <config.h> + +#include <string.h> +#include <gtk/gtk.h> +#include <gconf/gconf-client.h> +#include <glade/glade.h> +#include <libgnomevfs/gnome-vfs-async-ops.h> +#include <libgnomevfs/gnome-vfs-ops.h> +#include <libgnomevfs/gnome-vfs-utils.h> + +#include <libwindow-settings/gnome-wm-manager.h> + +#include "gnome-theme-info.h" +#include "capplet-util.h" +#include "activate-settings-daemon.h" +#include "gconf-property-editor.h" +#include "file-transfer-dialog.h" +#include "gnome-theme-installer.h" + +/* FIXME: This shouldn't be hardcoded + */ +#define METACITY_THEME_LOCATION "/usr/share/themes" + +#define GTK_THEME_KEY "/desktop/gnome/interface/gtk_theme" +#define WINDOW_THEME_KEY "/desktop/gnome/applications/window_manager/theme" +#define ICON_THEME_KEY "/desktop/gnome/interface/icon_theme" +#define METACITY_THEME_DIR "/apps/metacity/general" +#define METACITY_THEME_KEY METACITY_THEME_DIR "/theme" + +#define META_THEME_DEFAULT_NAME "Default" +#define GTK_THEME_DEFAULT_NAME "Default" +#define WINDOW_THEME_DEFAULT_NAME "Atlanta" +#define ICON_THEME_DEFAULT_NAME "Default" + +#define MAX_ELEMENTS_BEFORE_SCROLLING 8 + +static void read_themes (GladeXML *dialog); + +enum +{ + THEME_NAME_COLUMN, + THEME_ID_COLUMN, + DEFAULT_THEME_COLUMN, + N_COLUMNS +}; + +enum +{ + TARGET_URI_LIST, + TARGET_NS_URL +}; + +static GtkTargetEntry drop_types[] = +{ + {"text/uri-list", 0, TARGET_URI_LIST}, + {"_NETSCAPE_URL", 0, TARGET_NS_URL} +}; + +static gint n_drop_types = sizeof (drop_types) / sizeof (GtkTargetEntry); + +static gboolean setting_model = FALSE; +static gboolean initial_scroll = TRUE; + +static GladeXML * +create_dialog (void) +{ + GladeXML *dialog; + + dialog = glade_xml_new (GLADEDIR "/theme-properties.glade", NULL, NULL); + + return dialog; +} + + +static void +load_theme_names (GtkTreeView *tree_view, + GList *theme_list, + char *current_theme, + gchar *default_theme) +{ + GList *list; + GtkTreeModel *model; + GtkWidget *swindow; + gint i = 0; + gboolean current_theme_found = FALSE; + GtkTreeRowReference *row_ref = NULL; + + swindow = GTK_WIDGET (tree_view)->parent; + model = gtk_tree_view_get_model (tree_view); + + setting_model = TRUE; + gtk_list_store_clear (GTK_LIST_STORE (model)); + + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow), + GTK_POLICY_NEVER, GTK_POLICY_NEVER); + gtk_widget_set_usize (swindow, -1, -1); + + for (list = theme_list; list; list = list->next) + { + const char *name = list->data; + GtkTreeIter iter; + gboolean is_default; + + gtk_list_store_prepend (GTK_LIST_STORE (model), &iter); + + if (strcmp (default_theme, name) == 0) + is_default = TRUE; + else + is_default = FALSE; + + if (strcmp (current_theme, name) == 0) + { + GtkTreePath *path = gtk_tree_model_get_path (model, &iter); + row_ref = gtk_tree_row_reference_new (model, path); + gtk_tree_path_free (path); + current_theme_found = TRUE; + } + gtk_list_store_set (GTK_LIST_STORE (model), &iter, + THEME_NAME_COLUMN, name, + DEFAULT_THEME_COLUMN, is_default, + -1); + + if (i == MAX_ELEMENTS_BEFORE_SCROLLING) + { + GtkRequisition rectangle; + gtk_widget_size_request (GTK_WIDGET (tree_view), &rectangle); + gtk_widget_set_usize (swindow, -1, rectangle.height); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow), + GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + } + i++; + } + + if (! current_theme_found) + { + GtkTreeIter iter; + GtkTreePath *path; + gboolean is_default; + + if (strcmp (default_theme, current_theme) == 0) + is_default = TRUE; + else + is_default = FALSE; + gtk_list_store_prepend (GTK_LIST_STORE (model), &iter); + gtk_list_store_set (GTK_LIST_STORE (model), &iter, + THEME_NAME_COLUMN, current_theme, + DEFAULT_THEME_COLUMN, is_default, + -1); + + path = gtk_tree_model_get_path (model, &iter); + row_ref = gtk_tree_row_reference_new (model, path); + gtk_tree_path_free (path); + } + + if (row_ref) + { + GtkTreePath *path; + + path = gtk_tree_row_reference_get_path (row_ref); + gtk_tree_view_set_cursor (tree_view,path, NULL, FALSE); + + if (initial_scroll) + { + gtk_tree_view_scroll_to_cell (tree_view, path, NULL, TRUE, 0.5, 0.0); + initial_scroll = FALSE; + } + + gtk_tree_path_free (path); + gtk_tree_row_reference_free (row_ref); + } + setting_model = FALSE; +} + +/* Shared by icons and gtk+ */ +static void +update_gconf_key_from_selection (GtkTreeSelection *selection, + const gchar *gconf_key) +{ + GtkTreeModel *model; + gchar *new_key; + GConfClient *client; + GtkTreeIter iter; + + if (setting_model) + return; + + client = gconf_client_get_default (); + + if (gtk_tree_selection_get_selected (selection, &model, &iter)) + { + gtk_tree_model_get (model, &iter, + THEME_NAME_COLUMN, &new_key, + -1); + } + else + /* This shouldn't happen */ + { + new_key = NULL; + } + + if (new_key != NULL) + { + gchar *old_key; + + old_key = gconf_client_get_string (client, gconf_key, NULL); + if (old_key && strcmp (old_key, new_key)) + { + gconf_client_set_string (client, gconf_key, new_key, NULL); + } + g_free (old_key); + } + else + { + gconf_client_unset (client, gconf_key, NULL); + } + g_free (new_key); + g_object_unref (client); +} + +static void +meta_theme_setup_info (GnomeThemeMetaInfo *meta_theme_info, + GladeXML *dialog) +{ + if (meta_theme_info == NULL) + { + gtk_widget_hide (WID ("meta_theme_extras_vbox")); + gtk_widget_hide (WID ("meta_theme_description_label")); + gtk_image_set_from_pixbuf (GTK_IMAGE (WID ("meta_theme_image")), NULL); + } + else + { + if (meta_theme_info->icon_file) + { + gtk_image_set_from_file (GTK_IMAGE (WID ("meta_theme_image")), meta_theme_info->icon_file); + } + else + { + gtk_image_set_from_pixbuf (GTK_IMAGE (WID ("meta_theme_image")), NULL); + } + if (meta_theme_info->comment) + { + gchar *real_comment; + + real_comment = g_strconcat ("<span size=\"larger\" weight=\"bold\">", + meta_theme_info->comment, + "</span>", NULL); + gtk_label_set_markup (GTK_LABEL (WID ("meta_theme_description_label")), + real_comment); + g_free (real_comment); + gtk_widget_show (WID ("meta_theme_description_label")); + } + else + { + gtk_widget_hide (WID ("meta_theme_description_label")); + } + + if (meta_theme_info->font != NULL) + { + gtk_widget_show (WID ("meta_theme_extras_vbox")); + if (meta_theme_info->background != NULL) + { + gtk_label_set_text (GTK_LABEL (WID ("meta_theme_info_label")), + _("This theme suggests the use of a font and a background:")); + gtk_widget_show (WID ("meta_theme_background_button")); + gtk_widget_show (WID ("meta_theme_font_button")); + } + else + { + gtk_label_set_text (GTK_LABEL (WID ("meta_theme_info_label")), + _("This theme suggests the use of a font:")); + gtk_widget_hide (WID ("meta_theme_background_button")); + gtk_widget_show (WID ("meta_theme_font_button")); + } + } + else + { + if (meta_theme_info->background != NULL) + { + gtk_widget_show (WID ("meta_theme_extras_vbox")); + gtk_label_set_text (GTK_LABEL (WID ("meta_theme_info_label")), + _("This theme suggests the use of a background:")); + gtk_widget_show (WID ("meta_theme_background_button")); + gtk_widget_hide (WID ("meta_theme_font_button")); + } + else + { + gtk_widget_hide (WID ("meta_theme_extras_vbox")); + gtk_widget_hide (WID ("meta_theme_background_button")); + gtk_widget_hide (WID ("meta_theme_font_button")); + } + } + } +} + +static void +meta_theme_set (GnomeThemeMetaInfo *meta_theme_info) +{ + GConfClient *client; + gchar *old_key; + GnomeWindowManager *window_manager; + GnomeWMSettings wm_settings; + + window_manager = gnome_wm_manager_get_current (gdk_display_get_default_screen (gdk_display_get_default ())); + + client = gconf_client_get_default (); + + /* Set the gtk+ key */ + old_key = gconf_client_get_string (client, GTK_THEME_KEY, NULL); + if (old_key && strcmp (old_key, meta_theme_info->gtk_theme_name)) + { + gconf_client_set_string (client, GTK_THEME_KEY, meta_theme_info->gtk_theme_name, NULL); + } + g_free (old_key); + + /* Set the wm key */ + wm_settings.flags = GNOME_WM_SETTING_THEME; + wm_settings.theme = meta_theme_info->metacity_theme_name; + gnome_window_manager_change_settings (window_manager, &wm_settings); + + /* set the icon theme */ + old_key = gconf_client_get_string (client, ICON_THEME_KEY, NULL); + if (old_key && strcmp (old_key, meta_theme_info->icon_theme_name)) + { + gconf_client_set_string (client, ICON_THEME_KEY, meta_theme_info->icon_theme_name, NULL); + } + g_free (old_key); + +} + +static void +meta_theme_selection_changed (GtkTreeSelection *selection, + GladeXML *dialog) +{ + GnomeThemeMetaInfo *meta_theme_info; + GtkTreeIter iter; + gchar *meta_theme_name; + GtkTreeModel *model; + + if (gtk_tree_selection_get_selected (selection, &model, &iter)) + { + gtk_tree_model_get (model, &iter, + THEME_NAME_COLUMN, &meta_theme_name, + -1); + } + else + /* This shouldn't happen */ + return; + + meta_theme_info = gnome_theme_meta_info_find (meta_theme_name); + meta_theme_setup_info (meta_theme_info, dialog); + + if (setting_model) + return; + + if (meta_theme_info) + meta_theme_set (meta_theme_info); +} + +static void +gtk_theme_selection_changed (GtkTreeSelection *selection, + gpointer data) +{ + update_gconf_key_from_selection (selection, GTK_THEME_KEY); +} + +static void +window_theme_selection_changed (GtkTreeSelection *selection, + gpointer data) +{ + GnomeWindowManager *window_manager; + GnomeWMSettings wm_settings; + GtkTreeIter iter; + gchar *window_theme_name; + GtkTreeModel *model; + + if (setting_model) + return; + + if (gtk_tree_selection_get_selected (selection, &model, &iter)) + { + gtk_tree_model_get (model, &iter, + THEME_NAME_COLUMN, &window_theme_name, + -1); + } + else + /* This shouldn't happen */ + return; + + window_manager = gnome_wm_manager_get_current (gdk_display_get_default_screen (gdk_display_get_default ())); + + wm_settings.flags = GNOME_WM_SETTING_THEME; + wm_settings.theme = window_theme_name; + gnome_window_manager_change_settings (window_manager, &wm_settings); + +} + +static void +icon_theme_selection_changed (GtkTreeSelection *selection, + gpointer data) +{ + update_gconf_key_from_selection (selection, ICON_THEME_KEY); +} + + +/* This function will adjust the UI to reflect the current theme/gconf + * situation. It is called after the themes change on disk, or a gconf-key + * changes. + */ +static void +read_themes (GladeXML *dialog) +{ + GList *theme_list; + GList *string_list; + GList *list; + GConfClient *client; + gchar *current_meta_theme; + gchar *current_gtk_theme; + gchar *current_window_theme; + gchar *current_icon_theme; + GnomeWindowManager *window_manager; + GnomeWMSettings wm_settings; + + client = gconf_client_get_default (); + + current_meta_theme = NULL; + current_gtk_theme = gconf_client_get_string (client, GTK_THEME_KEY, NULL); + current_icon_theme = gconf_client_get_string (client, ICON_THEME_KEY, NULL); + window_manager = gnome_wm_manager_get_current (gdk_display_get_default_screen (gdk_display_get_default ())); + wm_settings.flags = GNOME_WM_SETTING_THEME; + gnome_window_manager_get_settings (window_manager, &wm_settings); + current_window_theme = g_strdup (wm_settings.theme); + + if (current_icon_theme == NULL) + current_icon_theme = g_strdup ("Default"); + if (current_gtk_theme == NULL) + current_gtk_theme = g_strdup ("Default"); + + /* First, we update the GTK+ themes page */ + theme_list = gnome_theme_info_find_by_type (GNOME_THEME_GTK_2); + string_list = NULL; + for (list = theme_list; list; list = list->next) + { + GnomeThemeInfo *info = list->data; + string_list = g_list_prepend (string_list, info->name); + } + + load_theme_names (GTK_TREE_VIEW (WID ("control_theme_treeview")), string_list, current_gtk_theme, GTK_THEME_DEFAULT_NAME); + g_list_free (string_list); + g_list_free (theme_list); + + /* Next, we do the window managers */ + string_list = gnome_window_manager_get_theme_list (window_manager); + load_theme_names (GTK_TREE_VIEW (WID ("window_theme_treeview")), string_list, current_window_theme, WINDOW_THEME_DEFAULT_NAME); + g_list_free (string_list); + + /* Third, we do the icon theme */ + theme_list = gnome_theme_icon_info_find_all (); + string_list = NULL; + + for (list = theme_list; list; list = list->next) + { + GnomeThemeIconInfo *info = list->data; + string_list = g_list_prepend (string_list, info->name); + } + + load_theme_names (GTK_TREE_VIEW (WID ("icon_theme_treeview")), string_list, current_icon_theme, ICON_THEME_DEFAULT_NAME); + g_list_free (string_list); + g_list_free (theme_list); + + /* Finally, we do the Meta themes */ + theme_list = gnome_theme_meta_info_find_all (); + string_list = NULL; + for (list = theme_list; list; list = list->next) + { + GnomeThemeMetaInfo *info = list->data; + + if (! strcmp (info->gtk_theme_name, current_gtk_theme) && + ! strcmp (info->icon_theme_name, current_icon_theme) && + ! strcmp (info->metacity_theme_name, current_window_theme)) + { + current_meta_theme = g_strdup (info->name); + } + string_list = g_list_prepend (string_list, info->name); + } + + if (current_meta_theme == NULL) + current_meta_theme = g_strdup (_("Current modified")); + + load_theme_names (GTK_TREE_VIEW (WID ("meta_theme_treeview")), string_list, current_meta_theme, META_THEME_DEFAULT_NAME); + g_list_free (string_list); + g_list_free (theme_list); + + + g_free (current_gtk_theme); + g_free (current_icon_theme); + g_free (current_meta_theme); +} + + +static void +theme_key_changed (GConfClient *client, + guint cnxn_id, + GConfEntry *entry, + gpointer user_data) +{ + if (!strcmp (entry->key, GTK_THEME_KEY) || !strcmp (entry->key, ICON_THEME_KEY)) + { + read_themes ((GladeXML *)user_data); + } +} + +static void +window_settings_changed (GnomeWindowManager *window_manager, + GladeXML *dialog) +{ + /* We regretfully reread the entire capplet when this happens. + * We should prolly change the lib to pass in a mask of changes. + */ + read_themes (dialog); +} + +static void +icon_key_changed (GConfClient *client, + guint cnxn_id, + GConfEntry *entry, + gpointer user_data) +{ + if (strcmp (entry->key, ICON_THEME_KEY)) + return; + + read_themes ((GladeXML *)user_data); +} + +static void +theme_changed_func (gpointer uri, + gpointer user_data) +{ + read_themes ((GladeXML *)user_data); +} + +static gint +sort_func (GtkTreeModel *model, + GtkTreeIter *a, + GtkTreeIter *b, + gpointer user_data) +{ + gchar *a_str = NULL; + gchar *b_str = NULL; + gboolean a_default = FALSE; + gboolean b_default = FALSE; + gint retval; + + gtk_tree_model_get (model, a, + THEME_NAME_COLUMN, &a_str, + DEFAULT_THEME_COLUMN, &a_default, + -1); + gtk_tree_model_get (model, b, + THEME_NAME_COLUMN, &b_str, + DEFAULT_THEME_COLUMN, &b_default, + -1); + + if (a_str == NULL) a_str = g_strdup (""); + if (b_str == NULL) b_str = g_strdup (""); + + if (a_default) + retval = -1; + else if (b_default) + retval = 1; + else + retval = g_utf8_collate (a_str, b_str); + + g_free (a_str); + g_free (b_str); + + return retval; +} + +/* Show the nautilus themes window */ +static void +window_show_manage_themes (GtkWidget *button, gpointer data) +{ + gchar *path, *command; + GnomeVFSURI *uri; + GnomeWindowManager *wm; + + wm = gnome_wm_manager_get_current (gdk_display_get_default_screen (gdk_display_get_default ())); + + path = gnome_window_manager_get_user_theme_folder (wm); + g_object_unref (G_OBJECT (wm)); + + uri = gnome_vfs_uri_new (path); + + if (!gnome_vfs_uri_exists (uri)) { + /* Create the directory */ + gnome_vfs_make_directory_for_uri (uri, 0775); + } + gnome_vfs_uri_unref (uri); + + + command = g_strdup_printf ("nautilus --no-desktop %s", path); + g_free (path); + + g_spawn_command_line_async (command, NULL); + g_free (command); +} + + +static void +show_install_dialog (GtkWidget *button, gpointer parent) +{ + gnome_theme_installer_run (parent, NULL); +} +/* Callback issued during drag movements */ + +static gboolean +drag_motion_cb (GtkWidget *widget, GdkDragContext *context, + gint x, gint y, guint time, gpointer data) +{ + return FALSE; +} + +/* Callback issued during drag leaves */ + +static void +drag_leave_cb (GtkWidget *widget, GdkDragContext *context, + guint time, gpointer data) +{ + gtk_widget_queue_draw (widget); +} + +/* Callback issued on actual drops. Attempts to load the file dropped. */ +static void +drag_data_received_cb (GtkWidget *widget, GdkDragContext *context, + gint x, gint y, + GtkSelectionData *selection_data, + guint info, guint time, gpointer data) +{ + GList *uris; + gchar *filename = NULL; + + if (!(info == TARGET_URI_LIST || info == TARGET_NS_URL)) + return; + + uris = gnome_vfs_uri_list_parse ((gchar *) selection_data->data); + if (uris != NULL && uris->data != NULL) { + GnomeVFSURI *uri = (GnomeVFSURI *) uris->data; + filename = gnome_vfs_unescape_string ( + gnome_vfs_uri_get_path (uri), G_DIR_SEPARATOR_S); + gnome_vfs_uri_list_unref (uris); + } + + gnome_theme_installer_run (widget, filename); + g_free (filename); +} + +/* Starts nautilus on the themes directory*/ +static void +show_manage_themes (GtkWidget *button, gpointer data) +{ + gchar *path, *command; + GnomeVFSURI *uri; + + path = g_strdup_printf ("%s/.themes", g_get_home_dir ()); + uri = gnome_vfs_uri_new (path); + + if (!gnome_vfs_uri_exists (uri)) { + /* Create the directory */ + gnome_vfs_make_directory_for_uri (uri, 0775); + } + gnome_vfs_uri_unref (uri); + + command = g_strdup_printf ("nautilus --no-desktop %s", path); + g_free (path); + + g_spawn_command_line_async (command, NULL); + g_free (command); +} + +static void +cb_dialog_response (GtkDialog *dialog, gint response_id) +{ + if (response_id == GTK_RESPONSE_HELP) + capplet_help (GTK_WINDOW (dialog), + "wgoscustdesk.xml", + "goscustdesk-12"); + else + gtk_main_quit (); +} + +static void +setup_tree_view (GtkTreeView *tree_view, + GCallback changed_callback, + GladeXML *dialog) +{ + GtkTreeModel *model; + GtkTreeSelection *selection; + + gtk_tree_view_insert_column_with_attributes (tree_view, + -1, NULL, + gtk_cell_renderer_text_new (), + "text", THEME_NAME_COLUMN, + NULL); + + model = (GtkTreeModel *) gtk_list_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN); + gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (model), 0, sort_func, NULL, NULL); + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model), 0, GTK_SORT_ASCENDING); + gtk_tree_view_set_model (tree_view, model); + selection = gtk_tree_view_get_selection (tree_view); + gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE); + g_signal_connect (G_OBJECT (selection), "changed", changed_callback, dialog); +} + +static void +setup_dialog (GladeXML *dialog) +{ + GConfClient *client; + GtkWidget *parent, *widget; + GnomeWindowManager *window_manager; + + client = gconf_client_get_default (); + window_manager = gnome_wm_manager_get_current (gdk_display_get_default_screen (gdk_display_get_default ())); + parent = WID ("theme_dialog"); + + setup_tree_view (GTK_TREE_VIEW (WID ("meta_theme_treeview")), + (GCallback) meta_theme_selection_changed, + dialog); + setup_tree_view (GTK_TREE_VIEW (WID ("control_theme_treeview")), + (GCallback) gtk_theme_selection_changed, + dialog); + setup_tree_view (GTK_TREE_VIEW (WID ("window_theme_treeview")), + (GCallback) window_theme_selection_changed, + dialog); + setup_tree_view (GTK_TREE_VIEW (WID ("icon_theme_treeview")), + (GCallback) icon_theme_selection_changed, + dialog); + + gconf_client_add_dir (client, "/desktop/gnome/interface", GCONF_CLIENT_PRELOAD_ONELEVEL, NULL); + + gconf_client_notify_add (client, + GTK_THEME_KEY, + (GConfClientNotifyFunc) &theme_key_changed, + dialog, NULL, NULL); + gconf_client_notify_add (client, + ICON_THEME_KEY, + (GConfClientNotifyFunc) &icon_key_changed, + dialog, NULL, NULL); + + g_signal_connect (G_OBJECT (window_manager), "settings_changed", (GCallback)window_settings_changed, dialog); + read_themes (dialog); + + gnome_theme_info_register_theme_change (theme_changed_func, dialog); + + /* gtk themes */ + widget = WID ("control_install_button"); + g_signal_connect (G_OBJECT (widget), "clicked", + G_CALLBACK (show_install_dialog), parent); + widget = WID ("control_manage_button"); + g_signal_connect (G_OBJECT (widget), "clicked", + G_CALLBACK (show_manage_themes), dialog); + + /* window manager themes */ + widget = WID ("window_install_button"); + g_signal_connect (G_OBJECT (widget), "clicked", + G_CALLBACK (show_install_dialog), parent); + widget = WID ("window_manage_button"); + g_signal_connect (G_OBJECT (widget), "clicked", + G_CALLBACK (window_show_manage_themes), dialog); + + /* icon themes */ + widget = WID ("icon_install_button"); + g_signal_connect (G_OBJECT (widget), "clicked", + G_CALLBACK (show_install_dialog), parent); + widget = WID ("icon_manage_button"); + g_signal_connect (G_OBJECT (widget), "clicked", + G_CALLBACK (show_manage_themes), dialog); + + /* + g_signal_connect (G_OBJECT (WID ("install_dialog")), "response", + G_CALLBACK (install_dialog_response), dialog); + */ + + g_signal_connect (G_OBJECT (parent), + "response", + G_CALLBACK (cb_dialog_response), NULL); + + gtk_drag_dest_set (parent, GTK_DEST_DEFAULT_ALL, + drop_types, n_drop_types, + GDK_ACTION_COPY | GDK_ACTION_LINK | GDK_ACTION_MOVE); + + g_signal_connect (G_OBJECT (parent), "drag-motion", + G_CALLBACK (drag_motion_cb), NULL); + g_signal_connect (G_OBJECT (parent), "drag-leave", + G_CALLBACK (drag_leave_cb), NULL); + g_signal_connect (G_OBJECT (parent), "drag-data-received", + G_CALLBACK (drag_data_received_cb), + dialog); + + capplet_set_icon (parent, "gnome-ccthemes.png"); + gtk_widget_show (parent); +} + +int +main (int argc, char *argv[]) +{ + GladeXML *dialog; + + bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + textdomain (GETTEXT_PACKAGE); + gnome_program_init ("gnome-theme-properties", VERSION, + LIBGNOMEUI_MODULE, argc, argv, + GNOME_PARAM_APP_DATADIR, GNOMECC_DATA_DIR, + NULL); + + gnome_wm_manager_init (); + activate_settings_daemon (); + dialog = create_dialog (); + + setup_dialog (dialog); + gtk_main (); + + return 0; +} diff --git a/capplets/theme-switcher/theme-properties.glade b/capplets/theme-switcher/theme-properties.glade index 8690310c0..33bfcba96 100644 --- a/capplets/theme-switcher/theme-properties.glade +++ b/capplets/theme-switcher/theme-properties.glade @@ -72,6 +72,216 @@ <property name="enable_popup">False</property> <child> + <widget class="GtkHBox" id="hbox9"> + <property name="border_width">8</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">8</property> + + <child> + <widget class="GtkScrolledWindow" id="theme_swindow"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="shadow_type">GTK_SHADOW_IN</property> + <property name="window_placement">GTK_CORNER_TOP_LEFT</property> + + <child> + <widget class="GtkTreeView" id="meta_theme_treeview"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="headers_visible">False</property> + <property name="rules_hint">False</property> + <property name="reorderable">False</property> + <property name="enable_search">True</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox7"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">9</property> + + <child> + <widget class="GtkAlignment" id="alignment1"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">0</property> + <property name="yscale">0</property> + + <child> + <widget class="GtkFrame" id="frame1"> + <property name="visible">True</property> + <property name="label_xalign">0</property> + <property name="label_yalign">0.5</property> + <property name="shadow_type">GTK_SHADOW_IN</property> + + <child> + <widget class="GtkImage" id="meta_theme_image"> + <property name="width_request">320</property> + <property name="height_request">240</property> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="meta_theme_description_label"> + <property name="visible">True</property> + <property name="label" translatable="yes"></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="meta_theme_extras_vbox"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">3</property> + + <child> + <widget class="GtkHSeparator" id="hseparator1"> + <property name="visible">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="meta_theme_info_label"> + <property name="visible">True</property> + <property name="label" translatable="yes"></property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">True</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHButtonBox" id="hbuttonbox1"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_SPREAD</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkButton" id="meta_theme_background_button"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Apply _Background</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + </widget> + </child> + + <child> + <widget class="GtkButton" id="meta_theme_font_button"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Apply _Font</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">GTK_PACK_END</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="tab_expand">False</property> + <property name="tab_fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label14"> + <property name="visible">True</property> + <property name="label" translatable="yes">Theme</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="type">tab</property> + </packing> + </child> + + <child> <widget class="GtkVBox" id="vbox1"> <property name="visible">True</property> <property name="homogeneous">False</property> @@ -91,7 +301,7 @@ <property name="spacing">8</property> <child> - <widget class="GtkScrolledWindow" id="theme_swindow"> + <widget class="GtkScrolledWindow" id="control_theme_swindow"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="hscrollbar_policy">GTK_POLICY_ALWAYS</property> @@ -100,7 +310,7 @@ <property name="window_placement">GTK_CORNER_TOP_LEFT</property> <child> - <widget class="GtkTreeView" id="theme_treeview"> + <widget class="GtkTreeView" id="control_theme_treeview"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="headers_visible">False</property> @@ -124,7 +334,7 @@ <property name="spacing">8</property> <child> - <widget class="GtkButton" id="install_button"> + <widget class="GtkButton" id="control_install_button"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="label" translatable="yes">_Install New Theme...</property> @@ -139,7 +349,7 @@ </child> <child> - <widget class="GtkButton" id="manage_button"> + <widget class="GtkButton" id="control_manage_button"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="label" translatable="yes">_Go to theme folder</property> @@ -235,7 +445,7 @@ <child> <widget class="GtkLabel" id="label11"> <property name="visible">True</property> - <property name="label" translatable="yes">Widget Theme</property> + <property name="label" translatable="yes">Controls</property> <property name="use_underline">False</property> <property name="use_markup">False</property> <property name="justify">GTK_JUSTIFY_LEFT</property> @@ -268,8 +478,8 @@ <widget class="GtkScrolledWindow" id="window_theme_swindow"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="hscrollbar_policy">GTK_POLICY_ALWAYS</property> - <property name="vscrollbar_policy">GTK_POLICY_ALWAYS</property> + <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> <property name="shadow_type">GTK_SHADOW_IN</property> <property name="window_placement">GTK_CORNER_TOP_LEFT</property> @@ -401,7 +611,173 @@ <child> <widget class="GtkLabel" id="label12"> <property name="visible">True</property> - <property name="label" translatable="yes">Window Border Theme</property> + <property name="label" translatable="yes">Window Border</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="type">tab</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox9"> + <property name="border_width">8</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">8</property> + + <child> + <widget class="GtkHBox" id="hbox10"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">8</property> + + <child> + <widget class="GtkScrolledWindow" id="icon_theme_swindow"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_ALWAYS</property> + <property name="vscrollbar_policy">GTK_POLICY_ALWAYS</property> + <property name="shadow_type">GTK_SHADOW_IN</property> + <property name="window_placement">GTK_CORNER_TOP_LEFT</property> + + <child> + <widget class="GtkTreeView" id="icon_theme_treeview"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="headers_visible">False</property> + <property name="rules_hint">False</property> + <property name="reorderable">False</property> + <property name="enable_search">True</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox10"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">8</property> + + <child> + <widget class="GtkButton" id="icon_install_button"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">_Install New Theme...</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkButton" id="icon_manage_button"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">_Go to theme folder</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox11"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">8</property> + + <child> + <widget class="GtkImage" id="image4"> + <property name="visible">True</property> + <property name="stock">gtk-dialog-info</property> + <property name="icon_size">6</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label16"> + <property name="visible">True</property> + <property name="label" translatable="yes">New themes can also be installed by dragging them into the window.</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">True</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="tab_expand">False</property> + <property name="tab_fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label15"> + <property name="visible">True</property> + <property name="label" translatable="yes">Icons</property> <property name="use_underline">False</property> <property name="use_markup">False</property> <property name="justify">GTK_JUSTIFY_LEFT</property> |