# HG changeset patch # User Sadrul Habib Chowdhury # Date 1162164957 0 # Node ID cf25420b074de3019dbc76214d804f76d2af5554 # Parent 036927fddcbaaed58ac369eca17cffe46ec35f0f [gaim-migrate @ 17621] Allow custom buddy icons for people in the buddylist. It's done completely in the UI side. The custom icon does not overwrite the original icon, which is displayed in the tooltip. You can set the icon by dragging an image on the conv window, or on the buddy in the buddylist. You can also set/remove custom icon from the conversation window by right clicking on the icon in the conv window. committer: Tailor Script diff -r 036927fddcba -r cf25420b074d ChangeLog.API --- a/ChangeLog.API Sun Oct 29 23:28:37 2006 +0000 +++ b/ChangeLog.API Sun Oct 29 23:35:57 2006 +0000 @@ -138,6 +138,7 @@ a change in the values stored in the column. * gaim_find_buddies() returns a list of all buddies in the account if name is NULL. + * gaim_gtk_set_custom_buddy_icon() sets custom icon for a user. Removed: * gaim_gtk_sound_{get,set}_mute() (replaced by the /gaim/gtk/sound/mute diff -r 036927fddcba -r cf25420b074d gtk/gtkblist.c --- a/gtk/gtkblist.c Sun Oct 29 23:28:37 2006 +0000 +++ b/gtk/gtkblist.c Sun Oct 29 23:35:57 2006 +0000 @@ -1992,12 +1992,12 @@ } static GdkPixbuf *gaim_gtk_blist_get_buddy_icon(GaimBlistNode *node, - gboolean scaled, gboolean greyed) + gboolean scaled, gboolean greyed, gboolean custom) { GdkPixbuf *buf, *ret = NULL; GdkPixbufLoader *loader; GaimBuddyIcon *icon; - const guchar *data; + const guchar *data = NULL; gsize len; GaimBuddy *buddy = (GaimBuddy *)node; @@ -2014,12 +2014,30 @@ return NULL; #endif - if (!(icon = gaim_buddy_get_icon(buddy))) - if (!(icon = gaim_buddy_icons_find(buddy->account, buddy->name))) /* Not sure I like this...*/ - return NULL; + if (custom) { + const char *file = gaim_blist_node_get_string((GaimBlistNode*)gaim_buddy_get_contact(buddy), + "custom_buddy_icon"); + if (file && *file) { + char *contents; + GError *err = NULL; + if (!g_file_get_contents(file, &contents, &len, &err)) { + gaim_debug_info("custom -icon", "Could not open custom-icon %s for %s\n", + file, gaim_buddy_get_name(buddy), err->message); + g_error_free(err); + } else + data = (const guchar*)contents; + } + } + + if (data == NULL) { + if (!(icon = gaim_buddy_get_icon(buddy))) + if (!(icon = gaim_buddy_icons_find(buddy->account, buddy->name))) /* Not sure I like this...*/ + return NULL; + data = gaim_buddy_icon_get_data(icon, &len); + custom = FALSE; /* We are not using the custom icon */ + } loader = gdk_pixbuf_loader_new(); - data = gaim_buddy_icon_get_data(icon, &len); gdk_pixbuf_loader_write(loader, data, len, NULL); gdk_pixbuf_loader_close(loader, NULL); buf = gdk_pixbuf_loader_get_pixbuf(loader); @@ -2027,6 +2045,8 @@ g_object_ref(G_OBJECT(buf)); g_object_unref(G_OBJECT(loader)); + if (custom) + g_free((void*)data); if (buf) { GaimAccount *account = gaim_buddy_get_account(buddy); GaimPluginProtocolInfo *prpl_info = NULL; @@ -2088,7 +2108,7 @@ struct tooltip_data *td = g_new0(struct tooltip_data, 1); td->status_icon = gaim_gtk_blist_get_status_icon(node, GAIM_STATUS_ICON_LARGE); - td->avatar = gaim_gtk_blist_get_buddy_icon(node, !full, FALSE); + td->avatar = gaim_gtk_blist_get_buddy_icon(node, !full, FALSE, FALSE); tooltip_text = gaim_get_tooltip_text(node, full); td->layout = gtk_widget_create_pango_layout(gtkblist->tipwindow, NULL); pango_layout_set_markup(td->layout, tooltip_text, -1); @@ -4470,7 +4490,7 @@ status = gaim_gtk_blist_get_status_icon((GaimBlistNode*)buddy, biglist ? GAIM_STATUS_ICON_LARGE : GAIM_STATUS_ICON_SMALL); - avatar = gaim_gtk_blist_get_buddy_icon((GaimBlistNode *)buddy, TRUE, TRUE); + avatar = gaim_gtk_blist_get_buddy_icon((GaimBlistNode *)buddy, TRUE, TRUE, TRUE); mark = gaim_gtk_blist_get_name_markup(buddy, selected); if (gaim_prefs_get_bool("/gaim/gtk/blist/show_idle_time") && diff -r 036927fddcba -r cf25420b074d gtk/gtkconv.c --- a/gtk/gtkconv.c Sun Oct 29 23:28:37 2006 +0000 +++ b/gtk/gtkconv.c Sun Oct 29 23:35:57 2006 +0000 @@ -2354,7 +2354,7 @@ } static void -remove_icon(GaimGtkConversation *gtkconv) +remove_icon(GtkWidget *widget, GaimGtkConversation *gtkconv) { GaimConversation *conv = gtkconv->active_conv; GaimGtkWindow *gtkwin; @@ -2412,6 +2412,53 @@ fclose(fp); } +static const char * +custom_icon_pref_name(GaimGtkConversation *gtkconv) +{ + GaimConversation *conv; + GaimAccount *account; + GaimBuddy *buddy; + + conv = gtkconv->active_conv; + account = gaim_conversation_get_account(conv); + buddy = gaim_find_buddy(account, gaim_conversation_get_name(conv)); + if (buddy) { + GaimContact *contact = gaim_buddy_get_contact(buddy); + return gaim_blist_node_get_string((GaimBlistNode*)contact, "custom_buddy_icon"); + } + return NULL; +} + +static void +custom_icon_sel_cb(const char *filename, gpointer data) +{ + if (filename) { + GaimGtkConversation *gtkconv = data; + GaimConversation *conv = gtkconv->active_conv; + GaimAccount *account = gaim_conversation_get_account(conv); + gaim_gtk_set_custom_buddy_icon(account, gaim_conversation_get_name(conv), filename); + } +} + +static void +set_custom_icon_cb(GtkWidget *widget, GaimGtkConversation *gtkconv) +{ + GtkWidget *win = gaim_gtk_buddy_icon_chooser_new(GTK_WINDOW(gtkconv->win->window), + custom_icon_sel_cb, gtkconv); + gtk_widget_show_all(win); +} + +static void +remove_custom_icon_cb(GtkWidget *widget, GaimGtkConversation *gtkconv) +{ + GaimConversation *conv; + GaimAccount *account; + + conv = gtkconv->active_conv; + account = gaim_conversation_get_account(conv); + gaim_gtk_set_custom_buddy_icon(account, gaim_conversation_get_name(conv), NULL); +} + static void icon_menu_save_cb(GtkWidget *widget, GaimGtkConversation *gtkconv) { @@ -2459,7 +2506,7 @@ icon_menu(GtkObject *obj, GdkEventButton *e, GaimGtkConversation *gtkconv) { static GtkWidget *menu = NULL; - GtkWidget *item; + const char *pref; if (e->button != 3 || e->type != GDK_BUTTON_PRESS) return FALSE; @@ -2481,16 +2528,25 @@ gtkconv->u.im->icon_timer); } - item = gtk_menu_item_new_with_label(_("Hide Icon")); - g_signal_connect_swapped(G_OBJECT(item), "activate", - G_CALLBACK(remove_icon), gtkconv); - gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); - gtk_widget_show(item); + gaim_new_item_from_stock(menu, _("Hide Icon"), NULL, G_CALLBACK(remove_icon), + gtkconv, 0, 0, NULL); gaim_new_item_from_stock(menu, _("Save Icon As..."), GTK_STOCK_SAVE_AS, G_CALLBACK(icon_menu_save_cb), gtkconv, 0, 0, NULL); + gaim_new_item_from_stock(menu, _("Set Custom Icon..."), NULL, + G_CALLBACK(set_custom_icon_cb), gtkconv, + 0, 0, NULL); + + /* Is there a custom icon for this person? */ + pref = custom_icon_pref_name(gtkconv); + if (pref && *pref) { + gaim_new_item_from_stock(menu, _("Remove Custom Icon"), NULL, + G_CALLBACK(remove_custom_icon_cb), gtkconv, + 0, 0, NULL); + } + gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, e->button, e->time); return TRUE; @@ -2518,7 +2574,7 @@ if (active) gaim_gtkconv_update_buddy_icon(conv); else - remove_icon(gtkconv); + remove_icon(NULL, gtkconv); } /************************************************************************** @@ -5836,7 +5892,8 @@ GdkPixbufAnimation *anim; GError *err = NULL; - const void *data; + const char *custom = NULL; + const void *data = NULL; size_t len; GdkPixbuf *buf; @@ -5893,12 +5950,28 @@ if (gaim_conversation_get_gc(conv) == NULL) return; - icon = gaim_conv_im_get_icon(GAIM_CONV_IM(conv)); - - if (icon == NULL) - return; - - data = gaim_buddy_icon_get_data(icon, &len); + custom = custom_icon_pref_name(gtkconv); + if (custom) { + /* There is a custom icon for this user */ + char *contents = NULL; + if (!g_file_get_contents(custom, &contents, &len, &err)) { + gaim_debug_warning("custom icon", "could not load custom icon %s for %s\n", + custom, gaim_conversation_get_name(conv)); + g_error_free(err); + err = NULL; + } else + data = contents; + } + + if (data == NULL) { + icon = gaim_conv_im_get_icon(GAIM_CONV_IM(conv)); + + if (icon == NULL) + return; + + data = gaim_buddy_icon_get_data(icon, &len); + custom = NULL; + } loader = gdk_pixbuf_loader_new(); gdk_pixbuf_loader_write(loader, data, len, NULL); @@ -5908,6 +5981,9 @@ g_object_ref(G_OBJECT(anim)); g_object_unref(loader); + if (custom) + g_free((void*)data); + if (!anim) return; gtkconv->u.im->anim = anim; diff -r 036927fddcba -r cf25420b074d gtk/gtkutils.c --- a/gtk/gtkutils.c Sun Oct 29 23:28:37 2006 +0000 +++ b/gtk/gtkutils.c Sun Oct 29 23:35:57 2006 +0000 @@ -1,5 +1,5 @@ /** - * @file gtkutils.h GTK+ utility functions + * @file gtkutils.c GTK+ utility functions * @ingroup gtkui * * gaim @@ -1296,6 +1296,7 @@ { char *filedata; size_t size; + struct stat st; GError *err = NULL; GaimConversation *conv; GaimGtkConversation *gtkconv; @@ -1303,23 +1304,20 @@ int id; switch (choice) { case DND_BUDDY_ICON: - if (!g_file_get_contents(data->filename, &filedata, &size, - &err)) { + if (g_stat(data->filename, &st)) { char *str; - str = g_strdup_printf(_("The following error has occurred loading %s: %s"), data->filename, err->message); + str = g_strdup_printf(_("The following error has occurred loading %s: %s"), + data->filename, strerror(errno)); gaim_notify_error(NULL, NULL, _("Failed to load image"), str); - - g_error_free(err); g_free(str); return; } - gaim_buddy_icons_set_for_user(data->account, data->who, filedata, size); - g_free(filedata); + gaim_gtk_set_custom_buddy_icon(data->account, data->who, data->filename); break; case DND_FILE_TRANSFER: serv_send_file(gaim_account_get_connection(data->account), data->who, data->filename); @@ -2795,3 +2793,48 @@ } #endif +void gaim_gtk_set_custom_buddy_icon(GaimAccount *account, const char *who, const char *filename) +{ + GaimConversation *conv; + GaimBuddy *buddy; + GaimBlistNode *node; + char *path = NULL; + + buddy = gaim_find_buddy(account, who); + if (!buddy) { + gaim_debug_info("custom-icon", "You can only set custom icon for someone in your buddylist.\n"); + return; + } + + node = (GaimBlistNode*)gaim_buddy_get_contact(buddy); + path = (char*)gaim_blist_node_get_string(node, "custom_buddy_icon"); + if (path) { + struct stat st; + if (g_stat(path, &st) == 0) + g_unlink(path); + path = NULL; + } + + if (filename) { + char *newfile; + + newfile = gaim_gtk_convert_buddy_icon(gaim_find_prpl(gaim_account_get_protocol_id(account)), + filename); + path = gaim_buddy_icons_get_full_path(newfile); + g_free(newfile); + } + + gaim_blist_node_set_string(node, "custom_buddy_icon", path); + g_free(path); + + /* Update the conversation */ + conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, who, account); + if (conv) + gaim_conversation_update(conv, GAIM_CONV_UPDATE_ICON); + + /* Update the buddylist */ + if (buddy) + gaim_blist_update_buddy_icon(buddy); +} + + diff -r 036927fddcba -r cf25420b074d gtk/gtkutils.h --- a/gtk/gtkutils.h Sun Oct 29 23:28:37 2006 +0000 +++ b/gtk/gtkutils.h Sun Oct 29 23:35:57 2006 +0000 @@ -475,7 +475,7 @@ * * @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 + * @return The name of a new buddy icon */ char* gaim_gtk_convert_buddy_icon(GaimPlugin *plugin, const char *path); @@ -491,3 +491,13 @@ #endif #endif /* _GAIM_GTKUTILS_H_ */ + +/** + * Set or unset a custom buddyicon for a user. + * + * @param account The account the user belongs to. + * @param who The name of the user. + * @param filename The path of the custom icon. If this is @c NULL, then any + * previously set custom buddy icon for the user is removed. + */ +void gaim_gtk_set_custom_buddy_icon(GaimAccount *account, const char *who, const char *filename);