diff -r b371a53b1695 -r 0f7cb3b272b2 src/gtkutils.c
--- a/src/gtkutils.c Tue Aug 15 20:23:58 2006 +0000
+++ b/src/gtkutils.c Tue Aug 15 23:25:29 2006 +0000
@@ -2211,3 +2211,429 @@
gdk_window_set_cursor(widget->window, NULL);
}
+struct _icon_chooser {
+ GtkWidget *icon_filesel;
+ GtkWidget *icon_preview;
+ GtkWidget *icon_text;
+
+ void (*callback)(const char*,gpointer);
+ gpointer data;
+};
+
+#if !GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
+static void
+icon_filesel_delete_cb(GtkWidget *w, struct _icon_chooser *dialog)
+{
+ if (dialog->icon_filesel != NULL)
+ gtk_widget_destroy(dialog->icon_filesel);
+
+ if (dialog->callback)
+ dialog->callback(NULL, data);
+
+ g_free(dialog);
+}
+#endif /* FILECHOOSER */
+
+
+
+#if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
+static void
+icon_filesel_choose_cb(GtkWidget *widget, gint response, struct _icon_chooser *dialog)
+{
+ char *filename, *current_folder;
+
+ if (response != GTK_RESPONSE_ACCEPT) {
+ if (response == GTK_RESPONSE_CANCEL) {
+ gtk_widget_destroy(dialog->icon_filesel);
+ }
+ dialog->icon_filesel = NULL;
+ if (dialog->callback)
+ dialog->callback(NULL, dialog->data);
+ g_free(dialog);
+ return;
+ }
+
+ filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog->icon_filesel));
+ current_folder = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(dialog->icon_filesel));
+ if (current_folder != NULL) {
+ gaim_prefs_set_string("/gaim/gtk/filelocations/last_icon_folder", current_folder);
+ g_free(current_folder);
+ }
+
+#else /* FILECHOOSER */
+static void
+icon_filesel_choose_cb(GtkWidget *w, AccountPrefsDialog *dialog)
+{
+ char *filename, *current_folder;
+
+ filename = g_strdup(gtk_file_selection_get_filename(
+ GTK_FILE_SELECTION(dialog->icon_filesel)));
+
+ /* If they typed in a directory, change there */
+ if (gaim_gtk_check_if_dir(filename,
+ GTK_FILE_SELECTION(dialog->icon_filesel)))
+ {
+ g_free(filename);
+ return;
+ }
+
+ current_folder = g_path_get_dirname(filename);
+ if (current_folder != NULL) {
+ gaim_prefs_set_string("/gaim/gtk/filelocations/last_icon_folder", current_folder);
+ g_free(current_folder);
+ }
+
+#endif /* FILECHOOSER */
+ if (dialog->callback)
+ dialog->callback(filename, dialog->data);
+ gtk_widget_destroy(dialog->icon_filesel);
+ g_free(filename);
+ g_free(dialog);
+ }
+
+
+static void
+#if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
+icon_preview_change_cb(GtkFileChooser *widget, struct _icon_chooser *dialog)
+#else /* FILECHOOSER */
+icon_preview_change_cb(GtkTreeSelection *sel, struct _icon_chooser *dialog)
+#endif /* FILECHOOSER */
+{
+ GdkPixbuf *pixbuf, *scale;
+ int height, width;
+ char *basename, *markup, *size;
+ struct stat st;
+ char *filename;
+
+#if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
+ filename = gtk_file_chooser_get_preview_filename(
+ GTK_FILE_CHOOSER(dialog->icon_filesel));
+#else /* FILECHOOSER */
+ filename = g_strdup(gtk_file_selection_get_filename(
+ GTK_FILE_SELECTION(dialog->icon_filesel)));
+#endif /* FILECHOOSER */
+
+ if (!filename || g_stat(filename, &st))
+ {
+ g_free(filename);
+ return;
+ }
+
+ pixbuf = gdk_pixbuf_new_from_file(filename, NULL);
+ if (!pixbuf) {
+ gtk_image_set_from_pixbuf(GTK_IMAGE(dialog->icon_preview), NULL);
+ gtk_label_set_markup(GTK_LABEL(dialog->icon_text), "");
+#if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
+ gtk_file_chooser_set_preview_widget_active(
+ GTK_FILE_CHOOSER(dialog->icon_filesel), FALSE);
+#endif /* FILECHOOSER */
+ g_free(filename);
+ return;
+ }
+
+ width = gdk_pixbuf_get_width(pixbuf);
+ height = gdk_pixbuf_get_height(pixbuf);
+ basename = g_path_get_basename(filename);
+ size = gaim_str_size_to_units(st.st_size);
+ markup = g_strdup_printf(_("File: %s\n"
+ "File size: %s\n"
+ "Image size: %dx%d"),
+ basename, size, width, height);
+
+ scale = gdk_pixbuf_scale_simple(pixbuf, width * 50 / height,
+ 50, GDK_INTERP_BILINEAR);
+ gtk_image_set_from_pixbuf(GTK_IMAGE(dialog->icon_preview), scale);
+#if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
+ gtk_file_chooser_set_preview_widget_active(
+ GTK_FILE_CHOOSER(dialog->icon_filesel), TRUE);
+#endif /* FILECHOOSER */
+ gtk_label_set_markup(GTK_LABEL(dialog->icon_text), markup);
+
+ g_object_unref(G_OBJECT(pixbuf));
+ g_object_unref(G_OBJECT(scale));
+ g_free(filename);
+ g_free(basename);
+ g_free(size);
+ g_free(markup);
+}
+
+
+GtkWidget *gaim_gtk_buddy_icon_chooser_new(GtkWindow *parent, void(*callback)(const char*,gpointer), gpointer data) {
+ struct _icon_chooser *dialog = g_new0(struct _icon_chooser, 1);
+
+#if !GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
+ GtkWidget *hbox;
+ GtkWidget *tv;
+ GtkTreeSelection *sel;
+
+#endif /* FILECHOOSER */
+ const char *current_folder;
+
+ dialog->callback = callback;
+ dialog->data = data;
+
+ if (dialog->icon_filesel != NULL) {
+ gtk_window_present(GTK_WINDOW(dialog->icon_filesel));
+ return NULL;
+ }
+
+ current_folder = gaim_prefs_get_string("/gaim/gtk/filelocations/last_icon_folder");
+#if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */
+
+ dialog->icon_filesel = gtk_file_chooser_dialog_new(_("Buddy Icon"),
+ parent,
+ GTK_FILE_CHOOSER_ACTION_OPEN,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
+ NULL);
+ gtk_dialog_set_default_response(GTK_DIALOG(dialog->icon_filesel), GTK_RESPONSE_ACCEPT);
+ if ((current_folder != NULL) && (*current_folder != '\0'))
+ gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog->icon_filesel),
+ current_folder);
+
+ dialog->icon_preview = gtk_image_new();
+ dialog->icon_text = gtk_label_new(NULL);
+ gtk_widget_set_size_request(GTK_WIDGET(dialog->icon_preview), -1, 50);
+ gtk_file_chooser_set_preview_widget(GTK_FILE_CHOOSER(dialog->icon_filesel),
+ GTK_WIDGET(dialog->icon_preview));
+ g_signal_connect(G_OBJECT(dialog->icon_filesel), "update-preview",
+ G_CALLBACK(icon_preview_change_cb), dialog);
+ g_signal_connect(G_OBJECT(dialog->icon_filesel), "response",
+ G_CALLBACK(icon_filesel_choose_cb), dialog);
+ icon_preview_change_cb(NULL, dialog);
+#else /* FILECHOOSER */
+ dialog->icon_filesel = gtk_file_selection_new(_("Buddy Icon"));
+ dialog->icon_preview = gtk_image_new();
+ dialog->icon_text = gtk_label_new(NULL);
+ if ((current_folder != NULL) && (*current_folder != '\0'))
+ gtk_file_selection_set_filename(GTK_FILE_SELECTION(dialog->icon_filesel),
+ current_folder);
+
+ gtk_widget_set_size_request(GTK_WIDGET(dialog->icon_preview), -1, 50);
+ hbox = gtk_hbox_new(FALSE, GAIM_HIG_BOX_SPACE);
+ gtk_box_pack_start(
+ GTK_BOX(GTK_FILE_SELECTION(dialog->icon_filesel)->main_vbox),
+ hbox, FALSE, FALSE, 0);
+ gtk_box_pack_end(GTK_BOX(hbox), dialog->icon_preview,
+ FALSE, FALSE, 0);
+ gtk_box_pack_end(GTK_BOX(hbox), dialog->icon_text, FALSE, FALSE, 0);
+
+ tv = GTK_FILE_SELECTION(dialog->icon_filesel)->file_list;
+ sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tv));
+
+ g_signal_connect(G_OBJECT(sel), "changed",
+ G_CALLBACK(icon_preview_change_cb), dialog);
+ g_signal_connect(
+ G_OBJECT(GTK_FILE_SELECTION(dialog->icon_filesel)->ok_button),
+ "clicked",
+ G_CALLBACK(icon_filesel_choose_cb), dialog);
+ g_signal_connect(
+ G_OBJECT(GTK_FILE_SELECTION(dialog->icon_filesel)->cancel_button),
+ "clicked",
+ G_CALLBACK(icon_filesel_delete_cb), dialog);
+ g_signal_connect(G_OBJECT(dialog->icon_filesel), "destroy",
+ G_CALLBACK(icon_filesel_delete_cb), dialog);
+#endif /* FILECHOOSER */
+ return dialog->icon_filesel;
+}
+
+
+#if GTK_CHECK_VERSION(2,2,0)
+static gboolean
+str_array_match(char **a, char **b)
+{
+ int i, j;
+
+ if (!a || !b)
+ return FALSE;
+ for (i = 0; a[i] != NULL; i++)
+ for (j = 0; b[j] != NULL; j++)
+ if (!g_ascii_strcasecmp(a[i], b[j]))
+ return TRUE;
+ return FALSE;
+}
+#endif
+
+char*
+gaim_gtk_convert_buddy_icon(GaimPlugin *plugin, const char *path)
+{
+#if GTK_CHECK_VERSION(2,2,0)
+ int width, height;
+ char **pixbuf_formats = NULL;
+ GdkPixbufFormat *format;
+ GdkPixbuf *pixbuf;
+ GaimPluginProtocolInfo *prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(plugin);
+ char **prpl_formats = g_strsplit (prpl_info->icon_spec.format,",",0);
+#if !GTK_CHECK_VERSION(2,4,0)
+ GdkPixbufLoader *loader;
+ FILE *file;
+ struct stat st;
+ void *data = NULL;
+#endif
+#endif
+ const char *dirname = gaim_buddy_icons_get_cache_dir();
+ char *random = g_strdup_printf("%x", g_random_int());
+ char *filename = g_build_filename(dirname, random, NULL);
+
+ if (!g_file_test(dirname, G_FILE_TEST_IS_DIR)) {
+ gaim_debug_info("buddyicon", "Creating icon cache directory.\n");
+
+ if (g_mkdir(dirname, S_IRUSR | S_IWUSR | S_IXUSR) < 0) {
+ gaim_debug_error("buddyicon",
+ "Unable to create directory %s: %s\n",
+ dirname, strerror(errno));
+#if GTK_CHECK_VERSION(2,2,0)
+ g_strfreev(prpl_formats);
+#endif
+ g_free(random);
+ g_free(filename);
+ return NULL;
+ }
+ }
+
+#if GTK_CHECK_VERSION(2,2,0)
+#if GTK_CHECK_VERSION(2,4,0)
+ format = gdk_pixbuf_get_file_info (path, &width, &height);
+#else
+ loader = gdk_pixbuf_loader_new();
+ if (!g_stat(path, &st) && (file = g_fopen(path, "rb")) != NULL) {
+ data = g_malloc(st.st_size);
+ fread(data, 1, st.st_size, file);
+ fclose(file);
+ gdk_pixbuf_loader_write(loader, data, st.st_size, NULL);
+ g_free(data);
+ }
+ gdk_pixbuf_loader_close(loader, NULL);
+ pixbuf = gdk_pixbuf_loader_get_pixbuf(loader);
+ width = gdk_pixbuf_get_width(pixbuf);
+ height = gdk_pixbuf_get_height(pixbuf);
+ format = gdk_pixbuf_loader_get_format(loader);
+ g_object_unref(G_OBJECT(loader));
+#endif
+ pixbuf_formats = gdk_pixbuf_format_get_extensions(format);
+
+ if (str_array_match(pixbuf_formats, prpl_formats) && /* This is an acceptable format AND */
+ (!(prpl_info->icon_spec.scale_rules & GAIM_ICON_SCALE_SEND) || /* The prpl doesn't scale before it sends OR */
+ (prpl_info->icon_spec.min_width <= width &&
+ prpl_info->icon_spec.max_width >= width &&
+ prpl_info->icon_spec.min_height <= height &&
+ prpl_info->icon_spec.max_height >= height))) /* The icon is the correct size */
+#endif
+ {
+ gchar *contents;
+ gsize length;
+ FILE *image;
+
+#if GTK_CHECK_VERSION(2,2,0)
+ g_strfreev(prpl_formats);
+ g_strfreev(pixbuf_formats);
+#endif
+
+ /* Copy the image to the cache folder as "filename". */
+
+ if (!g_file_get_contents(path, &contents, &length, NULL) ||
+ (image = g_fopen(filename, "wb")) == NULL)
+ {
+ g_free(random);
+ g_free(filename);
+#if GTK_CHECK_VERSION(2,2,0) && !GTK_CHECK_VERSION(2,4,0)
+ g_object_unref(G_OBJECT(pixbuf));
+#endif
+ return NULL;
+ }
+
+ if (fwrite(contents, 1, length, image) != length)
+ {
+ fclose(image);
+ g_unlink(filename);
+
+ g_free(random);
+ g_free(filename);
+#if GTK_CHECK_VERSION(2,2,0) && !GTK_CHECK_VERSION(2,4,0)
+ g_object_unref(G_OBJECT(pixbuf));
+#endif
+ return NULL;
+ }
+ fclose(image);
+
+#if GTK_CHECK_VERSION(2,2,0) && !GTK_CHECK_VERSION(2,4,0)
+ g_object_unref(G_OBJECT(pixbuf));
+#endif
+
+ g_free(filename);
+ return random;
+ }
+#if GTK_CHECK_VERSION(2,2,0)
+ else
+ {
+ int i;
+ GError *error = NULL;
+ GdkPixbuf *scale;
+ pixbuf = gdk_pixbuf_new_from_file(path, &error);
+ g_strfreev(pixbuf_formats);
+ if (!error && (prpl_info->icon_spec.scale_rules & GAIM_ICON_SCALE_SEND) &&
+ (width < prpl_info->icon_spec.min_width ||
+ width > prpl_info->icon_spec.max_width ||
+ height < prpl_info->icon_spec.min_height ||
+ height > prpl_info->icon_spec.max_height))
+ {
+ int new_width = width;
+ int new_height = height;
+
+ if(new_width > prpl_info->icon_spec.max_width)
+ new_width = prpl_info->icon_spec.max_width;
+ else if(new_width < prpl_info->icon_spec.min_width)
+ new_width = prpl_info->icon_spec.min_width;
+ if(new_height > prpl_info->icon_spec.max_height)
+ new_height = prpl_info->icon_spec.max_height;
+ else if(new_height < prpl_info->icon_spec.min_height)
+ new_height = prpl_info->icon_spec.min_height;
+
+ /* preserve aspect ratio */
+ if ((double)height * (double)new_width >
+ (double)width * (double)new_height) {
+ new_width = 0.5 + (double)width * (double)new_height / (double)height;
+ } else {
+ new_height = 0.5 + (double)height * (double)new_width / (double)width;
+ }
+
+ scale = gdk_pixbuf_scale_simple (pixbuf, new_width, new_height,
+ GDK_INTERP_HYPER);
+ g_object_unref(G_OBJECT(pixbuf));
+ pixbuf = scale;
+ }
+ if (error) {
+ g_free(random);
+ g_free(filename);
+ gaim_debug_error("buddyicon", "Could not open icon for conversion: %s\n", error->message);
+ g_error_free(error);
+ g_strfreev(prpl_formats);
+ return NULL;
+ }
+
+ for (i = 0; prpl_formats[i]; i++) {
+ gaim_debug_info("buddyicon", "Converting buddy icon to %s as %s\n", prpl_formats[i], filename);
+ /* The gdk-pixbuf documentation is wrong. gdk_pixbuf_save returns TRUE if it was successful,
+ * FALSE if an error was set. */
+ if (gdk_pixbuf_save (pixbuf, filename, prpl_formats[i], &error, NULL) == TRUE)
+ break;
+ gaim_debug_warning("buddyicon", "Could not convert to %s: %s\n", prpl_formats[i], error->message);
+ g_error_free(error);
+ error = NULL;
+ }
+ g_strfreev(prpl_formats);
+ if (!error) {
+ g_object_unref(G_OBJECT(pixbuf));
+ g_free(filename);
+ return random;
+ } else {
+ gaim_debug_error("buddyicon", "Could not convert icon to usable format: %s\n", error->message);
+ g_error_free(error);
+ }
+ g_free(random);
+ g_free(filename);
+ g_object_unref(G_OBJECT(pixbuf));
+ }
+ return NULL;
+#endif
+}