Mercurial > pidgin.yaz
changeset 14133:31d33e7bc0e6
[gaim-migrate @ 16775]
A global buddy icon selector in the statusbox.
This is done totally in the GTK+ UI; the core still sees a buddy icon as
belonging to an account.
Per-account icons can override the global one in Modify Account.
There are some caching issues to work out, still.
committer: Tailor Script <tailor@pidgin.im>
author | Sean Egan <seanegan@gmail.com> |
---|---|
date | Tue, 15 Aug 2006 23:25:29 +0000 |
parents | 2c85b0f97dd0 |
children | 4006d3dc2871 |
files | src/gtkaccount.c src/gtkblist.c src/gtkstatusbox.c src/gtkstatusbox.h src/gtkutils.c src/gtkutils.h |
diffstat | 6 files changed, 685 insertions(+), 416 deletions(-) [+] |
line wrap: on
line diff
--- a/src/gtkaccount.c Tue Aug 15 20:23:58 2006 +0000 +++ b/src/gtkaccount.c Tue Aug 15 23:25:29 2006 +0000 @@ -115,6 +115,7 @@ GtkWidget *user_frame; GtkWidget *new_mail_check; GtkWidget *icon_hbox; + GtkWidget *icon_check; GtkWidget *icon_entry; char *icon_path; GtkWidget *icon_filesel; @@ -153,8 +154,6 @@ static void add_account_to_liststore(GaimAccount *account, gpointer user_data); static void set_account(GtkListStore *store, GtkTreeIter *iter, GaimAccount *account); -static char* -convert_buddy_icon(GaimPlugin *plugin, const char *path); /************************************************************************** * Add/Modify Account dialog @@ -271,210 +270,24 @@ } } -#if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */ static void -icon_filesel_choose_cb(GtkWidget *widget, gint response, AccountPrefsDialog *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; - 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 */ - - g_free(dialog->icon_path); - dialog->icon_path = convert_buddy_icon(dialog->plugin, filename); - set_dialog_icon(dialog); - gtk_widget_show(dialog->icon_entry); - - gtk_widget_destroy(dialog->icon_filesel); - dialog->icon_filesel = NULL; - g_free(filename); - } - -static void -#if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */ -icon_preview_change_cb(GtkFileChooser *widget, AccountPrefsDialog *dialog) -#else /* FILECHOOSER */ -icon_preview_change_cb(GtkTreeSelection *sel, AccountPrefsDialog *dialog) -#endif /* FILECHOOSER */ +icon_filesel_choose_cb(const char *filename, AccountPrefsDialog *dialog) { - 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; + if (filename) { + g_free(dialog->icon_path); + dialog->icon_path = gaim_gtk_convert_buddy_icon(dialog->plugin, filename); + set_dialog_icon(dialog); + gtk_widget_show(dialog->icon_entry); } - - 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(_("<b>File:</b> %s\n" - "<b>File size:</b> %s\n" - "<b>Image size:</b> %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); -} - -#if !GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */ -static void -icon_filesel_delete_cb(GtkWidget *w, AccountPrefsDialog *dialog) -{ - if (dialog->icon_filesel != NULL) - gtk_widget_destroy(dialog->icon_filesel); - + dialog->icon_filesel = NULL; } -#endif /* FILECHOOSER */ static void icon_select_cb(GtkWidget *button, AccountPrefsDialog *dialog) { -#if !GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */ - GtkWidget *hbox; - GtkWidget *tv; - GtkTreeSelection *sel; -#endif /* FILECHOOSER */ - const char *current_folder; - - if (dialog->icon_filesel != NULL) { - gtk_window_present(GTK_WINDOW(dialog->icon_filesel)); - return; - } - - 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"), - GTK_WINDOW(dialog->window), - 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 */ - - gtk_widget_show_all(GTK_WIDGET(dialog->icon_filesel)); + dialog->icon_filesel = gaim_gtk_buddy_icon_chooser_new(dialog->window, icon_filesel_choose_cb, dialog); + gtk_widget_show_all(dialog->icon_filesel); } static void @@ -510,7 +323,8 @@ if ((rtmp = strchr(tmp, '\r')) || (rtmp = strchr(tmp, '\n'))) *rtmp = '\0'; g_free(dialog->icon_path); - dialog->icon_path = convert_buddy_icon(dialog->plugin, tmp); + + dialog->icon_path = gaim_gtk_convert_buddy_icon(dialog->plugin, tmp); set_dialog_icon(dialog); gtk_widget_show(dialog->icon_entry); g_free(tmp); @@ -520,207 +334,6 @@ gtk_drag_finish(dc, FALSE, FALSE, t); } - -#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 - -static char* -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 -} - static void update_editable(GaimConnection *gc, AccountPrefsDialog *dialog) { @@ -898,6 +511,12 @@ } static void +icon_check_cb(GtkWidget *checkbox, AccountPrefsDialog *dialog) +{ + gtk_widget_set_sensitive(dialog->icon_hbox, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->icon_check))); +} + +static void add_user_options(AccountPrefsDialog *dialog, GtkWidget *parent) { GtkWidget *frame; @@ -930,12 +549,17 @@ gtk_widget_show(dialog->new_mail_check); /* Buddy icon */ + dialog->icon_check = gtk_check_button_new_with_label(_("Use this buddy icon for this account:")); + g_signal_connect(G_OBJECT(dialog->icon_check), "toggled", G_CALLBACK(icon_check_cb), dialog); + gtk_widget_show(dialog->icon_check); + gtk_box_pack_start(GTK_BOX(vbox), dialog->icon_check, FALSE, FALSE, 0); + dialog->icon_hbox = hbox = gtk_hbox_new(FALSE, GAIM_HIG_BOX_SPACE); + gtk_widget_set_sensitive(hbox, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->icon_check))); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); gtk_widget_show(hbox); - label = gtk_label_new(_("Buddy icon:")); - gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0); + label = gtk_label_new(" "); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); gtk_widget_show(label); @@ -976,12 +600,14 @@ if (dialog->account != NULL) { gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->new_mail_check), - gaim_account_get_check_mail(dialog->account)); - - if (gaim_account_get_buddy_icon(dialog->account) != NULL) { - dialog->icon_path = g_strdup(gaim_account_get_buddy_icon(dialog->account)); - set_dialog_icon(dialog); - } + gaim_account_get_check_mail(dialog->account)); + + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->icon_check), + !gaim_account_get_ui_bool(dialog->account, GAIM_GTK_UI, "use-global-buddyicon", + TRUE)); + + dialog->icon_path = g_strdup(gaim_account_get_ui_string(dialog->account, GAIM_GTK_UI, "non-global-buddyicon", NULL)); + set_dialog_icon(dialog); } if (!dialog->prpl_info || @@ -1425,12 +1051,13 @@ if (dialog->icon_path != NULL) { - const char *icon = gaim_account_get_buddy_icon(dialog->account); + const char *icon = gaim_account_get_ui_string(dialog->account, GAIM_GTK_UI, "non-global-buddyicon", NULL); if (dialog->icon_path != NULL && (icon == NULL || strcmp(dialog->icon_path, icon))) { /* The user set an icon, which would've been cached by convert_buddy_icon, * but didn't save the changes. Delete the cache file. */ char *filename = g_build_filename(gaim_buddy_icons_get_cache_dir(), dialog->icon_path, NULL); + printf("Deleting\n"); g_unlink(filename); g_free(filename); } @@ -1460,7 +1087,7 @@ const char *value; char *username; char *tmp; - gboolean new = FALSE; + gboolean new = FALSE, icon_change = FALSE; GaimAccount *account; if (dialog->account == NULL) @@ -1488,7 +1115,20 @@ gaim_account_set_alias(account, NULL); /* Buddy Icon */ - gaim_account_set_buddy_icon(account, dialog->icon_path); + if (gaim_account_get_ui_bool(account, GAIM_GTK_UI, "use-global-buddyicon", TRUE) == + gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->icon_check))) { + icon_change = TRUE; + } + gaim_account_set_ui_bool(account, GAIM_GTK_UI, "use-global-buddyicon", !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->icon_check))); + gaim_account_set_ui_string(account, GAIM_GTK_UI, "non-global-buddyicon", dialog->icon_path); + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->icon_check))) { + gaim_account_set_buddy_icon(account, dialog->icon_path); + } else if (gaim_prefs_get_string("/gaim/gtk/accounts/buddyicon") && icon_change) { + char *icon = gaim_gtk_convert_buddy_icon(dialog->plugin, gaim_prefs_get_string("/gaim/gtk/accounts/buddyicon")); + gaim_account_set_buddy_icon(account, icon); + g_free(icon); + } + /* Remember Password */ gaim_account_set_remember_password(account, @@ -2672,6 +2312,7 @@ gaim_prefs_add_none("/gaim/gtk/accounts/dialog"); gaim_prefs_add_int("/gaim/gtk/accounts/dialog/width", 520); gaim_prefs_add_int("/gaim/gtk/accounts/dialog/height", 321); + gaim_prefs_add_string("/gaim/gtk/accounts/buddyicon", NULL); gaim_signal_register(gaim_gtk_account_get_handle(), "account-modified", gaim_marshal_VOID__POINTER, NULL, 1,
--- a/src/gtkblist.c Tue Aug 15 20:23:58 2006 +0000 +++ b/src/gtkblist.c Tue Aug 15 23:25:29 2006 +0000 @@ -3814,12 +3814,11 @@ /* Add the statusbox */ gtkblist->statusbox = gtk_gaim_status_box_new(); + gtk_box_pack_start(GTK_BOX(gtkblist->vbox), gtkblist->statusbox, FALSE, TRUE, 0); gtk_widget_set_name(gtkblist->statusbox, "gaim_gtkblist_statusbox"); - + gtk_gaim_status_box_set_buddy_icon(gtkblist->statusbox, gaim_prefs_get_string("/gaim/gtk/accounts/buddyicon")); gtk_widget_show(gtkblist->statusbox); - gtk_box_pack_start(GTK_BOX(gtkblist->vbox), gtkblist->statusbox, FALSE, TRUE, 0); - - + /* set the Show Offline Buddies option. must be done * after the treeview or faceprint gets mad. -Robot101 */
--- a/src/gtkstatusbox.c Tue Aug 15 20:23:58 2006 +0000 +++ b/src/gtkstatusbox.c Tue Aug 15 23:25:29 2006 +0000 @@ -77,6 +77,8 @@ static gboolean gtk_gaim_status_box_expose_event (GtkWidget *widget, GdkEventExpose *event); static void gtk_gaim_status_box_forall (GtkContainer *container, gboolean include_internals, GtkCallback callback, gpointer callback_data); +static void do_colorshift (GdkPixbuf *dest, GdkPixbuf *src, int shift); + static void (*combo_box_size_request)(GtkWidget *widget, GtkRequisition *requisition); static void (*combo_box_size_allocate)(GtkWidget *widget, GtkAllocation *allocation); static void (*combo_box_forall) (GtkContainer *container, gboolean include_internals, GtkCallback callback, gpointer callback_data); @@ -260,6 +262,17 @@ gaim_signals_disconnect_by_handle(statusbox); gaim_prefs_disconnect_by_handle(statusbox); + gdk_cursor_unref(statusbox->hand_cursor); + gdk_cursor_unref(statusbox->arrow_cursor); + + g_object_unref(G_OBJECT(statusbox->buddy_icon)); + g_object_unref(G_OBJECT(statusbox->buddy_icon_hover)); + + if (statusbox->buddy_icon_sel) + gtk_widget_destroy(statusbox->buddy_icon_sel); + + g_free(statusbox->buddy_icon_path); + G_OBJECT_CLASS(parent_class)->finalize(obj); } @@ -907,6 +920,55 @@ } static void +icon_choose_cb(const char *filename, GtkGaimStatusBox *box) +{ + if (filename) { + GList *accounts; + for (accounts = gaim_accounts_get_all(); accounts != NULL; accounts = accounts->next) { + GaimAccount *account = accounts->data; + if (gaim_account_get_ui_bool(account, GAIM_GTK_UI, "use-global-buddy-icon", TRUE)) { + char *icon = gaim_gtk_convert_buddy_icon(gaim_find_prpl(gaim_account_get_protocol_id(account)), + filename); + gaim_account_set_buddy_icon(account, icon); + g_free(icon); + } + } + gtk_gaim_status_box_set_buddy_icon(box, filename); + } + + box->buddy_icon_sel = NULL; +} + +static gboolean +icon_box_press_cb(GtkWidget *widget, GdkEventButton *event, GtkGaimStatusBox *box) +{ + if (box->buddy_icon_sel) { + gtk_window_present(GTK_WINDOW(box->buddy_icon_sel)); + return FALSE; + } + + GtkWidget *filesel = gaim_gtk_buddy_icon_chooser_new(NULL, icon_choose_cb, box); + gtk_widget_show_all(filesel); + return FALSE; +} + +static gboolean +icon_box_enter_cb(GtkWidget *widget, GdkEventCrossing *event, GtkGaimStatusBox *box) +{ + gdk_window_set_cursor(widget->window, box->hand_cursor); + gtk_image_set_from_pixbuf(box->icon, box->buddy_icon_hover); + return FALSE; +} + +static gboolean +icon_box_leave_cb(GtkWidget *widget, GdkEventCrossing *event, GtkGaimStatusBox *box) +{ + gdk_window_set_cursor(widget->window, box->arrow_cursor); + gtk_image_set_from_pixbuf(box->icon, box->buddy_icon) ; + return FALSE; +} + +static void gtk_gaim_status_box_init (GtkGaimStatusBox *status_box) { GtkCellRenderer *text_rend; @@ -922,6 +984,18 @@ status_box->vsep = gtk_vseparator_new(); status_box->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE); + status_box->buddy_icon = gdk_pixbuf_new_from_file("/home/seanegan/p1120233.jpg", NULL); + status_box->icon = gtk_image_new_from_pixbuf(status_box->buddy_icon); + status_box->icon_box = gtk_event_box_new(); + status_box->hand_cursor = gdk_cursor_new (GDK_HAND2); + status_box->arrow_cursor = gdk_cursor_new (GDK_LEFT_PTR); + + g_signal_connect(G_OBJECT(status_box->icon_box), "enter-notify-event", G_CALLBACK(icon_box_enter_cb), status_box); + g_signal_connect(G_OBJECT(status_box->icon_box), "leave-notify-event", G_CALLBACK(icon_box_leave_cb), status_box); + g_signal_connect(G_OBJECT(status_box->icon_box), "button-press-event", G_CALLBACK(icon_box_press_cb), status_box); + + gtk_container_add(GTK_CONTAINER(status_box->icon_box), status_box->icon); + status_box->store = gtk_list_store_new(NUM_COLUMNS, G_TYPE_INT, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER); status_box->dropdown_store = gtk_list_store_new(NUM_COLUMNS, G_TYPE_INT, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER); gtk_combo_box_set_model(GTK_COMBO_BOX(status_box), GTK_TREE_MODEL(status_box->dropdown_store)); @@ -934,6 +1008,7 @@ gtk_box_pack_start(GTK_BOX(status_box->hbox), status_box->vsep, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(status_box->hbox), status_box->arrow, FALSE, FALSE, 0); gtk_widget_show_all(status_box->toggle_button); + gtk_widget_show_all(status_box->icon_box); #if GTK_CHECK_VERSION(2,4,0) gtk_button_set_focus_on_click(GTK_BUTTON(status_box->toggle_button), FALSE); #endif @@ -984,6 +1059,7 @@ #endif gtk_widget_set_parent(status_box->vbox, GTK_WIDGET(status_box)); gtk_widget_set_parent(status_box->toggle_button, GTK_WIDGET(status_box)); + gtk_widget_set_parent(status_box->icon_box, GTK_WIDGET(status_box)); GTK_BIN(status_box)->child = status_box->toggle_button; gtk_box_pack_start(GTK_BOX(status_box->vbox), status_box->sw, TRUE, TRUE, 0); @@ -1024,14 +1100,58 @@ requisition->height += box_req.height + 3; requisition->width = 1; + + +} + +/* From gnome-panel */ +static void +do_colorshift (GdkPixbuf *dest, GdkPixbuf *src, int shift) +{ + gint i, j; + gint width, height, has_alpha, srcrowstride, destrowstride; + guchar *target_pixels; + guchar *original_pixels; + guchar *pixsrc; + guchar *pixdest; + int val; + guchar r,g,b; + + has_alpha = gdk_pixbuf_get_has_alpha (src); + width = gdk_pixbuf_get_width (src); + height = gdk_pixbuf_get_height (src); + srcrowstride = gdk_pixbuf_get_rowstride (src); + destrowstride = gdk_pixbuf_get_rowstride (dest); + target_pixels = gdk_pixbuf_get_pixels (dest); + original_pixels = gdk_pixbuf_get_pixels (src); + + for (i = 0; i < height; i++) { + pixdest = target_pixels + i*destrowstride; + pixsrc = original_pixels + i*srcrowstride; + for (j = 0; j < width; j++) { + r = *(pixsrc++); + g = *(pixsrc++); + b = *(pixsrc++); + val = r + shift; + *(pixdest++) = CLAMP(val, 0, 255); + val = g + shift; + *(pixdest++) = CLAMP(val, 0, 255); + val = b + shift; + *(pixdest++) = CLAMP(val, 0, 255); + if (has_alpha) + *(pixdest++) = *(pixsrc++); + } + } } static void gtk_gaim_status_box_size_allocate(GtkWidget *widget, - GtkAllocation *allocation) + GtkAllocation *allocation) { + GtkGaimStatusBox *status_box = GTK_GAIM_STATUS_BOX(widget); GtkRequisition req = {0,0}; - GtkAllocation parent_alc, box_alc; + GtkAllocation parent_alc, box_alc, icon_alc; + GdkPixbuf *scaled; combo_box_size_request(widget, &req); @@ -1043,7 +1163,28 @@ parent_alc = *allocation; parent_alc.height = MAX(1,req.height); parent_alc.y += 3; + parent_alc.width -= (parent_alc.height + 3); combo_box_size_allocate(widget, &parent_alc); + + icon_alc = *allocation; + icon_alc.height = MAX(1,req.height); + icon_alc.width = icon_alc.height; + icon_alc.x = allocation->width - icon_alc.width; + icon_alc.y += 3; + + if (status_box->icon_size != icon_alc.height) { + scaled = gdk_pixbuf_new_from_file_at_scale(status_box->buddy_icon_path, + icon_alc.height, icon_alc.width, FALSE, NULL); + status_box->buddy_icon_hover = gdk_pixbuf_copy(scaled); + do_colorshift(status_box->buddy_icon_hover, status_box->buddy_icon_hover, 30); + g_object_unref(status_box->buddy_icon); + status_box->buddy_icon = scaled; + gtk_image_set_from_pixbuf(status_box->icon, status_box->buddy_icon); + status_box->icon_size = icon_alc.height; + } + gtk_widget_size_allocate((GTK_GAIM_STATUS_BOX(widget))->icon_box, &icon_alc); + + gtk_widget_size_allocate((GTK_GAIM_STATUS_BOX(widget))->toggle_button, &parent_alc); widget->allocation = *allocation; } @@ -1055,6 +1196,7 @@ GtkGaimStatusBox *status_box = GTK_GAIM_STATUS_BOX(widget); gtk_container_propagate_expose(GTK_CONTAINER(widget), status_box->vbox, event); gtk_container_propagate_expose(GTK_CONTAINER(widget), status_box->toggle_button, event); + gtk_container_propagate_expose(GTK_CONTAINER(widget), status_box->icon_box, event); return FALSE; } @@ -1071,6 +1213,7 @@ (* callback) (status_box->vbox, callback_data); (* callback) (status_box->toggle_button, callback_data); (* callback) (status_box->arrow, callback_data); + (* callback) (status_box->icon_box, callback_data); } combo_box_forall(container, include_internals, callback, callback_data); @@ -1179,6 +1322,30 @@ } void +gtk_gaim_status_box_set_buddy_icon(GtkGaimStatusBox *box, const char *filename) +{ + GdkPixbuf *scaled; + g_free(box->buddy_icon_path); + box->buddy_icon_path = g_strdup(filename); + + scaled = gdk_pixbuf_new_from_file_at_scale(filename, + box->icon_size, box->icon_size, FALSE, NULL); + box->buddy_icon_hover = gdk_pixbuf_copy(scaled); + do_colorshift(box->buddy_icon_hover, box->buddy_icon_hover, 30); + g_object_unref(box->buddy_icon); + box->buddy_icon = scaled; + gtk_image_set_from_pixbuf(box->icon, box->buddy_icon); + + gaim_prefs_set_string("/gaim/gtk/accounts/buddyicon", filename); +} + +const char* +gtk_gaim_status_box_get_buddy_icon(GtkGaimStatusBox *box) +{ + return box->buddy_icon_path; +} + +void gtk_gaim_status_box_pulse_connecting(GtkGaimStatusBox *status_box) { if (!status_box)
--- a/src/gtkstatusbox.h Tue Aug 15 20:23:58 2006 +0000 +++ b/src/gtkstatusbox.h Tue Aug 15 23:25:29 2006 +0000 @@ -83,6 +83,17 @@ GtkWidget *vbox, *sw; GtkWidget *imhtml; + + char *buddy_icon_path; + GdkPixbuf *buddy_icon; + GdkPixbuf *buddy_icon_hover; + GtkWidget *buddy_icon_sel; + GtkWidget *icon; + GtkWidget *icon_box; + GdkCursor *hand_cursor; + GdkCursor *arrow_cursor; + int icon_size; + gboolean imhtml_visible; GtkWidget *cell_view; @@ -146,6 +157,12 @@ void gtk_gaim_status_box_pulse_connecting(GtkGaimStatusBox *status_box); +void +gtk_gaim_status_box_set_buddy_icon(GtkGaimStatusBox *status_box, const char *filename); + +const char * +gtk_gaim_status_box_get_buddy_icon(GtkGaimStatusBox *status_box); + char *gtk_gaim_status_box_get_message(GtkGaimStatusBox *status_box); G_END_DECLS
--- 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(_("<b>File:</b> %s\n" + "<b>File size:</b> %s\n" + "<b>Image size:</b> %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 +}
--- a/src/gtkutils.h Tue Aug 15 20:23:58 2006 +0000 +++ b/src/gtkutils.h Tue Aug 15 23:25:29 2006 +0000 @@ -460,4 +460,23 @@ */ void gaim_gtk_clear_cursor(GtkWidget *widget); +/** + * Creates a File Selection widget for choosing a buddy icon + * + * @param parent The parent window + * @param callback The callback to call when the window is closed. If the user chose an icon, the char* argument will point to its path + * @param data Data to pass to @callback + * @return The file dialog + */ +GtkWidget *gaim_gtk_buddy_icon_chooser_new(GtkWindow *parent, void(*callback)(const char*,gpointer), gpointer data); + +/** + * Converts a buddy icon to the required size and format + * + * @param plugin The prpl to conver the icon + * @param path The path of a buddy icon to convert + * @return The path of a new buddy icon + */ +char* gaim_gtk_convert_buddy_icon(GaimPlugin *plugin, const char *path); + #endif /* _GAIM_GTKUTILS_H_ */