Mercurial > pidgin
changeset 27203:d629a42c8340
Allow drag-and-drop of all sorts of themes.
Patch from Justin "ffdragon6" Rodriguez. Closes #8085.
committer: Paul Aurich <paul@darkrain42.org>
author | Justin Rodriguez <ffdragon@soc.pidgin.im> |
---|---|
date | Sun, 28 Jun 2009 06:28:46 +0000 |
parents | 9ad4b5200f24 |
children | 7685f06c7801 |
files | libpurple/theme-manager.c libpurple/theme-manager.h pidgin/gtkprefs.c |
diffstat | 3 files changed, 461 insertions(+), 234 deletions(-) [+] |
line wrap: on
line diff
--- a/libpurple/theme-manager.c Sun Jun 28 06:26:48 2009 +0000 +++ b/libpurple/theme-manager.c Sun Jun 28 06:28:46 2009 +0000 @@ -294,3 +294,16 @@ g_hash_table_foreach(theme_table, (GHFunc) purple_theme_manager_function_wrapper, func); } + +PurpleTheme * +purple_theme_manager_load_theme(const gchar *theme_dir, const gchar *type) +{ + PurpleThemeLoader *loader; + + g_return_val_if_fail(theme_dir != NULL && type != NULL, NULL); + + loader = g_hash_table_lookup(theme_table, type); + g_return_val_if_fail(PURPLE_IS_THEME_LOADER(loader), NULL); + + return purple_theme_loader_build(loader, theme_dir); +}
--- a/libpurple/theme-manager.h Sun Jun 28 06:26:48 2009 +0000 +++ b/libpurple/theme-manager.h Sun Jun 28 06:28:46 2009 +0000 @@ -127,5 +127,13 @@ */ void purple_theme_manager_for_each_theme(PTFunc func); +/** + * Loads a theme of the given type without adding it to the manager + * + * @param theme_dir the directory of the theme to load + * @param type the type of theme to load + */ +PurpleTheme *purple_theme_manager_load_theme(const gchar *theme_dir, const gchar *type); + G_END_DECLS #endif /* PURPLE_THEME_MANAGER_H */
--- a/pidgin/gtkprefs.c Sun Jun 28 06:26:48 2009 +0000 +++ b/pidgin/gtkprefs.c Sun Jun 28 06:28:46 2009 +0000 @@ -61,6 +61,12 @@ #define PREFS_OPTIMAL_ICON_SIZE 32 +struct theme_info { + gchar *type; + gchar *extension; + gchar *original_name; +}; + static int sound_row_sel = 0; static GtkWidget *prefsnotebook; @@ -74,11 +80,13 @@ static int notebook_page = 0; static GtkTreeRowReference *previous_smiley_row = NULL; -static gboolean prefs_themes_unsorted = TRUE; static GtkListStore *prefs_sound_themes; static GtkListStore *prefs_blist_themes; static GtkListStore *prefs_status_icon_themes; +static GtkWidget *prefs_sound_themes_combo_box; +static GtkWidget *prefs_blist_themes_combo_box; +static GtkWidget *prefs_status_themes_combo_box; /* * PROTOTYPES @@ -442,141 +450,6 @@ return row_ref; } -static void theme_install_theme(char *path, char *extn) { -#ifndef _WIN32 - gchar *command; -#endif - gchar *destdir; - gchar *tail; - GtkTreeRowReference *theme_rowref; - - /* Just to be safe */ - g_strchomp(path); - - /* I dont know what you are, get out of here */ - if (extn != NULL) - tail = extn; - else if ((tail = strrchr(path, '.')) == NULL) - return; - - destdir = g_strconcat(purple_user_dir(), G_DIR_SEPARATOR_S "smileys", NULL); - - /* We'll check this just to make sure. This also lets us do something different on - * other platforms, if need be */ - if (!g_ascii_strcasecmp(tail, ".gz") || !g_ascii_strcasecmp(tail, ".tgz")) { -#ifndef _WIN32 - gchar *path_escaped = g_shell_quote(path); - gchar *destdir_escaped = g_shell_quote(destdir); - command = g_strdup_printf("tar > /dev/null xzf %s -C %s", path_escaped, destdir_escaped); - g_free(path_escaped); - g_free(destdir_escaped); -#else - if(!winpidgin_gz_untar(path, destdir)) { - g_free(destdir); - return; - } -#endif - } - else { - g_free(destdir); - return; - } - -#ifndef _WIN32 - /* Fire! */ - if (system(command)) - { - purple_notify_error(NULL, NULL, _("Smiley theme failed to unpack."), NULL); - } - - g_free(command); -#endif - g_free(destdir); - - theme_rowref = theme_refresh_theme_list(); - if (theme_rowref != NULL) { - GtkTreePath *tp = gtk_tree_row_reference_get_path(theme_rowref); - - if (tp) - gtk_tree_selection_select_path(smiley_theme_sel, tp); - gtk_tree_row_reference_free(theme_rowref); - } -} - -static void -theme_got_url(PurpleUtilFetchUrlData *url_data, gpointer user_data, - const gchar *themedata, size_t len, const gchar *error_message) -{ - FILE *f; - gchar *path; - size_t wc; - - if ((error_message != NULL) || (len == 0)) - return; - - f = purple_mkstemp(&path, TRUE); - wc = fwrite(themedata, len, 1, f); - if (wc != 1) { - purple_debug_warning("theme_got_url", "Unable to write theme data.\n"); - fclose(f); - g_unlink(path); - g_free(path); - return; - } - fclose(f); - - theme_install_theme(path, user_data); - - g_unlink(path); - g_free(path); -} - -static void -theme_dnd_recv(GtkWidget *widget, GdkDragContext *dc, guint x, guint y, - GtkSelectionData *sd, guint info, guint t, gpointer data) -{ - gchar *name = (gchar *)sd->data; - - if ((sd->length >= 0) && (sd->format == 8)) { - /* Well, it looks like the drag event was cool. - * Let's do something with it */ - - if (!g_ascii_strncasecmp(name, "file://", 7)) { - GError *converr = NULL; - gchar *tmp; - /* It looks like we're dealing with a local file. Let's - * just untar it in the right place */ - if(!(tmp = g_filename_from_uri(name, NULL, &converr))) { - purple_debug(PURPLE_DEBUG_ERROR, "theme dnd", "%s\n", - (converr ? converr->message : - "g_filename_from_uri error")); - return; - } - theme_install_theme(tmp, NULL); - g_free(tmp); - } else if (!g_ascii_strncasecmp(name, "http://", 7)) { - /* Oo, a web drag and drop. This is where things - * will start to get interesting */ - purple_util_fetch_url(name, TRUE, NULL, FALSE, theme_got_url, ".tgz"); - } else if (!g_ascii_strncasecmp(name, "https://", 8)) { - /* purple_util_fetch_url() doesn't support HTTPS, but we want users - * to be able to drag and drop links from the SF trackers, so - * we'll try it as an HTTP URL. */ - char *tmp = g_strdup(name + 1); - tmp[0] = 'h'; - tmp[1] = 't'; - tmp[2] = 't'; - tmp[3] = 'p'; - purple_util_fetch_url(tmp, TRUE, NULL, FALSE, theme_got_url, ".tgz"); - g_free(tmp); - } - - gtk_drag_finish(dc, TRUE, FALSE, t); - } - - gtk_drag_finish(dc, FALSE, FALSE, t); -} - /* Rebuild the markup for the sound theme selection for "(Custom)" themes */ static void pref_sound_generate_markup() @@ -596,7 +469,7 @@ print_custom = customized && g_str_equal(current_theme, name); - if (g_str_equal(name, "")) + if (!name || *name == '\0') markup = g_strdup_printf("<b>(Default)</b>%s%s - None\n<span foreground='dim grey'>The default Pidgin sound theme</span>", print_custom ? " " : "", print_custom ? "(Custom)" : ""); else { @@ -617,7 +490,7 @@ } } -/* adds the themes to the theme list from the manager so they can be sisplayed in prefs */ +/* adds the themes to the theme list from the manager so they can be displayed in prefs */ static void prefs_themes_sort(PurpleTheme *theme) { @@ -667,53 +540,380 @@ if (pixbuf != NULL) g_object_unref(G_OBJECT(pixbuf)); } - } -/* init all the theme variables so that the themes can be sorted later and used by pref pages */ static void -prefs_themes_init() +prefs_set_active_theme_combo(GtkWidget *combo_box, GtkListStore *store, const gchar *current_theme) +{ + GtkTreeIter iter; + gchar *theme = NULL; + gboolean unset = TRUE; + + if (current_theme && *current_theme && gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter)) { + do { + gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, 2, &theme, -1); + + if (g_str_equal(current_theme, theme)) { + gtk_combo_box_set_active_iter(GTK_COMBO_BOX(combo_box), &iter); + unset = FALSE; + } + + g_free(theme); + } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter)); + } + + if (unset) + gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box), 0); +} + +static void +prefs_themes_refresh() { GdkPixbuf *pixbuf = NULL; gchar *filename; GtkTreeIter iter; + /* refresh the list of themes in the manager */ + purple_theme_manager_refresh(); + filename = g_build_filename(DATADIR, "icons", "hicolor", "32x32", "apps", "pidgin.png", NULL); pixbuf = gdk_pixbuf_new_from_file_at_scale(filename, PREFS_OPTIMAL_ICON_SIZE, PREFS_OPTIMAL_ICON_SIZE, TRUE, NULL); g_free(filename); /* sound themes */ - prefs_sound_themes = gtk_list_store_new(3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING); - + gtk_list_store_clear(prefs_sound_themes); gtk_list_store_append(prefs_sound_themes, &iter); gtk_list_store_set(prefs_sound_themes, &iter, 0, pixbuf, 2, "", -1); /* blist themes */ - prefs_blist_themes = gtk_list_store_new(3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING); - + gtk_list_store_clear(prefs_blist_themes); gtk_list_store_append(prefs_blist_themes, &iter); - gtk_list_store_set(prefs_blist_themes, &iter, 0, pixbuf, 1, "<b>(Default)</b> - None\n<span color='dim grey'>" - "The default Pidgin buddy list theme</span>", 2, "", -1); + gtk_list_store_set(prefs_blist_themes, &iter, 0, pixbuf, 1, + "<b>(Default)</b> - None\n<span color='dim grey'>" + "The default Pidgin buddy list theme</span>", 2, "", -1); /* status icon themes */ - prefs_status_icon_themes = gtk_list_store_new(3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING); - + gtk_list_store_clear(prefs_status_icon_themes); gtk_list_store_append(prefs_status_icon_themes, &iter); - gtk_list_store_set(prefs_status_icon_themes, &iter, 0, pixbuf, 1, "<b>(Default)</b> - None\n<span color='dim grey'>" - "The default Pidgin status icon theme</span>", 2, "", -1); - + gtk_list_store_set(prefs_status_icon_themes, &iter, 0, pixbuf, 1, + "<b>(Default)</b> - None\n<span color='dim grey'>" + "The default Pidgin status icon theme</span>", 2, "", -1); g_object_unref(G_OBJECT(pixbuf)); + + purple_theme_manager_for_each_theme(prefs_themes_sort); + pref_sound_generate_markup(); + + /* set active */ + prefs_set_active_theme_combo(prefs_sound_themes_combo_box, prefs_sound_themes, purple_prefs_get_string(PIDGIN_PREFS_ROOT "/sound/theme")); + prefs_set_active_theme_combo(prefs_blist_themes_combo_box, prefs_blist_themes, purple_prefs_get_string(PIDGIN_PREFS_ROOT "/blist/theme")); + prefs_set_active_theme_combo(prefs_status_themes_combo_box, prefs_status_icon_themes, purple_prefs_get_string(PIDGIN_PREFS_ROOT "/status/icon-theme")); +} + +/* init all the theme variables so that the themes can be sorted later and used by pref pages */ +static void +prefs_themes_init() +{ + prefs_sound_themes = gtk_list_store_new(3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING); + + prefs_blist_themes = gtk_list_store_new(3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING); + + prefs_status_icon_themes = gtk_list_store_new(3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING); +} + +static PurpleTheme * +prefs_theme_find_theme(const gchar *path, const gchar *type) +{ + PurpleTheme *theme = purple_theme_manager_load_theme(path, type); + GDir *dir = g_dir_open(path, 0, NULL); + const gchar *next; + + while (!PURPLE_IS_THEME(theme) && (next = g_dir_read_name(dir))) { + gchar *next_path = g_build_filename(path, next, NULL); + + if (g_file_test(next_path, G_FILE_TEST_IS_DIR)) + theme = prefs_theme_find_theme(next_path, type); + + g_free(next_path); + } + + g_dir_close(dir); + + return theme; +} + +/* installs a theme, info is freed by function */ +static void +theme_install_theme(char *path, struct theme_info *info) { +#ifndef _WIN32 + gchar *command; +#endif + gchar *destdir, *tail, *type, *original_name; + GtkTreeRowReference *theme_rowref; + gboolean is_smiley_theme, is_archive; + PurpleTheme *theme = NULL; + + if (info == NULL) + return; + + original_name = info->original_name; + type = info->type; + + /* check the extension */ + tail = info->extension ? info->extension : g_strdup(strrchr(path, '.')); + + if (!tail) { + g_free(type); + g_free(original_name); + g_free(info); + return; + } else g_free(info); + + is_archive = !g_ascii_strcasecmp(tail, ".gz") || !g_ascii_strcasecmp(tail, ".tgz"); + + g_free(tail); + + /* Just to be safe */ + g_strchomp(path); + + if ((is_smiley_theme = g_str_equal(type, "smiley"))) + destdir = g_build_filename(purple_user_dir(), "smileys", NULL); + else destdir = g_build_filename(purple_user_dir(), "themes", "temp", NULL); + + /* We'll check this just to make sure. This also lets us do something different on + * other platforms, if need be */ + if (is_archive) { +#ifndef _WIN32 + gchar *path_escaped = g_shell_quote(path); + gchar *destdir_escaped = g_shell_quote(destdir); + + if (!g_file_test(destdir, G_FILE_TEST_IS_DIR)) + g_mkdir_with_parents(destdir, 0700); + + command = g_strdup_printf("tar > /dev/null xzf %s -C %s", path_escaped, destdir_escaped); + g_free(path_escaped); + g_free(destdir_escaped); + + /* Fire! */ + if (system(command)) { + purple_notify_error(NULL, NULL, _("Theme failed to unpack."), NULL); + g_free(command); + g_free(destdir); + g_free(type); + g_free(original_name); + return; + } +#else + if(!winpidgin_gz_untar(path, destdir)) { + g_free(destdir); + g_free(type); + g_free(original_name); + return; + } +#endif + } + + if (is_smiley_theme) { + /* just extract the folder to the smiley directory */ + theme_rowref = theme_refresh_theme_list(); + + if (theme_rowref != NULL) { + GtkTreePath *tp = gtk_tree_row_reference_get_path(theme_rowref); + + if (tp) + gtk_tree_selection_select_path(smiley_theme_sel, tp); + + gtk_tree_row_reference_free(theme_rowref); + } + + } else if (is_archive) { + theme = prefs_theme_find_theme(destdir, type); + + if (PURPLE_IS_THEME(theme)) { + /* create the location for the theme */ + gchar *theme_dest = g_build_filename(purple_user_dir(), "themes", + purple_theme_get_name(theme), + "purple", type, NULL); + + if (!g_file_test(theme_dest, G_FILE_TEST_IS_DIR)) + g_mkdir_with_parents(theme_dest, 0700); + + g_free(theme_dest); + theme_dest = g_build_filename(purple_user_dir(), "themes", + purple_theme_get_name(theme), + "purple", type, NULL); + + /* move the entire directory to new location */ + g_rename(purple_theme_get_dir(theme), theme_dest); + + g_free(theme_dest); + g_remove(destdir); + g_object_unref(theme); + + prefs_themes_refresh(); + + } else { + /* something was wrong with the theme archive */ + g_unlink(destdir); + purple_notify_error(NULL, NULL, _("Theme failed to load."), NULL); + } + + } else { /* just a single file so copy it to a new temp directory and attempt to load it*/ + GFile *source, *destination; + gchar *temp_path, *temp_file; + + source = g_file_new_for_path(path); + + temp_path = g_build_filename(purple_user_dir(), "themes", "temp", "sub_folder", NULL); + + if (original_name != NULL) { + /* name was changed from the original (probably a dnd) change it back before loading */ + temp_file = g_build_filename(temp_path, original_name, NULL); + + } else { + /* find the file name and name the new file the same thing */ + GFileInfo* file_info = g_file_query_info (source, + G_FILE_ATTRIBUTE_STANDARD_NAME, + G_FILE_QUERY_INFO_NONE, + NULL, + NULL); + + const gchar *source_name = g_file_info_get_content_type(file_info); + + temp_file = g_build_filename(temp_path, source_name, NULL); + + g_object_unref(file_info); + } + + destination = g_file_new_for_path(temp_file); + + if (!g_file_test(temp_path, G_FILE_TEST_IS_DIR)) + g_mkdir_with_parents(temp_path, 0700); + + g_file_copy(source, destination, G_FILE_COPY_OVERWRITE, NULL, NULL, NULL, NULL); + + g_object_unref(source); + g_object_unref(destination); + + /* find the theme, could be in subfolder */ + theme = prefs_theme_find_theme(temp_path, type); + + if (PURPLE_IS_THEME(theme)) { + gchar *theme_dest = g_build_filename(purple_user_dir(), "themes", + purple_theme_get_name(theme), + "purple", type, NULL); + + if(!g_file_test(theme_dest, G_FILE_TEST_IS_DIR)) + g_mkdir_with_parents(theme_dest, 0700); + + g_rename(purple_theme_get_dir(theme), theme_dest); + + g_free(theme_dest); + g_object_unref(theme); + + prefs_themes_refresh(); + + } else { + g_remove(temp_path); + purple_notify_error(NULL, NULL, _("Theme failed to load."), NULL); + } + + g_free(temp_file); + g_free(temp_path); + } + + g_free(type); + g_free(original_name); + g_free(destdir); +} + +static void +theme_got_url(PurpleUtilFetchUrlData *url_data, gpointer user_data, + const gchar *themedata, size_t len, const gchar *error_message) +{ + FILE *f; + gchar *path; + size_t wc; + + if ((error_message != NULL) || (len == 0)) + return; + + f = purple_mkstemp(&path, TRUE); + wc = fwrite(themedata, len, 1, f); + if (wc != 1) { + purple_debug_warning("theme_got_url", "Unable to write theme data.\n"); + fclose(f); + g_unlink(path); + g_free(path); + return; + } + fclose(f); + + theme_install_theme(path, user_data); + + g_unlink(path); + g_free(path); +} + +static void +theme_dnd_recv(GtkWidget *widget, GdkDragContext *dc, guint x, guint y, + GtkSelectionData *sd, guint info, guint t, gpointer user_data) +{ + gchar *name = g_strchomp((gchar *)sd->data); + + if ((sd->length >= 0) && (sd->format == 8)) { + /* Well, it looks like the drag event was cool. + * Let's do something with it */ + gchar *temp; + struct theme_info *info = g_new0(struct theme_info, 1); + info->type = g_strdup((gchar *)user_data); + info->extension = g_strdup(g_strrstr(name,".")); + temp = g_strrstr(name, "/"); + info->original_name = temp ? g_strdup(++temp) : NULL; + + if (!g_ascii_strncasecmp(name, "file://", 7)) { + GError *converr = NULL; + gchar *tmp; + /* It looks like we're dealing with a local file. Let's + * just untar it in the right place */ + if(!(tmp = g_filename_from_uri(name, NULL, &converr))) { + purple_debug(PURPLE_DEBUG_ERROR, "theme dnd", "%s\n", + (converr ? converr->message : + "g_filename_from_uri error")); + return; + } + theme_install_theme(tmp, info); + g_free(tmp); + } else if (!g_ascii_strncasecmp(name, "http://", 7)) { + /* Oo, a web drag and drop. This is where things + * will start to get interesting */ + purple_util_fetch_url(name, TRUE, NULL, FALSE, theme_got_url, info); + } else if (!g_ascii_strncasecmp(name, "https://", 8)) { + /* purple_util_fetch_url() doesn't support HTTPS, but we want users + * to be able to drag and drop links from the SF trackers, so + * we'll try it as an HTTP URL. */ + char *tmp = g_strdup(name + 1); + tmp[0] = 'h'; + tmp[1] = 't'; + tmp[2] = 't'; + tmp[3] = 'p'; + + purple_util_fetch_url(tmp, TRUE, NULL, FALSE, theme_got_url, info); + g_free(tmp); + } + + gtk_drag_finish(dc, TRUE, FALSE, t); + } + + gtk_drag_finish(dc, FALSE, FALSE, t); } /* builds a theme combo box from a list store with colums: icon preview, markup, theme name */ static GtkWidget * -prefs_build_theme_combo_box(GtkListStore *store, const gchar *current_theme) +prefs_build_theme_combo_box(GtkListStore *store, const gchar *current_theme, gchar *type) { - GtkWidget *combo_box; GtkCellRenderer *cell_rend; - GtkTreeIter iter; - gchar *theme = NULL; - gboolean unset = TRUE; + GtkWidget *combo_box; + GtkTargetEntry te[3] = {{"text/plain", 0, 0},{"text/uri-list", 0, 1},{"STRING", 0, 2}}; g_return_val_if_fail(store != NULL && current_theme != NULL, NULL); @@ -731,21 +931,10 @@ g_object_set(cell_rend, "ellipsize", PANGO_ELLIPSIZE_END, NULL); #endif*/ - if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter)) { - do { - gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, 2, &theme, -1); - - if (g_str_equal(current_theme, theme)) { - gtk_combo_box_set_active_iter(GTK_COMBO_BOX(combo_box), &iter); - unset = FALSE; - } - - g_free(theme); - } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter)); - } - - if (unset) - gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box), 0); + gtk_drag_dest_set(combo_box, GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT | GTK_DEST_DEFAULT_DROP, te, + sizeof(te) / sizeof(GtkTargetEntry) , GDK_ACTION_COPY | GDK_ACTION_MOVE); + + g_signal_connect(G_OBJECT(combo_box), "drag_data_received", G_CALLBACK(theme_dnd_recv), type); return combo_box; } @@ -757,32 +946,32 @@ gint i; gchar *pref; gchar *new_theme; - gboolean success; GtkTreeIter new_iter; - success = gtk_combo_box_get_active_iter(combo_box, &new_iter); - g_return_if_fail(success); - - gtk_tree_model_get(GTK_TREE_MODEL(prefs_sound_themes), &new_iter, 2, &new_theme, -1); - - purple_prefs_set_string(PIDGIN_PREFS_ROOT "/sound/theme", new_theme); - - /* New theme removes all customization */ - for(i=0; i < PURPLE_NUM_SOUNDS; i++){ - pref = g_strdup_printf(PIDGIN_PREFS_ROOT "/sound/file/%s", - pidgin_sound_get_event_option(i)); - purple_prefs_set_path(pref, ""); - g_free(pref); + if(gtk_combo_box_get_active_iter(combo_box, &new_iter)) { + + gtk_tree_model_get(GTK_TREE_MODEL(prefs_sound_themes), &new_iter, 2, &new_theme, -1); + + purple_prefs_set_string(PIDGIN_PREFS_ROOT "/sound/theme", new_theme); + + /* New theme removes all customization */ + for(i=0; i < PURPLE_NUM_SOUNDS; i++){ + pref = g_strdup_printf(PIDGIN_PREFS_ROOT "/sound/file/%s", + pidgin_sound_get_event_option(i)); + purple_prefs_set_path(pref, ""); + g_free(pref); + } + + /* gets rid of the "(Custom)" from the last selection */ + pref_sound_generate_markup(); + + gtk_entry_set_text(GTK_ENTRY(sound_entry), _("(default)")); + + g_free(new_theme); } - - /* gets rid of the "(Custom)" from the last selection */ - pref_sound_generate_markup(); - - gtk_entry_set_text(GTK_ENTRY(sound_entry), _("(default)")); - - g_free(new_theme); } + /* Does same as normal sort, except "none" is sorted first */ static gint pidgin_sort_smileys (GtkTreeModel *model, GtkTreeIter *a, @@ -821,11 +1010,18 @@ static void request_theme_file_name_cb(gpointer data, char *theme_file_name) { - theme_install_theme(theme_file_name, NULL) ; + struct theme_info *info = g_new0(struct theme_info, 1); + info->type = g_strdup("smiley"); + info->extension = NULL; + info->original_name = NULL; + + theme_install_theme(theme_file_name, info) ; + + g_free(info); } static void -add_theme_button_clicked_cb(GtkWidget *widget, gpointer null) +add_theme_button_clicked_cb(GtkWidget *widget, gpointer user_data) { purple_request_file(NULL, _("Install Theme"), NULL, FALSE, (GCallback)request_theme_file_name_cb, NULL, NULL, NULL, NULL, NULL) ; } @@ -903,7 +1099,7 @@ gtk_drag_dest_set(view, GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT | GTK_DEST_DEFAULT_DROP, te, sizeof(te) / sizeof(GtkTargetEntry) , GDK_ACTION_COPY | GDK_ACTION_MOVE); - g_signal_connect(G_OBJECT(view), "drag_data_received", G_CALLBACK(theme_dnd_recv), smiley_theme_store); + g_signal_connect(G_OBJECT(view), "drag_data_received", G_CALLBACK(theme_dnd_recv), "smiley"); rend = gtk_cell_renderer_pixbuf_new(); smiley_theme_sel = sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (view)); @@ -1163,35 +1359,42 @@ static void prefs_set_blist_theme_cb(GtkComboBox *combo_box, gpointer user_data) { - PidginBlistTheme *theme = NULL; + PidginBlistTheme *theme = NULL; GtkTreeIter iter; gchar *name = NULL; - g_return_if_fail(gtk_combo_box_get_active_iter(combo_box, &iter)); - gtk_tree_model_get(GTK_TREE_MODEL(prefs_blist_themes), &iter, 2, &name, -1); - - if (name && *name) - theme = PIDGIN_BLIST_THEME(purple_theme_manager_find_theme(name, "blist")); - g_free(name); - - pidgin_blist_set_theme(theme); + if(gtk_combo_box_get_active_iter(combo_box, &iter)) { + + gtk_tree_model_get(GTK_TREE_MODEL(prefs_blist_themes), &iter, 2, &name, -1); + + if(!name || !g_str_equal(name, "")) + theme = PIDGIN_BLIST_THEME(purple_theme_manager_find_theme(name, "blist")); + + g_free(name); + + pidgin_blist_set_theme(theme); + } } /* sets the current icon theme */ static void prefs_set_status_icon_theme_cb(GtkComboBox *combo_box, gpointer user_data) { - PidginStatusIconTheme *theme; + PidginStatusIconTheme *theme = NULL; GtkTreeIter iter; gchar *name = NULL; - g_return_if_fail(gtk_combo_box_get_active_iter(combo_box, &iter)); - gtk_tree_model_get(GTK_TREE_MODEL(prefs_status_icon_themes), &iter, 2, &name, -1); - - theme = PIDGIN_STATUS_ICON_THEME(purple_theme_manager_find_theme(name, "status-icon")); - g_free(name); - - pidgin_stock_load_status_icon_theme(theme); + if(gtk_combo_box_get_active_iter(combo_box, &iter)) { + + gtk_tree_model_get(GTK_TREE_MODEL(prefs_status_icon_themes), &iter, 2, &name, -1); + + if(!name || !g_str_equal(name, "")) + theme = PIDGIN_STATUS_ICON_THEME(purple_theme_manager_find_theme(name, "status-icon")); + + g_free(name); + + pidgin_stock_load_status_icon_theme(theme); + } } static GtkWidget * @@ -1201,7 +1404,6 @@ GtkWidget *vbox; GtkWidget *vbox2; GtkWidget *label; - GtkWidget *combo_box; GtkSizeGroup *sg; GList *names = NULL; @@ -1213,14 +1415,20 @@ /* Buddy List Themes */ vbox = pidgin_make_frame(ret, _("Buddy List Theme")); - combo_box = prefs_build_theme_combo_box(prefs_blist_themes, purple_prefs_get_string(PIDGIN_PREFS_ROOT "/blist/theme")); - gtk_box_pack_start(GTK_BOX (vbox), combo_box, FALSE, FALSE, 0); - g_signal_connect(G_OBJECT(combo_box), "changed", (GCallback)prefs_set_blist_theme_cb, NULL); + prefs_blist_themes_combo_box = prefs_build_theme_combo_box(prefs_blist_themes, + purple_prefs_get_string(PIDGIN_PREFS_ROOT "/blist/theme"), + "blist"); + + gtk_box_pack_start(GTK_BOX (vbox), prefs_blist_themes_combo_box, FALSE, FALSE, 0); + g_signal_connect(G_OBJECT(prefs_blist_themes_combo_box), "changed", (GCallback)prefs_set_blist_theme_cb, NULL); /* Status Icon Themes */ - combo_box = prefs_build_theme_combo_box(prefs_status_icon_themes, purple_prefs_get_string(PIDGIN_PREFS_ROOT "/status/icon-theme")); - gtk_box_pack_start(GTK_BOX (vbox), combo_box, FALSE, FALSE, 0); - g_signal_connect(G_OBJECT(combo_box), "changed", (GCallback)prefs_set_status_icon_theme_cb, NULL); + prefs_status_themes_combo_box = prefs_build_theme_combo_box(prefs_status_icon_themes, + purple_prefs_get_string(PIDGIN_PREFS_ROOT "/status/icon-theme"), + "icon"); + + gtk_box_pack_start(GTK_BOX (vbox), prefs_status_themes_combo_box, FALSE, FALSE, 0); + g_signal_connect(G_OBJECT(prefs_status_themes_combo_box), "changed", (GCallback)prefs_set_status_icon_theme_cb, NULL); /* System Tray */ vbox = pidgin_make_frame(ret, _("System Tray Icon")); @@ -2202,7 +2410,7 @@ sound_page(void) { GtkWidget *ret; - GtkWidget *vbox, *sw, *button, *combo_box; + GtkWidget *vbox, *sw, *button; GtkSizeGroup *sg; GtkTreeIter iter; GtkWidget *event_view; @@ -2308,11 +2516,14 @@ vbox->parent->parent, TRUE, TRUE, 0, GTK_PACK_START); /* SOUND THEMES */ - combo_box = prefs_build_theme_combo_box(prefs_sound_themes, purple_prefs_get_string(PIDGIN_PREFS_ROOT "/sound/theme")); - pref_sound_generate_markup(); - gtk_box_pack_start(GTK_BOX (vbox), combo_box, FALSE, FALSE, 0); - - g_signal_connect(G_OBJECT(combo_box), "changed", (GCallback)prefs_set_sound_theme_cb, NULL); + prefs_sound_themes_combo_box = prefs_build_theme_combo_box(prefs_sound_themes, + purple_prefs_get_string(PIDGIN_PREFS_ROOT "/sound/theme"), + "sound"); + + + gtk_box_pack_start(GTK_BOX (vbox), prefs_sound_themes_combo_box, FALSE, FALSE, 0); + + g_signal_connect(G_OBJECT(prefs_sound_themes_combo_box), "changed", (GCallback)prefs_set_sound_theme_cb, NULL); /* SOUND SELECTION */ sw = gtk_scrolled_window_new(NULL,NULL); @@ -2545,14 +2756,6 @@ return; } - /* Refresh the list of themes before showing the preferences window */ - purple_theme_manager_refresh(); - - /* add everything in the theme manager before the window is loaded */ - if (prefs_themes_unsorted) { - purple_theme_manager_for_each_theme(prefs_themes_sort); - prefs_themes_unsorted = FALSE; - } /* copy the preferences to tmp values... * I liked "take affect immediately" Oh well :-( */ /* (that should have been "effect," right?) */ @@ -2577,6 +2780,9 @@ prefs_notebook_init(); + /* Refresh the list of themes before showing the preferences window */ + prefs_themes_refresh(); + /* Show everything. */ gtk_widget_show(prefs); }