1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3
* Copyright (C) 2009 Mathias Hasselmann
5
* This program is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU General Public License as
7
* published by the Free Software Foundation; either version 2 of the
8
* License, or (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
* General Public License for more details.
15
* You should have received a copy of the GNU General Public
16
* License along with this program; if not, write to the
17
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18
* Boston, MA 02111-1307, USA.
22
#include "giggle-avatar-cache.h"
28
#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GIGGLE_TYPE_AVATAR_CACHE, GiggleAvatarCachePriv))
32
GiggleAvatarCache *cache;
33
GCancellable *cancellable;
35
GdkPixbufLoader *pixbuf_loader;
37
GSimpleAsyncResult *result;
38
} GiggleAvatarCacheLoader;
42
GHashTable *pixbuf_table;
43
GList *active_loaders;
44
} GiggleAvatarCachePriv;
46
G_DEFINE_TYPE (GiggleAvatarCache, giggle_avatar_cache, G_TYPE_OBJECT)
49
avatar_cache_loader_finish (GiggleAvatarCacheLoader *loader,
52
GiggleAvatarCachePriv *priv;
55
priv = GET_PRIV (loader->cache);
57
g_object_remove_weak_pointer
58
(G_OBJECT (loader->cache),
59
(gpointer) &loader->cache);
62
if (loader->cancellable) {
63
g_cancellable_cancel (loader->cancellable);
64
g_object_unref (loader->cancellable);
67
if (loader->pixbuf_loader) {
68
gdk_pixbuf_loader_close (loader->pixbuf_loader, NULL);
69
g_object_unref (loader->pixbuf_loader);
73
g_simple_async_result_set_op_res_gpointer
74
(loader->result, g_object_ref (loader->pixbuf),
77
g_simple_async_result_set_from_error (loader->result, error);
81
g_simple_async_result_complete_in_idle (loader->result);
82
g_object_unref (loader->result);
84
g_slice_free (GiggleAvatarCacheLoader, loader);
88
giggle_avatar_cache_init (GiggleAvatarCache *cache)
93
avatar_cache_insert (GiggleAvatarCache *cache,
97
GiggleAvatarCachePriv *priv = GET_PRIV (cache);
99
if (!priv->pixbuf_table) {
100
priv->pixbuf_table = g_hash_table_new_full
101
(g_str_hash, g_str_equal, g_free,
106
(priv->pixbuf_table, g_strdup (uri),
107
g_object_ref (pixbuf));
111
avatar_cache_close_cb (GObject *object,
112
GAsyncResult *result,
115
GiggleAvatarCacheLoader *loader = user_data;
116
GInputStream *stream = G_INPUT_STREAM (object);
117
GError *error = NULL;
119
if (g_input_stream_close_finish (stream, result, &error) &&
120
gdk_pixbuf_loader_close (loader->pixbuf_loader, &error)) {
121
loader->pixbuf = gdk_pixbuf_loader_get_pixbuf (loader->pixbuf_loader);
122
avatar_cache_insert (loader->cache, loader->uri, loader->pixbuf);
123
g_object_unref (loader->pixbuf_loader);
124
loader->pixbuf_loader = NULL;
127
if (error && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
128
g_warning ("%s: %s", G_STRFUNC, error->message);
130
avatar_cache_loader_finish (loader, error);
134
avatar_cache_read_cb (GObject *object,
135
GAsyncResult *result,
138
GiggleAvatarCacheLoader *loader = user_data;
139
GInputStream *stream = G_INPUT_STREAM (object);
140
GError *error = NULL;
143
len = g_input_stream_read_finish (stream, result, &error);
146
if (gdk_pixbuf_loader_write (loader->pixbuf_loader, (gpointer)
147
loader->buffer, len, &error)) {
148
g_input_stream_read_async
149
(stream, loader->buffer, sizeof loader->buffer,
150
G_PRIORITY_DEFAULT, loader->cancellable,
151
avatar_cache_read_cb, loader);
158
g_input_stream_close_async
159
(stream, G_PRIORITY_DEFAULT, loader->cancellable,
160
avatar_cache_close_cb, loader);
164
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
165
g_warning ("%s: %s", G_STRFUNC, error->message);
167
g_error_free (error);
172
avatar_cache_open_cb (GObject *object,
173
GAsyncResult *result,
176
GiggleAvatarCacheLoader *loader = user_data;
177
GError *error = NULL;
178
GFileInputStream *stream;
180
stream = g_file_read_finish (G_FILE (object), result, &error);
183
g_input_stream_read_async
184
(G_INPUT_STREAM (stream),
185
loader->buffer, sizeof loader->buffer,
186
G_PRIORITY_DEFAULT, loader->cancellable,
187
avatar_cache_read_cb, loader);
189
if (error && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
190
g_warning ("%s: %s", G_STRFUNC, error->message);
192
avatar_cache_loader_finish (loader, error);
197
avatar_cache_finalize (GObject *object)
199
GiggleAvatarCachePriv *priv = GET_PRIV (object);
200
GiggleAvatarCacheLoader *loader;
203
if (priv->pixbuf_table)
204
g_hash_table_unref (priv->pixbuf_table);
206
g_checksum_free (priv->checksum);
208
for (l = priv->active_loaders; l; l = g_list_delete_link (l, l)) {
209
loader = priv->active_loaders->data;
210
g_cancellable_cancel (loader->cancellable);
213
G_OBJECT_CLASS (giggle_avatar_cache_parent_class)->finalize (object);
217
giggle_avatar_cache_class_init (GiggleAvatarCacheClass *class)
219
GObjectClass *object_class = G_OBJECT_CLASS (class);
221
object_class->finalize = avatar_cache_finalize;
223
g_type_class_add_private (class, sizeof (GiggleAvatarCachePriv));
227
giggle_avatar_cache_new (void)
229
return g_object_new (GIGGLE_TYPE_AVATAR_CACHE, NULL);
233
giggle_avatar_cache_load_uri_async (GiggleAvatarCache *cache,
236
GCancellable *cancellable,
237
GAsyncReadyCallback callback,
240
GiggleAvatarCachePriv *priv;
241
GdkPixbuf *pixbuf = NULL;
242
GSimpleAsyncResult *result;
243
GiggleAvatarCacheLoader *loader;
246
g_return_if_fail (GIGGLE_IS_AVATAR_CACHE (cache));
247
g_return_if_fail (NULL != callback);
248
g_return_if_fail (NULL != uri);
250
priv = GET_PRIV (cache);
252
result = g_simple_async_result_new
253
(G_OBJECT (cache), callback, user_data,
254
giggle_avatar_cache_load_uri_async);
256
if (priv->pixbuf_table)
257
pixbuf = g_hash_table_lookup (priv->pixbuf_table, uri);
260
g_simple_async_result_set_op_res_gpointer
261
(result, g_object_ref (pixbuf), g_object_unref);
262
g_simple_async_result_complete_in_idle (result);
265
g_object_ref (cancellable);
267
cancellable = g_cancellable_new ();
270
loader = g_slice_new0 (GiggleAvatarCacheLoader);
271
loader->pixbuf_loader = gdk_pixbuf_loader_new ();
272
loader->result = g_object_ref (result);
273
loader->cancellable = cancellable;
274
loader->uri = g_strdup (uri);
275
loader->cache = cache;
277
g_object_add_weak_pointer
278
(G_OBJECT (loader->cache),
279
(gpointer) &loader->cache);
281
file = g_file_new_for_uri (uri);
284
(file, G_PRIORITY_DEFAULT, loader->cancellable,
285
avatar_cache_open_cb, loader);
287
g_object_unref (file);
290
g_object_unref (result);
294
giggle_avatar_cache_load_finish (GiggleAvatarCache *cache,
295
GAsyncResult *result,
298
GSimpleAsyncResult *simple;
301
g_return_val_if_fail (GIGGLE_IS_AVATAR_CACHE (cache), NULL);
302
g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), NULL);
304
simple = G_SIMPLE_ASYNC_RESULT (result);
305
source_tag = g_simple_async_result_get_source_tag (simple);
307
g_return_val_if_fail (source_tag == giggle_avatar_cache_load_uri_async, NULL);
309
if (g_simple_async_result_propagate_error (simple, error))
312
return g_simple_async_result_get_op_res_gpointer (simple);
316
giggle_avatar_cache_get_gravatar_uri (GiggleAvatarCache *cache,
317
const char *gravatar_id,
318
unsigned avatar_size)
320
GiggleAvatarCachePriv *priv;
322
g_return_val_if_fail (GIGGLE_IS_AVATAR_CACHE (cache), NULL);
323
g_return_val_if_fail (NULL != gravatar_id, NULL);
325
priv = GET_PRIV (cache);
327
if (priv->checksum) {
328
g_checksum_reset (priv->checksum);
330
priv->checksum = g_checksum_new (G_CHECKSUM_MD5);
334
(priv->checksum, (gpointer) gravatar_id,
335
strlen (gravatar_id));
337
return g_strdup_printf
338
("http://www.gravatar.com/avatar/%s?s=%d",
339
g_checksum_get_string (priv->checksum),