diff options
Diffstat (limited to 'libempathy-gtk')
-rw-r--r-- | libempathy-gtk/empathy-ui-utils.c | 140 |
1 files changed, 101 insertions, 39 deletions
diff --git a/libempathy-gtk/empathy-ui-utils.c b/libempathy-gtk/empathy-ui-utils.c index 8ad7dfb4b..060e0aab5 100644 --- a/libempathy-gtk/empathy-ui-utils.c +++ b/libempathy-gtk/empathy-ui-utils.c @@ -526,13 +526,18 @@ typedef struct { GSimpleAsyncResult *result; guint width; guint height; + struct SizeData size_data; + GdkPixbufLoader *loader; + GCancellable *cancellable; + guint8 data[512]; } PixbufAvatarFromIndividualClosure; static PixbufAvatarFromIndividualClosure * pixbuf_avatar_from_individual_closure_new (FolksIndividual *individual, GSimpleAsyncResult *result, gint width, - gint height) + gint height, + GCancellable *cancellable) { PixbufAvatarFromIndividualClosure *closure; @@ -544,6 +549,7 @@ pixbuf_avatar_from_individual_closure_new (FolksIndividual *individual, closure->result = g_object_ref (result); closure->width = width; closure->height = height; + closure->cancellable = g_object_ref (cancellable); return closure; } @@ -552,65 +558,120 @@ static void pixbuf_avatar_from_individual_closure_free ( PixbufAvatarFromIndividualClosure *closure) { + g_object_unref (closure->cancellable); + tp_clear_object (&closure->loader); g_object_unref (closure->individual); g_object_unref (closure->result); g_free (closure); } static void -avatar_file_load_contents_cb (GObject *object, - GAsyncResult *result, - gpointer user_data) +avatar_icon_load_read_cb (GObject *object, + GAsyncResult *result, + gpointer user_data) { - GFile *file = G_FILE (object); + GInputStream *stream = G_INPUT_STREAM (object); PixbufAvatarFromIndividualClosure *closure = user_data; - char *data = NULL; - gsize data_size; - struct SizeData size_data; + gssize n_read; GError *error = NULL; - GdkPixbufLoader *loader = NULL; - if (!g_file_load_contents_finish (file, result, &data, &data_size, - NULL, &error)) { - DEBUG ("failed to load avatar from file: %s", - error->message); + /* Finish reading this chunk from the stream */ + n_read = g_input_stream_read_finish (stream, result, &error); + if (error != NULL) { + DEBUG ("Failed to finish read from pixbuf stream: %s", + error->message); g_simple_async_result_set_from_error (closure->result, error); - goto out; + goto out_close; } - size_data.width = closure->width; - size_data.height = closure->height; - size_data.preserve_aspect_ratio = TRUE; - - loader = gdk_pixbuf_loader_new (); - - g_signal_connect (loader, "size-prepared", - G_CALLBACK (pixbuf_from_avatar_size_prepared_cb), - &size_data); - - if (!gdk_pixbuf_loader_write (loader, (guchar *) data, data_size, - &error)) { + /* Write the chunk to the pixbuf loader */ + if (!gdk_pixbuf_loader_write (closure->loader, (guchar *) closure->data, + n_read, &error)) { DEBUG ("Failed to write to pixbuf loader: %s", error ? error->message : "No error given"); g_simple_async_result_set_from_error (closure->result, error); + goto out_close; + } + + if (n_read == 0) { + /* EOF? */ + if (!gdk_pixbuf_loader_close (closure->loader, &error)) { + DEBUG ("Failed to close pixbuf loader: %s", + error ? error->message : "No error given"); + g_simple_async_result_set_from_error (closure->result, error); + goto out; + } + + /* We're done. */ + g_simple_async_result_set_op_res_gpointer (closure->result, + avatar_pixbuf_from_loader (closure->loader), + g_object_unref); + goto out; + } else { + /* Loop round and read another chunk. */ + g_input_stream_read_async (stream, closure->data, + G_N_ELEMENTS (closure->data), + G_PRIORITY_DEFAULT, closure->cancellable, + avatar_icon_load_read_cb, closure); + + return; } - if (!gdk_pixbuf_loader_close (loader, &error)) { - DEBUG ("Failed to close pixbuf loader: %s", - error ? error->message : "No error given"); + +out_close: + /* We must close the pixbuf loader before unreffing it. */ + gdk_pixbuf_loader_close (closure->loader, NULL); + +out: + g_simple_async_result_complete (closure->result); + + g_clear_error (&error); + pixbuf_avatar_from_individual_closure_free (closure); +} + +static void +avatar_icon_load_cb (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + GLoadableIcon *icon = G_LOADABLE_ICON (object); + PixbufAvatarFromIndividualClosure *closure = user_data; + GInputStream *stream; + GError *error = NULL; + + stream = g_loadable_icon_load_finish (icon, result, NULL, &error); + if (error != NULL) { + DEBUG ("Failed to open avatar stream: %s", error->message); g_simple_async_result_set_from_error (closure->result, error); goto out; } - g_simple_async_result_set_op_res_gpointer (closure->result, - avatar_pixbuf_from_loader (loader), g_object_unref); + closure->size_data.width = closure->width; + closure->size_data.height = closure->height; + closure->size_data.preserve_aspect_ratio = TRUE; + + /* Load the data into a pixbuf loader in chunks. */ + closure->loader = gdk_pixbuf_loader_new (); + + g_signal_connect (closure->loader, "size-prepared", + G_CALLBACK (pixbuf_from_avatar_size_prepared_cb), + &(closure->size_data)); + + /* Begin to read the first chunk. */ + g_input_stream_read_async (stream, closure->data, + G_N_ELEMENTS (closure->data), + G_PRIORITY_DEFAULT, closure->cancellable, + avatar_icon_load_read_cb, closure); + + g_object_unref (stream); + + return; out: g_simple_async_result_complete (closure->result); g_clear_error (&error); - g_free (data); - tp_clear_object (&loader); + tp_clear_object (&stream); pixbuf_avatar_from_individual_closure_free (closure); } @@ -623,7 +684,7 @@ empathy_pixbuf_avatar_from_individual_scaled_async ( GAsyncReadyCallback callback, gpointer user_data) { - GFile *avatar_file; + GLoadableIcon *avatar_icon; GSimpleAsyncResult *result; PixbufAvatarFromIndividualClosure *closure; @@ -631,18 +692,19 @@ empathy_pixbuf_avatar_from_individual_scaled_async ( callback, user_data, empathy_pixbuf_avatar_from_individual_scaled_async); - avatar_file = + avatar_icon = folks_avatar_details_get_avatar (FOLKS_AVATAR_DETAILS (individual)); - if (avatar_file == NULL) + if (avatar_icon == NULL) goto out; closure = pixbuf_avatar_from_individual_closure_new (individual, result, - width, height); + width, height, + cancellable); if (closure == NULL) goto out; - g_file_load_contents_async (avatar_file, cancellable, - avatar_file_load_contents_cb, closure); + g_loadable_icon_load_async (avatar_icon, width, cancellable, + avatar_icon_load_cb, closure); g_object_unref (result); |