# HG changeset patch # User Sadrul Habib Chowdhury # Date 1205801272 0 # Node ID 019052a807a32bf3ccda72cb22f5a5166c768794 # Parent 98167ea7c0932c9ff812e708e62b8851242070bb Introduce API for GtkIMHtmlSmiley. Use this to prevent leaking remote custom emoticons. diff -r 98167ea7c093 -r 019052a807a3 ChangeLog.API --- a/ChangeLog.API Fri Mar 14 23:41:03 2008 +0000 +++ b/ChangeLog.API Tue Mar 18 00:47:52 2008 +0000 @@ -1,5 +1,11 @@ Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul +version 2.5.0 (??/??/2008): + pidgin: + Added: + * gtk_imhtml_smiley_create, gtk_imhtml_smiley_reload and + gtk_imhtml_smiley_destroy to deal with GtkIMHtmlSmiley's. + version 2.4.0 (02/29/2008): libpurple: Added: diff -r 98167ea7c093 -r 019052a807a3 pidgin/gtkconv.c --- a/pidgin/gtkconv.c Fri Mar 14 23:41:03 2008 +0000 +++ b/pidgin/gtkconv.c Tue Mar 18 00:47:52 2008 +0000 @@ -157,8 +157,6 @@ static void update_typing_message(PidginConversation *gtkconv, const char *message); static const char *item_factory_translate_func (const char *path, gpointer func_data); gboolean pidgin_conv_has_focus(PurpleConversation *conv); -static void pidgin_conv_custom_smiley_allocated(GdkPixbufLoader *loader, gpointer user_data); -static void pidgin_conv_custom_smiley_closed(GdkPixbufLoader *loader, gpointer user_data); static GdkColor* generate_nick_colors(guint *numcolors, GdkColor background); static gboolean color_is_visible(GdkColor foreground, GdkColor background, int color_contrast, int brightness_contrast); static void pidgin_conv_update_fields(PurpleConversation *conv, PidginConvFields fields); @@ -5985,119 +5983,24 @@ return FALSE; } -static void pidgin_conv_custom_smiley_allocated(GdkPixbufLoader *loader, gpointer user_data) -{ - GtkIMHtmlSmiley *smiley; - - smiley = (GtkIMHtmlSmiley *)user_data; - smiley->icon = gdk_pixbuf_loader_get_animation(loader); - - if (smiley->icon) - g_object_ref(G_OBJECT(smiley->icon)); -#ifdef DEBUG_CUSTOM_SMILEY - purple_debug_info("custom-smiley", "pidgin_conv_custom_smiley_allocated(): got GdkPixbufAnimation %p for smiley '%s'\n", smiley->icon, smiley->smile); -#endif -} - -static void pidgin_conv_custom_smiley_closed(GdkPixbufLoader *loader, gpointer user_data) -{ - GtkIMHtmlSmiley *smiley; - GtkWidget *icon = NULL; - GtkTextChildAnchor *anchor = NULL; - GSList *current = NULL; - - smiley = (GtkIMHtmlSmiley *)user_data; - if (!smiley->imhtml) { -#ifdef DEBUG_CUSTOM_SMILEY - purple_debug_error("custom-smiley", "pidgin_conv_custom_smiley_closed(): orphan smiley found: %p\n", smiley); -#endif - g_object_unref(G_OBJECT(loader)); - smiley->loader = NULL; - return; - } - - for (current = smiley->anchors; current; current = g_slist_next(current)) { - - icon = gtk_image_new_from_animation(smiley->icon); - -#ifdef DEBUG_CUSTOM_SMILEY - purple_debug_info("custom-smiley", "pidgin_conv_custom_smiley_closed(): got GtkImage %p from GtkPixbufAnimation %p for smiley '%s'\n", - icon, smiley->icon, smiley->smile); -#endif - if (icon) { - GList *wids; - gtk_widget_show(icon); - - anchor = GTK_TEXT_CHILD_ANCHOR(current->data); - wids = gtk_text_child_anchor_get_widgets(anchor); - - g_object_set_data_full(G_OBJECT(anchor), "gtkimhtml_plaintext", purple_unescape_html(smiley->smile), g_free); - g_object_set_data_full(G_OBJECT(anchor), "gtkimhtml_htmltext", g_strdup(smiley->smile), g_free); - - if (smiley->imhtml) { - if (wids) { - GList *children = gtk_container_get_children(GTK_CONTAINER(wids->data)); - g_list_foreach(children, (GFunc)gtk_widget_destroy, NULL); - g_list_free(children); - gtk_container_add(GTK_CONTAINER(wids->data), icon); - } else - gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(smiley->imhtml), icon, anchor); - } - g_list_free(wids); - } - - } - - g_slist_free(smiley->anchors); - smiley->anchors = NULL; - - g_object_unref(G_OBJECT(loader)); - smiley->loader = NULL; -} - static gboolean add_custom_smiley_for_imhtml(GtkIMHtml *imhtml, const char *sml, const char *smile) { GtkIMHtmlSmiley *smiley; - GdkPixbufLoader *loader; smiley = gtk_imhtml_smiley_get(imhtml, sml, smile); if (smiley) { - if (!(smiley->flags & GTK_IMHTML_SMILEY_CUSTOM)) { return FALSE; } - - /* Close the old GdkPixbufAnimation, then create a new one for - * the smiley we are about to receive */ - g_object_unref(G_OBJECT(smiley->icon)); - - /* XXX: Is it necessary to _unref the loader first? */ - smiley->loader = gdk_pixbuf_loader_new(); - smiley->icon = NULL; - - g_signal_connect(smiley->loader, "area_prepared", G_CALLBACK(pidgin_conv_custom_smiley_allocated), smiley); - g_signal_connect(smiley->loader, "closed", G_CALLBACK(pidgin_conv_custom_smiley_closed), smiley); - + gtk_imhtml_smiley_reload(smiley); return TRUE; } - 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 opaque */ - smiley = g_new0(GtkIMHtmlSmiley, 1); - smiley->file = NULL; - smiley->smile = g_strdup(smile); - smiley->loader = loader; - smiley->flags = smiley->flags | GTK_IMHTML_SMILEY_CUSTOM; - - g_signal_connect(smiley->loader, "area_prepared", G_CALLBACK(pidgin_conv_custom_smiley_allocated), smiley); - g_signal_connect(smiley->loader, "closed", G_CALLBACK(pidgin_conv_custom_smiley_closed), smiley); - + smiley = gtk_imhtml_smiley_create(NULL, smile, FALSE, GTK_IMHTML_SMILEY_CUSTOM); gtk_imhtml_associate_smiley(imhtml, sml, smiley); + g_signal_connect_swapped(imhtml, "destroy", G_CALLBACK(gtk_imhtml_smiley_destroy), smiley); return TRUE; } diff -r 98167ea7c093 -r 019052a807a3 pidgin/gtkimhtml.c --- a/pidgin/gtkimhtml.c Fri Mar 14 23:41:03 2008 +0000 +++ b/pidgin/gtkimhtml.c Tue Mar 18 00:47:52 2008 +0000 @@ -5200,4 +5200,123 @@ gtk_imhtml_set_format_functions(imhtml, buttons); } - +/******* + * GtkIMHtmlSmiley functions + *******/ +static void gtk_custom_smiley_allocated(GdkPixbufLoader *loader, gpointer user_data) +{ + GtkIMHtmlSmiley *smiley; + + smiley = (GtkIMHtmlSmiley *)user_data; + smiley->icon = gdk_pixbuf_loader_get_animation(loader); + + if (smiley->icon) + g_object_ref(G_OBJECT(smiley->icon)); +#ifdef DEBUG_CUSTOM_SMILEY + purple_debug_info("custom-smiley", "gtk_custom_smiley_allocated(): got GdkPixbufAnimation %p for smiley '%s'\n", smiley->icon, smiley->smile); +#endif +} + +static void gtk_custom_smiley_closed(GdkPixbufLoader *loader, gpointer user_data) +{ + GtkIMHtmlSmiley *smiley; + GtkWidget *icon = NULL; + GtkTextChildAnchor *anchor = NULL; + GSList *current = NULL; + + smiley = (GtkIMHtmlSmiley *)user_data; + if (!smiley->imhtml) { +#ifdef DEBUG_CUSTOM_SMILEY + purple_debug_error("custom-smiley", "gtk_custom_smiley_closed(): orphan smiley found: %p\n", smiley); +#endif + g_object_unref(G_OBJECT(loader)); + smiley->loader = NULL; + return; + } + + for (current = smiley->anchors; current; current = g_slist_next(current)) { + + icon = gtk_image_new_from_animation(smiley->icon); + +#ifdef DEBUG_CUSTOM_SMILEY + purple_debug_info("custom-smiley", "gtk_custom_smiley_closed(): got GtkImage %p from GtkPixbufAnimation %p for smiley '%s'\n", + icon, smiley->icon, smiley->smile); +#endif + if (icon) { + GList *wids; + gtk_widget_show(icon); + + anchor = GTK_TEXT_CHILD_ANCHOR(current->data); + wids = gtk_text_child_anchor_get_widgets(anchor); + + g_object_set_data_full(G_OBJECT(anchor), "gtkimhtml_plaintext", purple_unescape_html(smiley->smile), g_free); + g_object_set_data_full(G_OBJECT(anchor), "gtkimhtml_htmltext", g_strdup(smiley->smile), g_free); + + if (smiley->imhtml) { + if (wids) { + GList *children = gtk_container_get_children(GTK_CONTAINER(wids->data)); + g_list_foreach(children, (GFunc)gtk_widget_destroy, NULL); + g_list_free(children); + gtk_container_add(GTK_CONTAINER(wids->data), icon); + } else + gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(smiley->imhtml), icon, anchor); + } + g_list_free(wids); + } + + } + + g_slist_free(smiley->anchors); + smiley->anchors = NULL; + + g_object_unref(G_OBJECT(loader)); + smiley->loader = NULL; +} + +void +gtk_imhtml_smiley_reload(GtkIMHtmlSmiley *smiley) +{ + if (smiley->icon) + g_object_unref(smiley->icon); + if (smiley->loader) + g_object_unref(smiley->loader); /* XXX: does this crash? */ + + smiley->icon = NULL; + smiley->loader = NULL; + + if (smiley->file) { + /* We do not use the pixbuf loader for a smiley that can be loaded + * from a file. (e.g., local custom smileys) + */ + return; + } + + smiley->loader = gdk_pixbuf_loader_new(); + + g_signal_connect(smiley->loader, "area_prepared", G_CALLBACK(gtk_custom_smiley_allocated), smiley); + g_signal_connect(smiley->loader, "closed", G_CALLBACK(gtk_custom_smiley_closed), smiley); +} + +GtkIMHtmlSmiley *gtk_imhtml_smiley_create(const char *file, const char *shortcut, gboolean hide, + GtkIMHtmlSmileyFlags flags) +{ + GtkIMHtmlSmiley *smiley = g_new0(GtkIMHtmlSmiley, 1); + smiley->file = g_strdup(file); + smiley->smile = g_strdup(shortcut); + smiley->hidden = hide; + smiley->flags = flags; + gtk_imhtml_smiley_reload(smiley); + return smiley; +} + +void gtk_imhtml_smiley_destroy(GtkIMHtmlSmiley *smiley) +{ + g_free(smiley->smile); + g_free(smiley->file); + if (smiley->icon) + g_object_unref(smiley->icon); + if (smiley->loader) + g_object_unref(smiley->loader); + g_free(smiley); +} + diff -r 98167ea7c093 -r 019052a807a3 pidgin/gtkimhtml.h --- a/pidgin/gtkimhtml.h Fri Mar 14 23:41:03 2008 +0000 +++ b/pidgin/gtkimhtml.h Tue Mar 18 00:47:52 2008 +0000 @@ -852,6 +852,12 @@ */ void gtk_imhtml_setup_entry(GtkIMHtml *imhtml, PurpleConnectionFlags flags); +GtkIMHtmlSmiley *gtk_imhtml_smiley_create(const char *file, const char *shortcut, gboolean hide, + GtkIMHtmlSmileyFlags flags); + +void gtk_imhtml_smiley_reload(GtkIMHtmlSmiley *smiley); + +void gtk_imhtml_smiley_destroy(GtkIMHtmlSmiley *smiley); /*@}*/ #ifdef __cplusplus diff -r 98167ea7c093 -r 019052a807a3 pidgin/gtksmiley.c --- a/pidgin/gtksmiley.c Fri Mar 14 23:41:03 2008 +0000 +++ b/pidgin/gtksmiley.c Tue Mar 18 00:47:52 2008 +0000 @@ -91,11 +91,9 @@ filename = g_build_filename(purple_smileys_get_storing_dir(),file, NULL); - gtksmiley = g_new0(GtkIMHtmlSmiley,1); - gtksmiley->smile = g_strdup(purple_smiley_get_shortcut(smiley)); - gtksmiley->hidden = FALSE; - gtksmiley->file = filename; - gtksmiley->flags = GTK_IMHTML_SMILEY_CUSTOM; + gtksmiley = gtk_imhtml_smiley_create(filename, purple_smiley_get_shortcut(smiley), + FALSE, GTK_IMHTML_SMILEY_CUSTOM); + g_free(filename); return gtksmiley; } @@ -108,14 +106,6 @@ add_gtkimhtml_to_list(gtksmiley); } -static void destroy_gtksmiley(GtkIMHtmlSmiley *gtksmiley) -{ - purple_debug_info("gtksmiley", "destroying %s\n", gtksmiley->smile); - g_free(gtksmiley->smile); - g_free(gtksmiley->file); - g_free(gtksmiley); -} - void pidgin_smiley_del_from_list(PurpleSmiley *smiley) { GSList *list = NULL; @@ -132,7 +122,7 @@ if (strcmp(gtksmiley->smile, purple_smiley_get_shortcut(smiley))) continue; - destroy_gtksmiley(gtksmiley); + gtk_imhtml_smiley_destroy(gtksmiley); break; } @@ -169,7 +159,7 @@ for (; list; list = g_slist_delete_link(list, list)) { gtksmiley = (GtkIMHtmlSmiley*)list->data; - destroy_gtksmiley(gtksmiley); + gtk_imhtml_smiley_destroy(gtksmiley); } gtk_smileys = NULL; diff -r 98167ea7c093 -r 019052a807a3 pidgin/gtkthemes.c --- a/pidgin/gtkthemes.c Fri Mar 14 23:41:03 2008 +0000 +++ b/pidgin/gtkthemes.c Tue Mar 18 00:47:52 2008 +0000 @@ -135,7 +135,7 @@ gtk_imhtml_associate_smiley(GTK_IMHTML(imhtml), sml, icons->data); icons = icons->next; } - + if (custom == TRUE) { icons = pidgin_smileys_get_all(); @@ -295,7 +295,6 @@ } else if (load && list) { gboolean hidden = FALSE; char *sfile = NULL; - gboolean have_used_sfile = FALSE; if (*i == '!' && *(i + 1) == ' ') { hidden = TRUE; @@ -309,17 +308,12 @@ i++; l[li++] = *(i++); } + l[li] = 0; if (!sfile) { - l[li] = 0; sfile = g_build_filename(dirname, l, NULL); } else { - GtkIMHtmlSmiley *smiley = g_new0(GtkIMHtmlSmiley, 1); - l[li] = 0; - smiley->file = sfile; - smiley->smile = g_strdup(l); - smiley->hidden = hidden; + GtkIMHtmlSmiley *smiley = gtk_imhtml_smiley_create(sfile, l, hidden, 0); list->smileys = g_slist_prepend(list->smileys, smiley); - have_used_sfile = TRUE; } while (isspace(*i)) i++; @@ -327,8 +321,7 @@ } - if (!have_used_sfile) - g_free(sfile); + g_free(sfile); } }