/pidgin/main: fb32647ef2f3: PurpleImage: better reference manage...

Tomasz Wasilczyk twasilczyk at pidgin.im
Fri Apr 11 16:53:30 EDT 2014


Changeset: fb32647ef2f32a0bc4e9643b5883ed7937f44120
Author:	 Tomasz Wasilczyk <twasilczyk at pidgin.im>
Date:	 2014-04-11 22:53 +0200
Branch:	 default
URL: https://hg.pidgin.im/pidgin/main/rev/fb32647ef2f3

Description:

PurpleImage: better reference management

diffstat:

 libpurple/image-store.c    |  26 ++++++++++++++++++++++++++
 libpurple/image-store.h    |   3 +++
 libpurple/image.c          |   1 +
 pidgin/gtkwebview.c        |  46 ++++++++++++++++++++++++++++++----------------
 pidgin/gtkwebviewtoolbar.c |  21 +++++----------------
 5 files changed, 65 insertions(+), 32 deletions(-)

diffs (214 lines):

diff --git a/libpurple/image-store.c b/libpurple/image-store.c
--- a/libpurple/image-store.c
+++ b/libpurple/image-store.c
@@ -23,6 +23,7 @@
 
 #include "eventloop.h"
 #include "glibcompat.h"
+#include "util.h"
 
 #define TEMP_IMAGE_TIMEOUT 5
 
@@ -157,6 +158,31 @@ purple_image_store_get(guint id)
 	return g_hash_table_lookup(id_to_image, GINT_TO_POINTER(id));
 }
 
+PurpleImage *
+purple_image_store_get_from_uri(const gchar *uri)
+{
+	guint64 longid;
+	guint id;
+	gchar *endptr;
+
+	if (!purple_str_has_prefix(uri, PURPLE_IMAGE_STORE_PROTOCOL))
+		return NULL;
+
+	uri += sizeof(PURPLE_IMAGE_STORE_PROTOCOL) - 1;
+	if (uri[0] == '-')
+		return NULL;
+
+	longid = g_ascii_strtoull(uri, &endptr, 10);
+	if (endptr[0] != '\0')
+		return NULL;
+
+	id = longid;
+	if (id != longid)
+		return NULL;
+
+	return purple_image_store_get(id);
+}
+
 void
 _purple_image_store_init(void)
 {
diff --git a/libpurple/image-store.h b/libpurple/image-store.h
--- a/libpurple/image-store.h
+++ b/libpurple/image-store.h
@@ -53,6 +53,9 @@ purple_image_store_add_temporary(PurpleI
 PurpleImage *
 purple_image_store_get(guint id);
 
+PurpleImage *
+purple_image_store_get_from_uri(const gchar *uri);
+
 void
 _purple_image_store_init(void);
 
diff --git a/libpurple/image.c b/libpurple/image.c
--- a/libpurple/image.c
+++ b/libpurple/image.c
@@ -163,6 +163,7 @@ purple_image_new_from_file(const gchar *
 	g_return_val_if_fail(g_file_test(path, G_FILE_TEST_EXISTS), NULL);
 
 	img = g_object_new(PURPLE_TYPE_IMAGE, NULL);
+	purple_image_set_friendly_filename(img, path);
 	priv = PURPLE_IMAGE_GET_PRIVATE(img);
 	priv->path = g_strdup(path);
 
diff --git a/pidgin/gtkwebview.c b/pidgin/gtkwebview.c
--- a/pidgin/gtkwebview.c
+++ b/pidgin/gtkwebview.c
@@ -111,9 +111,6 @@ typedef struct _PidginWebViewPriv {
 	/* WebKit inspector */
 	WebKitWebView *inspector_view;
 	GtkWindow *inspector_win;
-
-	/* Resources cache */
-	GHashTable *loaded_images;
 } PidginWebViewPriv;
 
 /******************************************************************************
@@ -125,6 +122,14 @@ static WebKitWebViewClass *parent_class 
 static GRegex *smileys_re = NULL;
 static GRegex *empty_html_re = NULL;
 
+/* Resources cache.
+ *
+ * It's global, because gtkwebkit calls "resource-load-finished" only once
+ * for each static resource.
+ */
+static GHashTable *globally_loaded_images = NULL;
+guint globally_loaded_images_refcnt = 0;
+
 
 /******************************************************************************
  * Helpers
@@ -208,10 +213,9 @@ static void
 webview_resource_loaded(WebKitWebView *web_view, WebKitWebFrame *web_frame,
 	WebKitWebResource *web_resource, gpointer user_data)
 {
-	PidginWebViewPriv *priv = PIDGIN_WEBVIEW_GET_PRIVATE(web_view);
 	const gchar *uri;
 	GString *data;
-	PurpleImage *image;
+	PurpleImage *image = NULL;
 
 	if (!purple_str_has_caseprefix(
 		webkit_web_resource_get_mime_type(web_resource), "image/"))
@@ -220,20 +224,23 @@ webview_resource_loaded(WebKitWebView *w
 	}
 
 	uri = webkit_web_resource_get_uri(web_resource);
-	if (g_hash_table_lookup(priv->loaded_images, uri))
+	if (g_hash_table_lookup(globally_loaded_images, uri))
 		return;
 
 	data = webkit_web_resource_get_data(web_resource);
 	if (data->len == 0)
 		return;
 
-	/* TODO: we could avoid copying data, if uri is a
-	 * PURPLE_IMAGE_STORE_PROTOCOL */
-	image = purple_image_new_from_data(
-		g_memdup(data->str, data->len), data->len);
-	g_return_if_fail(image != NULL);
+	image = purple_image_store_get_from_uri(uri);
+	if (image) {
+		g_object_ref(image);
+	} else {
+		image = purple_image_new_from_data(
+			g_memdup(data->str, data->len), data->len);
+		g_return_if_fail(image != NULL);
+	}
 
-	g_hash_table_insert(priv->loaded_images, g_strdup(uri), image);
+	g_hash_table_insert(globally_loaded_images, g_strdup(uri), image);
 }
 
 static PurpleImage *
@@ -243,7 +250,7 @@ webview_resource_get_loaded(WebKitWebVie
 
 	g_return_val_if_fail(priv != NULL, NULL);
 
-	return g_hash_table_lookup(priv->loaded_images, uri);
+	return g_hash_table_lookup(globally_loaded_images, uri);
 }
 
 static void
@@ -1117,7 +1124,11 @@ pidgin_webview_finalize(GObject *webview
 	}
 	g_queue_free(priv->load_queue);
 
-	g_hash_table_destroy(priv->loaded_images);
+	if (--globally_loaded_images_refcnt == 0) {
+		g_assert(globally_loaded_images != NULL);
+		g_hash_table_destroy(globally_loaded_images);
+		globally_loaded_images = NULL;
+	}
 
 	G_OBJECT_CLASS(parent_class)->finalize(G_OBJECT(webview));
 }
@@ -1298,8 +1309,11 @@ pidgin_webview_init(PidginWebView *webvi
 	g_signal_connect(G_OBJECT(inspector), "show-window",
 		G_CALLBACK(webview_inspector_show), webview);
 
-	priv->loaded_images = g_hash_table_new_full(g_str_hash, g_str_equal,
-		g_free, g_object_unref);
+	if (globally_loaded_images_refcnt++ == 0) {
+		g_assert(globally_loaded_images == NULL);
+		globally_loaded_images = g_hash_table_new_full(g_str_hash,
+			g_str_equal, g_free, g_object_unref);
+	}
 }
 
 GType
diff --git a/pidgin/gtkwebviewtoolbar.c b/pidgin/gtkwebviewtoolbar.c
--- a/pidgin/gtkwebviewtoolbar.c
+++ b/pidgin/gtkwebviewtoolbar.c
@@ -608,10 +608,7 @@ static void
 do_insert_image_cb(GtkWidget *widget, int response, PidginWebViewToolbar *toolbar)
 {
 	PidginWebViewToolbarPriv *priv = PIDGIN_WEBVIEWTOOLBAR_GET_PRIVATE(toolbar);
-	gchar *filename = NULL, *buf;
-	char *filedata;
-	size_t size;
-	GError *error = NULL;
+	gchar *filename = NULL;
 	PurpleImage *img;
 
 	if (response == GTK_RESPONSE_ACCEPT)
@@ -623,20 +620,12 @@ do_insert_image_cb(GtkWidget *widget, in
 	if (filename == NULL)
 		return;
 
-	if (!g_file_get_contents(filename, &filedata, &size, &error)) {
-		purple_notify_error(NULL, NULL, error->message, NULL, NULL);
-
-		g_error_free(error);
-		g_free(filename);
-
-		return;
-	}
-
-	img = purple_image_new_from_data(filedata, size);
-	purple_image_set_friendly_filename(img, filename);
+	img = purple_image_new_from_file(filename, TRUE);
 
 	if (!img) {
-		buf = g_strdup_printf(_("Failed to store image: %s\n"), filename);
+		gchar *buf = g_strdup_printf(_("Failed to store image: %s"),
+			filename);
+
 		purple_notify_error(NULL, NULL, buf, NULL, NULL);
 
 		g_free(buf);



More information about the Commits mailing list