~ubuntu-branches/ubuntu/lucid/giggle/lucid

« back to all changes in this revision

Viewing changes to src/giggle-avatar-cache.c

  • Committer: Bazaar Package Importer
  • Author(s): Andrea Corradi
  • Date: 2009-03-30 19:41:43 UTC
  • mfrom: (3.1.3 squeeze)
  • Revision ID: james.westby@ubuntu.com-20090330194143-nyr9ze1xola1shm5
Tags: 0.4.91-1
* New upstream release (Closes:  #519014)
* Use Standards-Version 3.8.1
* Add new Build-Depends
* Update Homepage and watch file
* Update debian/copyright
* Remove patch
* Update path in debian/rules
* Remove defs option from LDFLAGS

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 
2
/*
 
3
 * Copyright (C) 2009 Mathias Hasselmann
 
4
 *
 
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.
 
9
 *
 
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.
 
14
 *
 
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.
 
19
 */
 
20
 
 
21
#include "config.h"
 
22
#include "giggle-avatar-cache.h"
 
23
 
 
24
#include <glib.h>
 
25
#include <gio/gio.h>
 
26
#include <string.h>
 
27
 
 
28
#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GIGGLE_TYPE_AVATAR_CACHE, GiggleAvatarCachePriv))
 
29
 
 
30
typedef struct {
 
31
        char               *uri;
 
32
        GiggleAvatarCache  *cache;
 
33
        GCancellable       *cancellable;
 
34
        char                buffer[8192];
 
35
        GdkPixbufLoader    *pixbuf_loader;
 
36
        GdkPixbuf          *pixbuf;
 
37
        GSimpleAsyncResult *result;
 
38
} GiggleAvatarCacheLoader;
 
39
 
 
40
typedef struct {
 
41
        GChecksum  *checksum;
 
42
        GHashTable *pixbuf_table;
 
43
        GList      *active_loaders;
 
44
} GiggleAvatarCachePriv;
 
45
 
 
46
G_DEFINE_TYPE (GiggleAvatarCache, giggle_avatar_cache, G_TYPE_OBJECT)
 
47
 
 
48
static void
 
49
avatar_cache_loader_finish (GiggleAvatarCacheLoader *loader,
 
50
                            GError                  *error)
 
51
{
 
52
        GiggleAvatarCachePriv *priv;
 
53
 
 
54
        if (loader->cache) {
 
55
                priv = GET_PRIV (loader->cache);
 
56
 
 
57
                g_object_remove_weak_pointer
 
58
                        (G_OBJECT (loader->cache),
 
59
                         (gpointer) &loader->cache);
 
60
        }
 
61
 
 
62
        if (loader->cancellable) {
 
63
                g_cancellable_cancel (loader->cancellable);
 
64
                g_object_unref (loader->cancellable);
 
65
        }
 
66
 
 
67
        if (loader->pixbuf_loader) {
 
68
                gdk_pixbuf_loader_close (loader->pixbuf_loader, NULL);
 
69
                g_object_unref (loader->pixbuf_loader);
 
70
        }
 
71
 
 
72
        if (loader->pixbuf) {
 
73
                g_simple_async_result_set_op_res_gpointer
 
74
                        (loader->result, g_object_ref (loader->pixbuf),
 
75
                         g_object_unref);
 
76
        } else {
 
77
                g_simple_async_result_set_from_error (loader->result, error);
 
78
                g_error_free (error);
 
79
        }
 
80
 
 
81
        g_simple_async_result_complete_in_idle (loader->result);
 
82
        g_object_unref (loader->result);
 
83
 
 
84
        g_slice_free (GiggleAvatarCacheLoader, loader);
 
85
}
 
86
 
 
87
static void
 
88
giggle_avatar_cache_init (GiggleAvatarCache *cache)
 
89
{
 
90
}
 
91
 
 
92
static void
 
93
avatar_cache_insert (GiggleAvatarCache *cache,
 
94
                     const char        *uri,
 
95
                     GdkPixbuf         *pixbuf)
 
96
{
 
97
        GiggleAvatarCachePriv *priv = GET_PRIV (cache);
 
98
 
 
99
        if (!priv->pixbuf_table) {
 
100
                priv->pixbuf_table = g_hash_table_new_full
 
101
                        (g_str_hash, g_str_equal, g_free,
 
102
                         g_object_unref);
 
103
        }
 
104
 
 
105
        g_hash_table_insert
 
106
                (priv->pixbuf_table, g_strdup (uri),
 
107
                 g_object_ref (pixbuf));
 
108
}
 
109
 
 
110
static void
 
111
avatar_cache_close_cb (GObject      *object,
 
112
                       GAsyncResult *result,
 
113
                       gpointer      user_data)
 
114
{
 
115
        GiggleAvatarCacheLoader *loader = user_data;
 
116
        GInputStream            *stream = G_INPUT_STREAM (object);
 
117
        GError                  *error = NULL;
 
118
 
 
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;
 
125
        }
 
126
 
 
127
        if (error && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
 
128
                g_warning ("%s: %s", G_STRFUNC, error->message);
 
129
 
 
130
        avatar_cache_loader_finish (loader, error);
 
131
}
 
132
 
 
133
static void
 
134
avatar_cache_read_cb (GObject      *object,
 
135
                      GAsyncResult *result,
 
136
                      gpointer      user_data)
 
137
{
 
138
        GiggleAvatarCacheLoader *loader = user_data;
 
139
        GInputStream            *stream = G_INPUT_STREAM (object);
 
140
        GError                  *error = NULL;
 
141
        gssize                   len;
 
142
 
 
143
        len = g_input_stream_read_finish (stream, result, &error);
 
144
 
 
145
        if (len > 0) {
 
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);
 
152
                } else {
 
153
                        len = -2;
 
154
                }
 
155
        }
 
156
 
 
157
        if (0 >= len) {
 
158
                g_input_stream_close_async
 
159
                        (stream, G_PRIORITY_DEFAULT, loader->cancellable,
 
160
                         avatar_cache_close_cb, loader);
 
161
        }
 
162
 
 
163
        if (error) {
 
164
                if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
 
165
                        g_warning ("%s: %s", G_STRFUNC, error->message);
 
166
 
 
167
                g_error_free (error);
 
168
        }
 
169
}
 
170
 
 
171
static void
 
172
avatar_cache_open_cb (GObject      *object,
 
173
                      GAsyncResult *result,
 
174
                      gpointer      user_data)
 
175
{
 
176
        GiggleAvatarCacheLoader *loader = user_data;
 
177
        GError                  *error = NULL;
 
178
        GFileInputStream        *stream;
 
179
 
 
180
        stream = g_file_read_finish (G_FILE (object), result, &error);
 
181
 
 
182
        if (stream) {
 
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);
 
188
        } else {
 
189
                if (error && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
 
190
                        g_warning ("%s: %s", G_STRFUNC, error->message);
 
191
 
 
192
                avatar_cache_loader_finish (loader, error);
 
193
        }
 
194
}
 
195
 
 
196
static void
 
197
avatar_cache_finalize (GObject *object)
 
198
{
 
199
        GiggleAvatarCachePriv   *priv = GET_PRIV (object);
 
200
        GiggleAvatarCacheLoader *loader;
 
201
        GList                   *l;
 
202
 
 
203
        if (priv->pixbuf_table)
 
204
                g_hash_table_unref (priv->pixbuf_table);
 
205
        if (priv->checksum)
 
206
                g_checksum_free (priv->checksum);
 
207
 
 
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);
 
211
        }
 
212
 
 
213
        G_OBJECT_CLASS (giggle_avatar_cache_parent_class)->finalize (object);
 
214
}
 
215
 
 
216
static void
 
217
giggle_avatar_cache_class_init (GiggleAvatarCacheClass *class)
 
218
{
 
219
        GObjectClass *object_class = G_OBJECT_CLASS (class);
 
220
 
 
221
        object_class->finalize     = avatar_cache_finalize;
 
222
 
 
223
        g_type_class_add_private (class, sizeof (GiggleAvatarCachePriv));
 
224
}
 
225
 
 
226
GiggleAvatarCache *
 
227
giggle_avatar_cache_new (void)
 
228
{
 
229
        return g_object_new (GIGGLE_TYPE_AVATAR_CACHE, NULL);
 
230
}
 
231
 
 
232
void
 
233
giggle_avatar_cache_load_uri_async (GiggleAvatarCache   *cache,
 
234
                                    const char          *uri,
 
235
                                    int                  io_priority,
 
236
                                    GCancellable        *cancellable,
 
237
                                    GAsyncReadyCallback  callback,
 
238
                                    gpointer             user_data)
 
239
{
 
240
        GiggleAvatarCachePriv   *priv;
 
241
        GdkPixbuf               *pixbuf = NULL;
 
242
        GSimpleAsyncResult      *result;
 
243
        GiggleAvatarCacheLoader *loader;
 
244
        GFile                   *file;
 
245
 
 
246
        g_return_if_fail (GIGGLE_IS_AVATAR_CACHE (cache));
 
247
        g_return_if_fail (NULL != callback);
 
248
        g_return_if_fail (NULL != uri);
 
249
 
 
250
        priv = GET_PRIV (cache);
 
251
 
 
252
        result = g_simple_async_result_new
 
253
                (G_OBJECT (cache), callback, user_data,
 
254
                 giggle_avatar_cache_load_uri_async);
 
255
 
 
256
        if (priv->pixbuf_table)
 
257
                pixbuf = g_hash_table_lookup (priv->pixbuf_table, uri);
 
258
 
 
259
        if (pixbuf) {
 
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);
 
263
        } else {
 
264
                if (cancellable) {
 
265
                        g_object_ref (cancellable);
 
266
                } else {
 
267
                        cancellable = g_cancellable_new ();
 
268
                }
 
269
 
 
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;
 
276
 
 
277
                g_object_add_weak_pointer
 
278
                        (G_OBJECT (loader->cache),
 
279
                         (gpointer) &loader->cache);
 
280
 
 
281
                file = g_file_new_for_uri (uri);
 
282
 
 
283
                g_file_read_async
 
284
                        (file, G_PRIORITY_DEFAULT, loader->cancellable,
 
285
                         avatar_cache_open_cb, loader);
 
286
 
 
287
                g_object_unref (file);
 
288
        }
 
289
 
 
290
        g_object_unref (result);
 
291
}
 
292
 
 
293
GdkPixbuf *
 
294
giggle_avatar_cache_load_finish (GiggleAvatarCache  *cache,
 
295
                                 GAsyncResult       *result,
 
296
                                 GError            **error)
 
297
{
 
298
        GSimpleAsyncResult *simple;
 
299
        gpointer            source_tag;
 
300
 
 
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);
 
303
 
 
304
        simple = G_SIMPLE_ASYNC_RESULT (result);
 
305
        source_tag = g_simple_async_result_get_source_tag (simple);
 
306
 
 
307
        g_return_val_if_fail (source_tag == giggle_avatar_cache_load_uri_async, NULL);
 
308
 
 
309
        if (g_simple_async_result_propagate_error (simple, error))
 
310
                return NULL;
 
311
 
 
312
        return g_simple_async_result_get_op_res_gpointer (simple);
 
313
}
 
314
 
 
315
char *
 
316
giggle_avatar_cache_get_gravatar_uri (GiggleAvatarCache   *cache,
 
317
                                      const char          *gravatar_id,
 
318
                                      unsigned             avatar_size)
 
319
{
 
320
        GiggleAvatarCachePriv *priv;
 
321
 
 
322
        g_return_val_if_fail (GIGGLE_IS_AVATAR_CACHE (cache), NULL);
 
323
        g_return_val_if_fail (NULL != gravatar_id, NULL);
 
324
 
 
325
        priv = GET_PRIV (cache);
 
326
 
 
327
        if (priv->checksum) {
 
328
                g_checksum_reset (priv->checksum);
 
329
        } else {
 
330
                priv->checksum = g_checksum_new (G_CHECKSUM_MD5);
 
331
        }
 
332
 
 
333
        g_checksum_update
 
334
                (priv->checksum, (gpointer) gravatar_id,
 
335
                 strlen (gravatar_id));
 
336
 
 
337
        return g_strdup_printf
 
338
                ("http://www.gravatar.com/avatar/%s?s=%d",
 
339
                 g_checksum_get_string (priv->checksum),
 
340
                 avatar_size);
 
341
}
 
342
 
 
343