# HG changeset patch # User Tim Ringenbach # Date 1106073092 0 # Node ID 55e7d72fc09a08e249935ffa1b083558c9df2f69 # Parent ddea15f4cbc2086a4e6afe7114402c638a9f7d8e [gaim-migrate @ 11843] maquina writes: This patch implements a custom smiley API, and it also implements custom smileys for the msn protocol. As it stands, it is not able to cache custom smileys, and is not able to redefine a custom smiley without opening a new conversation. I modified it quite a bit, and didn't test it at all, so it probably doesn't work anymore. I'm not quite done with it yet either. Also, this is just receiving custom smileys. committer: Tailor Script diff -r ddea15f4cbc2 -r 55e7d72fc09a ChangeLog --- a/ChangeLog Tue Jan 18 15:36:39 2005 +0000 +++ b/ChangeLog Tue Jan 18 18:31:32 2005 +0000 @@ -20,6 +20,7 @@ * Add a "Last Seen" field to tooltips for buddies in your buddy list (Richard Laager) * Buddy icons in buddy list tooltips (Felipe Contreras) + * Custom smileys for MSN (maquina) Bug fixes: * Some memory leaks plugged (Miah Gregory, Felipe Contreras) diff -r ddea15f4cbc2 -r 55e7d72fc09a src/conversation.c --- a/src/conversation.c Tue Jan 18 15:36:39 2005 +0000 +++ b/src/conversation.c Tue Jan 18 18:31:32 2005 +0000 @@ -1755,6 +1755,51 @@ common_send(gaim_conv_im_get_conversation(im), message); } +gboolean +gaim_conv_custom_smiley_add(GaimConversation *conv, const char *smile, + const char *cksum_type, const char *chksum) +{ + if (conv == NULL || smile == NULL || !*smile) { + return FALSE; + } + + /* TODO: check if the icon is in the cache and return false if so */ + /* TODO: add an icon cache (that doesn't suck) */ + if (conv->ui_ops != NULL && conv->ui_ops->custom_smiley_add !=NULL) { + return conv->ui_ops->custom_smiley_add(conv, smile); + } else { + gaim_debug_info("conversation", "Could not find add custom smiley function"); + return FALSE; + } + +} + +void +gaim_conv_custom_smiley_write(GaimConversation *conv, const char *smile, + const char * data, gint64 size) +{ + g_return_if_fail(conv != NULL); + g_return_if_fail(smile != NULL && *smile); + + if (conv->ui_ops != NULL && conv->ui_ops->custom_smiley_write != NULL) + conv->ui_ops->custom_smiley_write(conv, smile, data, size); + else + gaim_debug_info("conversation", "Could not find the smiley write function"); +} + +void +gaim_conv_custom_smiley_close(GaimConversation *conv, const char *smile) +{ + g_return_if_fail(conv != NULL); + g_return_if_fail(smile != NULL && *smile); + + if (conv->ui_ops != NULL && conv->ui_ops->custom_smiley_close != NULL) + conv->ui_ops->custom_smiley_close(conv, smile); + else + gaim_debug_info("conversation", "Could not find custom smiley close function"); +} + + /************************************************************************** * Chat Conversation API **************************************************************************/ diff -r ddea15f4cbc2 -r 55e7d72fc09a src/conversation.h --- a/src/conversation.h Tue Jan 18 15:36:39 2005 +0000 +++ b/src/conversation.h Tue Jan 18 18:31:32 2005 +0000 @@ -199,6 +199,14 @@ gboolean (*has_focus)(GaimConversation *conv); + /* Custom Smileys */ + gboolean (*custom_smiley_add)(GaimConversation *conv, const char *smile); + void (*custom_smiley_write)(GaimConversation *conv, const char *smile, + const char * data, gint64 size); + void (*custom_smiley_close)(GaimConversation *conv, const char *smile); + + + /* Events */ void (*updated)(GaimConversation *conv, GaimConvUpdateType type); @@ -1033,6 +1041,47 @@ */ void gaim_conv_im_send(GaimConvIm *im, const char *message); +/** + * Adds a smiley to the conversation's smiley tree. + * + * @param conv The conversation to associate the smiley with. + * @param smile The text associated with the smiley + * @param cksum_type The type of checksum. + * @param chksum The checksum, as a NUL terminated base64 string. + * @return @c TRUE if an icon is excepted, else FALSE. Note that + * it is an error to never call gaim_conv_custom_smiley_close if + * this function returns @c TRUE, but an error to call it if + * @c FALSE is returned. + */ + +gboolean gaim_conv_custom_smiley_add(GaimConversation *conv, const char *smile, + const char *cksum_type, const char *chksum); + + +/** + * Updates the image associated with the current smiley. + * + * @param conv The conversation associated with the smiley. + * @param smile The text associated with the smiley. + * @param data The actual image data. + * @param size The length of the data. + */ + +void gaim_conv_custom_smiley_write(GaimConversation *conv, + const char *smile, const char * data, + gint64 size); + +/** + * Close the custom smiley, all data has been written with + * gaim_conv_custom_smiley_write, and it is no longer valid + * to call that function on that smiley. + * + * @param conv The gaim conversation associated with the smiley. + * @param smile The text associated with the smiley + */ + +void gaim_conv_custom_smiley_close(GaimConversation *conv, const char *smile); + /*@}*/ diff -r ddea15f4cbc2 -r 55e7d72fc09a src/gtkconv.c --- a/src/gtkconv.c Tue Jan 18 15:36:39 2005 +0000 +++ b/src/gtkconv.c Tue Jan 18 18:31:32 2005 +0000 @@ -5169,6 +5169,102 @@ return has_focus; } +static gboolean +gaim_gtkconv_custom_smiley_add(GaimConversation *conv, const char *smile) +{ + GaimGtkConversation *gtkconv; + GtkIMHtmlSmiley *smiley; + GdkPixbufLoader *loader; + const char *sml; + + if (conv == NULL || smile == NULL) { + return FALSE; + } + + sml = gaim_account_get_protocol_name(conv->account); /* XXX this sucks */ + gtkconv = GAIM_GTK_CONVERSATION(conv); + smiley = gtk_imhtml_smiley_get(GTK_IMHTML(gtkconv->imhtml), sml, smile); + + /* TODO: implement changing a custom smiley in the middle of a conversation */ + + if (smiley) { + return FALSE; + } + + + loader = gdk_pixbuf_loader_new(); + + /* this is wrong, this file ought not call g_new on GtkIMHtmlSmiley */ + /* Let gtk_imhtml have a gtk_imhtml_smiley_new function, and let + GtkIMHtmlSmiley by opque */ + smiley = g_new0(GtkIMHtmlSmiley, 1); + smiley->file = NULL; + smiley->smile = g_strdup(smile); + smiley->loader = loader; + + smiley->icon = gdk_pixbuf_loader_get_animation(loader); + if (smiley->icon) + g_object_ref(G_OBJECT(smiley->icon)); + + gtk_imhtml_associate_smiley(GTK_IMHTML(gtkconv->imhtml), sml, smiley); + + return TRUE; +} + +static void +gaim_gtkconv_custom_smiley_write(GaimConversation *conv, const char *smile, + const char * data, gint64 size) +{ + GaimGtkConversation *gtkconv; + GtkIMHtmlSmiley *smiley; + GdkPixbufLoader *loader; + const char *sml; + + sml = gaim_account_get_protocol_name(conv->account); + gtkconv = GAIM_GTK_CONVERSATION(conv); + smiley = gtk_imhtml_smiley_get(GTK_IMHTML(gtkconv->imhtml), sml, smile); + + if (!smiley) + return; + + loader = smiley->loader; + if (!loader) + return; + + gdk_pixbuf_loader_write(loader, data, size, NULL); +} + +static void +gaim_gtkconv_custom_smiley_close(GaimConversation *conv, const char *smile) +{ + GaimGtkConversation *gtkconv; + GtkIMHtmlSmiley *smiley; + GdkPixbufLoader *loader; + const char *sml; + + g_return_if_fail(conv != NULL); + g_return_if_fail(smile != NULL); + + sml = gaim_account_get_protocol_name(conv->account); + gtkconv = GAIM_GTK_CONVERSATION(conv); + smiley = gtk_imhtml_smiley_get(GTK_IMHTML(gtkconv->imhtml), sml, smile); + + if (!smiley) + return; + + loader = smiley->loader; + + if (!loader) + return; + + gaim_debug_info("gtkconv", "About to close the smiley pixbuf\n"); + + gdk_pixbuf_loader_close(loader, NULL); + g_object_unref(G_OBJECT(loader)); + smiley->loader = NULL; +} + + static void gaim_gtkconv_updated(GaimConversation *conv, GaimConvUpdateType type) { @@ -5320,6 +5416,9 @@ gaim_gtkconv_chat_update_user, /* chat_update_user */ NULL, /* update_progress */ gaim_gtkconv_has_focus, /* has_focus */ + gaim_gtkconv_custom_smiley_add, /* custom_smiley_add */ + gaim_gtkconv_custom_smiley_write, /* custom_smiley_write */ + gaim_gtkconv_custom_smiley_close, /* custom_smiley_close */ gaim_gtkconv_updated /* updated */ }; diff -r ddea15f4cbc2 -r 55e7d72fc09a src/gtkimhtml.c --- a/src/gtkimhtml.c Tue Jan 18 15:36:39 2005 +0000 +++ b/src/gtkimhtml.c Tue Jan 18 18:31:32 2005 +0000 @@ -1530,10 +1530,10 @@ return (*len > 0); } -GdkPixbufAnimation * -gtk_smiley_tree_image (GtkIMHtml *imhtml, - const gchar *sml, - const gchar *text) +GtkIMHtmlSmiley * +gtk_imhtml_smiley_get(GtkIMHtml *imhtml, + const gchar *sml, + const gchar *text) { GtkSmileyTree *t; const gchar *x = text; @@ -1544,31 +1544,49 @@ if (t == NULL) - return sml ? gtk_smiley_tree_image(imhtml, NULL, text) : NULL; + return sml ? gtk_imhtml_smiley_get(imhtml, NULL, text) : NULL; while (*x) { gchar *pos; if (!t->values) { - return sml ? gtk_smiley_tree_image(imhtml, NULL, text) : NULL; + return sml ? gtk_imhtml_smiley_get(imhtml, NULL, text) : NULL; } pos = strchr (t->values->str, *x); if (pos) { t = t->children [GPOINTER_TO_INT(pos) - GPOINTER_TO_INT(t->values->str)]; } else { - return sml ? gtk_smiley_tree_image(imhtml, NULL, text) : NULL; + return sml ? gtk_imhtml_smiley_get(imhtml, NULL, text) : NULL; } x++; } - if (!t->image->file) + return t->image; +} + +GdkPixbufAnimation * +gtk_smiley_tree_image (GtkIMHtml *imhtml, + const gchar *sml, + const gchar *text) +{ + + GtkIMHtmlSmiley *smiley; + + smiley = gtk_imhtml_smiley_get(imhtml,sml,text); + + if (!smiley) return NULL; - if (!t->image->icon) - t->image->icon = gdk_pixbuf_animation_new_from_file(t->image->file, NULL); - - return t->image->icon; + if (!smiley->icon && smiley->file) { + smiley->icon = gdk_pixbuf_animation_new_from_file(smiley->file, NULL); + } else if (!smiley->icon && smiley->loader) { + smiley->icon = gdk_pixbuf_loader_get_animation(smiley->loader); + if (smiley->icon) + g_object_ref(G_OBJECT(smiley->icon)); + } + + return smiley->icon; } #define VALID_TAG(x) if (!g_ascii_strncasecmp (string, x ">", strlen (x ">"))) { \ @@ -3839,19 +3857,31 @@ GtkTextChildAnchor *anchor; char *unescaped = gaim_unescape_html(smiley); - if (imhtml->format_functions & GTK_IMHTML_SMILEY) - { + if (imhtml->format_functions & GTK_IMHTML_SMILEY) { annipixbuf = gtk_smiley_tree_image(imhtml, sml, unescaped); - if(annipixbuf) { - if(gdk_pixbuf_animation_is_static_image(annipixbuf)) { + if (annipixbuf) { + if (gdk_pixbuf_animation_is_static_image(annipixbuf)) { pixbuf = gdk_pixbuf_animation_get_static_image(annipixbuf); - if(pixbuf) + if (pixbuf) icon = gtk_image_new_from_pixbuf(pixbuf); } else { icon = gtk_image_new_from_animation(annipixbuf); } } } +#if 0 + else { + GtkIMHtmlSmiley *imhtml_smiley; + + if (imhtml_smiley->loader) { ; } + icon = gtk_image_new_from_stock(GTK_STOCK_MISSING_IMAGE, GTK_ICON_SIZE_MENU); + imhtml_smiley = gtk_get_imhtml_smiley(imhtml, sml, unescaped); + if (!imhtml_smiley) { + gaim_debug_info("gtkimhtml", "geezz couldnt find smiley struct\n"); + } + imhtml_smiley->orphan = g_slist_append(imhtml_smiley->orphan, icon); + } +#endif if (icon) { anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, iter); diff -r ddea15f4cbc2 -r 55e7d72fc09a src/gtkimhtml.h --- a/src/gtkimhtml.h Tue Jan 18 15:36:39 2005 +0000 +++ b/src/gtkimhtml.h Tue Jan 18 18:31:32 2005 +0000 @@ -149,6 +149,7 @@ gchar *file; GdkPixbufAnimation *icon; gboolean hidden; + GdkPixbufLoader *loader; }; struct _GtkIMHtmlScalable { @@ -246,6 +247,18 @@ GtkWidget *gtk_imhtml_new(void *, void *); /** + * Returns the smiley object associated with the text. + * + * @param imhtml The GTK IM/HTML. + * @param sml The name of the smiley category. + * @param text The text associated with the smiley. + */ + +GtkIMHtmlSmiley *gtk_imhtml_smiley_get(GtkIMHtml * imhtml, + const gchar * sml, const gchar * text); + + +/** * Associates a smiley with a GTK IM/HTML. * * @param imhtml The GTK IM/HTML. diff -r ddea15f4cbc2 -r 55e7d72fc09a src/protocols/msn/slp.c --- a/src/protocols/msn/slp.c Tue Jan 18 15:36:39 2005 +0000 +++ b/src/protocols/msn/slp.c Tue Jan 18 18:31:32 2005 +0000 @@ -739,18 +739,24 @@ got_emoticon(MsnSlpCall *slpcall, const char *data, long long size) { - gaim_debug_info("msn", "Got smiley: %s\n", slpcall->data_info); + + GaimConversation *conv; + GaimConnection *gc; + const char *who; -#if 0 - serv_got_smiley(slpcall->slplink->session->account->gc, - slpcall->slplink->remote_user, slpcall->data_info, data, size); -#endif + gc = slpcall->slplink->session->account->gc; + who = slpcall->slplink->remote_user; + + conv = gaim_find_conversation_with_account(GAIM_CONV_ANY, who, gc->account); -#if 0 - GaimConversation *conv; - GaimConnection *gc = slpsession->swboard->servconn->session->account->gc; - serv_got_smiley(gc, info, data, size); -#endif + /* FIXME: it would be better if we wrote the data as we received it + instead of all at once, calling write multiple times and + close once at the very end + */ + gaim_conv_custom_smiley_write(conv, slpcall->data_info, data, size); + gaim_conv_custom_smiley_close(conv, slpcall->data_info ); + + gaim_debug_info("msn", "Got smiley: %s\n", slpcall->data_info); } void @@ -763,6 +769,9 @@ char *smile; const char *who; + GaimConversation *conversation; + GaimConnection *gc; + session = cmdproc->servconn->session; tokens = g_strsplit(msg->body, "\t", 2); @@ -774,7 +783,13 @@ slplink = msn_session_get_slplink(session, who); - msn_slplink_request_object(slplink, smile, got_emoticon, NULL, obj); + gc = slplink->session->account->gc; + + conversation = gaim_find_conversation_with_account(GAIM_CONV_ANY, who, gc->account); + + if (gaim_conv_custom_smiley_add(conversation, smile, "sha1" /* i think it's a sha1 checksum? */, "base64 encoded checksum here, shx should fix this!")) { + msn_slplink_request_object(slplink, smile, got_emoticon, NULL, obj); + } g_strfreev(tokens); }