Mercurial > pidgin
changeset 14852:cf25420b074d
[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 <tailor@pidgin.im>
author | Sadrul Habib Chowdhury <imadil@gmail.com> |
---|---|
date | Sun, 29 Oct 2006 23:35:57 +0000 |
parents | 036927fddcba |
children | 910e783fbbc7 |
files | ChangeLog.API gtk/gtkblist.c gtk/gtkconv.c gtk/gtkutils.c gtk/gtkutils.h |
diffstat | 5 files changed, 182 insertions(+), 32 deletions(-) [+] |
line wrap: on
line diff
--- 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
--- 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") &&
--- 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;
--- 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); +} + +
--- 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);