[clutter/wip/actor-content: 7/33] image: Implement asynchronous loading
- From: Emmanuele Bassi <ebassi src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [clutter/wip/actor-content: 7/33] image: Implement asynchronous loading
- Date: Wed, 18 May 2011 11:11:00 +0000 (UTC)
commit 1524e317e463c1657a911137a75c59c431de8c41
Author: Emmanuele Bassi <ebassi linux intel com>
Date: Tue Dec 7 14:41:09 2010 +0000
image: Implement asynchronous loading
We use a GIO-style API to fit in with the rest of the platform.
clutter/clutter-image.c | 204 +++++++++++++++++++++++++++++++++---
tests/conform/test-conform-main.c | 1 +
tests/conform/test-image.c | 54 ++++++++++-
3 files changed, 241 insertions(+), 18 deletions(-)
---
diff --git a/clutter/clutter-image.c b/clutter/clutter-image.c
index 7ca97ed..ed6ab66 100644
--- a/clutter/clutter-image.c
+++ b/clutter/clutter-image.c
@@ -13,8 +13,6 @@
struct _ClutterImagePrivate
{
- ClutterImageLoader *loader;
-
gint image_width;
gint image_height;
@@ -226,6 +224,7 @@ clutter_image_load (ClutterImage *image,
gint *height,
GError **error)
{
+ ClutterImageLoader *loader;
ClutterImagePrivate *priv;
GFileInputStream *stream;
CoglHandle texture;
@@ -238,21 +237,15 @@ clutter_image_load (ClutterImage *image,
priv = image->priv;
- if (priv->loader == NULL)
- {
- priv->loader = _clutter_image_loader_new ();
- if (priv->loader == NULL)
- return FALSE;
-
- CLUTTER_NOTE (MISC, "Image loader type: %s",
- G_OBJECT_TYPE_NAME (priv->loader));
- }
+ loader = _clutter_image_loader_new ();
+ if (loader == NULL)
+ return FALSE;
stream = g_file_read (gfile, cancellable, error);
if (stream == NULL)
return FALSE;
- res = _clutter_image_loader_load_stream (priv->loader,
+ res = _clutter_image_loader_load_stream (loader,
G_INPUT_STREAM (stream),
cancellable,
error);
@@ -262,11 +255,11 @@ clutter_image_load (ClutterImage *image,
return FALSE;
}
- _clutter_image_loader_get_image_size (priv->loader,
+ _clutter_image_loader_get_image_size (loader,
&priv->image_width,
&priv->image_height);
- texture = _clutter_image_loader_get_texture_handle (priv->loader);
+ texture = _clutter_image_loader_get_texture_handle (loader);
if (texture == COGL_INVALID_HANDLE)
{
g_object_unref (stream);
@@ -285,14 +278,125 @@ clutter_image_load (ClutterImage *image,
if (height)
*height = priv->image_height;
- g_object_unref (priv->loader);
- priv->loader = NULL;
-
+ g_object_unref (loader);
g_object_unref (stream);
return TRUE;
}
+typedef struct {
+ ClutterImageLoader *loader;
+ ClutterImage *image;
+ GAsyncReadyCallback callback;
+ gpointer user_data;
+ GInputStream *stream;
+ GError *error;
+ GCancellable *cancellable;
+} AsyncReadClosure;
+
+static void
+async_read_closure_free (gpointer data)
+{
+ if (data != NULL)
+ {
+ AsyncReadClosure *closure = data;
+
+ if (closure->loader != NULL)
+ g_object_unref (closure->loader);
+
+ if (closure->image != NULL)
+ g_object_unref (closure->image);
+
+ if (closure->stream != NULL)
+ g_object_unref (closure->stream);
+
+ if (closure->cancellable != NULL)
+ g_object_unref (closure->cancellable);
+
+ if (closure->error != NULL)
+ g_error_free (closure->error);
+
+ g_free (data);
+ }
+}
+
+static void
+async_load_complete (GObject *gobject,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ AsyncReadClosure *closure = user_data;
+ GSimpleAsyncResult *res;
+ GError *error = NULL;
+
+ CLUTTER_NOTE (MISC, "Async loading finished");
+ _clutter_image_loader_load_stream_finish (closure->loader,
+ result,
+ &error);
+ if (error)
+ closure->error = error;
+
+ res = g_simple_async_result_new (G_OBJECT (closure->image),
+ closure->callback,
+ closure->user_data,
+ clutter_image_load_async);
+
+ g_simple_async_result_set_op_res_gpointer (res,
+ closure,
+ async_read_closure_free);
+
+ g_simple_async_result_complete (res);
+ g_object_unref (res);
+}
+
+static void
+async_read_complete (GObject *gobject,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ AsyncReadClosure *closure = user_data;
+ GFileInputStream *stream;
+ GError *error = NULL;
+
+ stream = g_file_read_finish (G_FILE (gobject), result, &error);
+ if (stream == NULL)
+ {
+ GSimpleAsyncResult *res =
+ g_simple_async_result_new (G_OBJECT (closure->image),
+ closure->callback,
+ closure->user_data,
+ clutter_image_load_async);
+
+ if (error)
+ closure->error = error;
+
+ g_simple_async_result_set_op_res_gpointer (res,
+ closure,
+ async_read_closure_free);
+ g_simple_async_result_complete (res);
+ g_object_unref (res);
+ return;
+ }
+
+ if (g_cancellable_is_cancelled (closure->cancellable))
+ {
+ CLUTTER_NOTE (MISC, "Async image loading cancelled");
+ async_read_closure_free (closure);
+ return;
+ }
+
+ closure->stream = G_INPUT_STREAM (stream);
+ g_object_ref (closure->stream);
+
+ CLUTTER_NOTE (MISC, "Loading stream with '%s'",
+ G_OBJECT_TYPE_NAME (closure->loader));
+ _clutter_image_loader_load_stream_async (closure->loader,
+ closure->stream,
+ closure->cancellable,
+ async_load_complete,
+ closure);
+}
+
void
clutter_image_load_async (ClutterImage *image,
GFile *gfile,
@@ -300,10 +404,30 @@ clutter_image_load_async (ClutterImage *image,
GAsyncReadyCallback callback,
gpointer user_data)
{
+ AsyncReadClosure *closure;
+ ClutterImageLoader *loader;
+
g_return_if_fail (CLUTTER_IS_IMAGE (image));
g_return_if_fail (G_IS_FILE (gfile));
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
g_return_if_fail (callback != NULL);
+
+ loader = _clutter_image_loader_new ();
+ if (loader == NULL)
+ return;
+
+ closure = g_new0 (AsyncReadClosure, 1);
+ closure->loader = loader;
+ closure->image = g_object_ref (image);
+ closure->cancellable = (cancellable != NULL)
+ ? g_object_ref (cancellable)
+ : NULL;
+ closure->callback = callback;
+ closure->user_data = user_data;
+
+ g_file_read_async (gfile, G_PRIORITY_DEFAULT, cancellable,
+ async_read_complete,
+ closure);
}
gboolean
@@ -313,9 +437,55 @@ clutter_image_load_finish (ClutterImage *image,
gint *height,
GError **error)
{
+ AsyncReadClosure *closure;
+ GSimpleAsyncResult *simple;
+ ClutterImagePrivate *priv;
+ CoglHandle texture;
+
g_return_val_if_fail (CLUTTER_IS_IMAGE (image), FALSE);
g_return_val_if_fail (G_IS_ASYNC_RESULT (res), FALSE);
+ simple = G_SIMPLE_ASYNC_RESULT (res);
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == clutter_image_load_async);
+
+ closure = g_simple_async_result_get_op_res_gpointer (simple);
+ if (closure->error != NULL)
+ {
+ if (width)
+ *width = 0;
+
+ if (height)
+ *height = 0;
+
+ g_propagate_error (error, closure->error);
+ closure->error = NULL;
+
+ return FALSE;
+ }
+
+ priv = image->priv;
+
+ _clutter_image_loader_get_image_size (closure->loader,
+ &priv->image_width,
+ &priv->image_height);
+
+ texture = _clutter_image_loader_get_texture_handle (closure->loader);
+ cogl_material_set_layer (priv->material, 0, texture);
+
+ g_signal_emit (image, image_signals[SIZE_CHANGED], 0,
+ priv->image_width,
+ priv->image_height);
+
+ if (width)
+ *width = priv->image_width;
+
+ if (height)
+ *height = priv->image_height;
+
return TRUE;
}
diff --git a/tests/conform/test-conform-main.c b/tests/conform/test-conform-main.c
index 19c55c4..a6f44d6 100644
--- a/tests/conform/test-conform-main.c
+++ b/tests/conform/test-conform-main.c
@@ -211,6 +211,7 @@ main (int argc, char **argv)
TEST_CONFORM_SIMPLE ("/behaviours", test_behaviours);
TEST_CONFORM_SIMPLE ("/image", image_sync_loading);
+ TEST_CONFORM_SIMPLE ("/image", image_async_loading);
TEST_CONFORM_SIMPLE ("/cogl", test_cogl_object);
TEST_CONFORM_SIMPLE ("/cogl", test_cogl_fixed);
diff --git a/tests/conform/test-image.c b/tests/conform/test-image.c
index efccd24..5a89b6c 100644
--- a/tests/conform/test-image.c
+++ b/tests/conform/test-image.c
@@ -27,8 +27,60 @@ image_sync_loading (void)
g_assert (error == NULL);
g_assert (res);
- g_assert (width > 0 && height > 0);
+ g_assert_cmpint (width, >, 0);
+ g_assert_cmpint (height, >, 0);
g_object_unref (gfile);
g_object_unref (image);
}
+
+static void
+async_load_done_cb (GObject *gobject,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GMainLoop *main_loop = user_data;
+ GError *error = NULL;
+ gint width, height;
+ gboolean res;
+
+ width = height = 0;
+ res = clutter_image_load_finish (CLUTTER_IMAGE (gobject), result,
+ &width,
+ &height,
+ &error);
+
+ if (g_test_verbose () && error != NULL)
+ g_print ("Unexpected error: %s\n", error->message);
+
+ g_assert (res);
+ g_assert (error == NULL);
+ g_assert_cmpint (width, >, 0);
+ g_assert_cmpint (height, >, 0);
+
+ g_main_loop_quit (main_loop);
+}
+
+void
+image_async_loading (void)
+{
+ ClutterImage *image = clutter_image_new ();
+ GMainLoop *main_loop;
+ GFile *gfile;
+
+ g_assert (CLUTTER_IS_IMAGE (image));
+
+ gfile = g_file_new_for_path (TESTS_DATADIR "/redhand.png");
+
+ main_loop = g_main_loop_new (NULL, FALSE);
+
+ clutter_image_load_async (image, gfile, NULL,
+ async_load_done_cb,
+ main_loop);
+
+ g_main_loop_run (main_loop);
+
+ g_main_loop_unref (main_loop);
+ g_object_unref (gfile);
+ g_object_unref (image);
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]