diff options
author | Carlos Garcia Campos <cgarcia@igalia.com> | 2012-09-04 20:48:26 +0800 |
---|---|---|
committer | Carlos Garcia Campos <carlosgc@gnome.org> | 2012-09-06 16:25:09 +0800 |
commit | b70fe20a489b0a89e4f8779551e87698434485a5 (patch) | |
tree | 08d63f5fce54bd741bea3279fab00ebd7ba65295 | |
parent | 8712d1d951319e69dabae819d80700023cd920b8 (diff) | |
download | gsoc2013-epiphany-b70fe20a489b0a89e4f8779551e87698434485a5.tar gsoc2013-epiphany-b70fe20a489b0a89e4f8779551e87698434485a5.tar.gz gsoc2013-epiphany-b70fe20a489b0a89e4f8779551e87698434485a5.tar.bz2 gsoc2013-epiphany-b70fe20a489b0a89e4f8779551e87698434485a5.tar.lz gsoc2013-epiphany-b70fe20a489b0a89e4f8779551e87698434485a5.tar.xz gsoc2013-epiphany-b70fe20a489b0a89e4f8779551e87698434485a5.tar.zst gsoc2013-epiphany-b70fe20a489b0a89e4f8779551e87698434485a5.zip |
ephy-snapshot-service: Split ephy_snapshot_service_get_snapshot_async()
ephy_snapshot_service_get_snapshot_async() receives an option web view
parameter, that it's only used in case the snapshot is not the in the
thumbnails cache. We can split the method into
ephy_snapshot_service_get_snapshot_async() to get a snapshot from a web
view and ephy_snapshot_service_get_snapshot_for_url_async() to get a
snapshot from the cache. The former uses the latter to try first if the
web view URI is in the cache.
Patch includes other cleanups and fixes:
- Add missing ephy_snapshot_service_save_snapshot_finish()
- Add EphySnapshotServiceError to handle errors
- Use GSimpleAsyncResult API instead of using GIOScheduler directly
- Use different async data structs for every async operation
https://bugzilla.gnome.org/show_bug.cgi?id=683327
-rw-r--r-- | lib/ephy-snapshot-service.c | 511 | ||||
-rw-r--r-- | lib/ephy-snapshot-service.h | 76 | ||||
-rw-r--r-- | lib/widgets/ephy-overview-store.c | 87 | ||||
-rw-r--r-- | tests/ephy-snapshot-service-test.c | 8 |
4 files changed, 443 insertions, 239 deletions
diff --git a/lib/ephy-snapshot-service.c b/lib/ephy-snapshot-service.c index 04b559035..d201a163f 100644 --- a/lib/ephy-snapshot-service.c +++ b/lib/ephy-snapshot-service.c @@ -40,34 +40,6 @@ struct _EphySnapshotServicePrivate G_DEFINE_TYPE (EphySnapshotService, ephy_snapshot_service, G_TYPE_OBJECT) -typedef struct { - WebKitWebView *webview; - char *url; - time_t mtime; - GdkPixbuf *snapshot; - GCancellable *cancellable; - GAsyncReadyCallback callback; - gpointer user_data; -} SnapshotOp; - -static gboolean ephy_snapshot_service_complete_async (SnapshotOp *op); -static gboolean ephy_snapshot_service_take_from_webview (SnapshotOp *op); - -static void -snapshot_op_free (SnapshotOp *op) -{ - g_free (op->url); - - if (op->cancellable) - g_object_unref (op->cancellable); - if (op->webview) - g_object_unref (op->webview); - if (op->snapshot) - g_object_unref (op->snapshot); - - g_slice_free (SnapshotOp, op); -} - /* GObject boilerplate methods. */ static void @@ -85,119 +57,147 @@ ephy_snapshot_service_init (EphySnapshotService *self) self->priv->factory = gnome_desktop_thumbnail_factory_new (GNOME_DESKTOP_THUMBNAIL_SIZE_LARGE); } -/* IO scheduler methods, used for IO. */ +typedef struct { + char *url; + time_t mtime; -static GdkPixbuf * -io_scheduler_get_cached_snapshot (EphySnapshotService *service, - char *url, time_t mtime) -{ GdkPixbuf *snapshot; - char *uri; +} SnapshotForURLAsyncData; - uri = gnome_desktop_thumbnail_factory_lookup (service->priv->factory, - url, mtime); - if (uri == NULL) - return NULL; +static SnapshotForURLAsyncData * +snapshot_for_url_async_data_new (const char *url, + time_t mtime) +{ + SnapshotForURLAsyncData *data; - snapshot = gdk_pixbuf_new_from_file (uri, NULL); - g_free (uri); + data = g_slice_new0 (SnapshotForURLAsyncData); + data->url = g_strdup (url); + data->mtime = mtime; - return snapshot; + return data; } -static gboolean -io_scheduler_try_cache_query (GIOSchedulerJob *job, - GCancellable *cancellable, - gpointer user_data) +static void +snapshot_for_url_async_data_free (SnapshotForURLAsyncData *data) { - SnapshotOp *op; - EphySnapshotService *service = ephy_snapshot_service_get_default (); - GSourceFunc func; + g_free (data->url); + g_clear_object (&data->snapshot); - op = (SnapshotOp*) user_data; + g_slice_free (SnapshotForURLAsyncData, data); +} - if (g_cancellable_is_cancelled (op->cancellable)) { - func = (GSourceFunc)ephy_snapshot_service_complete_async; - goto out; +static void +get_snapshot_for_url_thread (GSimpleAsyncResult *result, + EphySnapshotService *service, + GCancellable *cancellable) +{ + SnapshotForURLAsyncData *data; + gchar *uri; + GError *error = NULL; + + data = (SnapshotForURLAsyncData *)g_simple_async_result_get_op_res_gpointer (result); + + uri = gnome_desktop_thumbnail_factory_lookup (service->priv->factory, data->url, data->mtime); + if (uri == NULL) { + g_simple_async_result_set_error (result, + EPHY_SNAPSHOT_SERVICE_ERROR, + EPHY_SNAPSHOT_SERVICE_ERROR_NOT_FOUND, + "Snapshot for url \"%s\" not found in cache", data->url); + return; } - op->snapshot = io_scheduler_get_cached_snapshot (service, op->url, op->mtime); - - /* If we do have a cached snapshot or we don't have a webview - already, just complete early. */ - if (op->snapshot || !op->webview) - func = (GSourceFunc)ephy_snapshot_service_complete_async; - else - func = (GSourceFunc)ephy_snapshot_service_take_from_webview; + data->snapshot = gdk_pixbuf_new_from_file (uri, &error); + if (data->snapshot == NULL) { + g_simple_async_result_set_error (result, + EPHY_SNAPSHOT_SERVICE_ERROR, + EPHY_SNAPSHOT_SERVICE_ERROR_INVALID, + "Error creating pixbuf for snapshot file \"%s\": %s", + uri, error->message); + g_error_free (error); + } -out: - g_io_scheduler_job_send_to_mainloop (job, func, op, NULL); - return FALSE; + g_free (uri); } -static gboolean -io_scheduler_save_thumbnail (GIOSchedulerJob *job, - GCancellable *cancellable, - gpointer user_data) -{ - SnapshotOp *op; - EphySnapshotService *service; +typedef struct { + WebKitWebView *web_view; + time_t mtime; + GCancellable *cancellable; - op = (SnapshotOp*) user_data; - service = ephy_snapshot_service_get_default (); - gnome_desktop_thumbnail_factory_save_thumbnail (service->priv->factory, - op->snapshot, - op->url, - op->mtime); + GdkPixbuf *snapshot; +} SnapshotAsyncData; - g_io_scheduler_job_send_to_mainloop_async (job, - (GSourceFunc)ephy_snapshot_service_complete_async, - op, NULL); +static SnapshotAsyncData * +snapshot_async_data_new (WebKitWebView *web_view, + time_t mtime, + GCancellable *cancellable) +{ + SnapshotAsyncData *data; - return FALSE; -} + data = g_slice_new0 (SnapshotAsyncData); + data->web_view = g_object_ref (web_view); + data->mtime = mtime; + data->cancellable = cancellable ? g_object_ref (cancellable) : NULL; -/* Methods that run in the mainloop. */ + return data; +} -static gboolean -ephy_snapshot_service_complete_async (SnapshotOp *op) +static void +snapshot_async_data_free (SnapshotAsyncData *data) { - GSimpleAsyncResult *res; + g_object_unref (data->web_view); + g_clear_object (&data->cancellable); + g_clear_object (&data->snapshot); - res = g_simple_async_result_new (G_OBJECT (ephy_snapshot_service_get_default ()), - op->callback, - op->user_data, - ephy_snapshot_service_complete_async); - g_simple_async_result_set_check_cancellable (res, op->cancellable); - g_simple_async_result_set_op_res_gpointer (res, op, (GDestroyNotify)snapshot_op_free); - g_simple_async_result_complete (res); - g_object_unref (res); + g_slice_free (SnapshotAsyncData, data); +} - return FALSE; +static void +snapshot_saved (EphySnapshotService *service, + GAsyncResult *result, + GSimpleAsyncResult *simple) +{ + ephy_snapshot_service_save_snapshot_finish (service, result, NULL); + g_simple_async_result_complete (simple); + g_object_unref (simple); } static gboolean -webview_retrieve_snapshot (SnapshotOp *op) +retrieve_snapshot_from_web_view (GSimpleAsyncResult *result) { + EphySnapshotService *service; cairo_surface_t *surface; + SnapshotAsyncData *data; + + data = (SnapshotAsyncData *)g_simple_async_result_get_op_res_gpointer (result); #ifdef HAVE_WEBKIT2 /* FIXME: We need to add this API to WebKit2. */ surface = NULL; #else - surface = webkit_web_view_get_snapshot (WEBKIT_WEB_VIEW (op->webview)); + surface = webkit_web_view_get_snapshot (data->web_view); #endif if (surface == NULL) { - ephy_snapshot_service_complete_async (op); + g_simple_async_result_set_error (result, + EPHY_SNAPSHOT_SERVICE_ERROR, + EPHY_SNAPSHOT_SERVICE_ERROR_WEB_VIEW, + "%s", "Error getting snapshot from web view"); + g_simple_async_result_complete (result); + g_object_unref (result); + return FALSE; } - op->snapshot = ephy_snapshot_service_crop_snapshot (surface); + data->snapshot = ephy_snapshot_service_crop_snapshot (surface); cairo_surface_destroy (surface); - g_io_scheduler_push_job ((GIOSchedulerJobFunc)io_scheduler_save_thumbnail, - op, NULL, G_PRIORITY_LOW, NULL); + service = (EphySnapshotService *)g_async_result_get_source_object (G_ASYNC_RESULT (result)); + ephy_snapshot_service_save_snapshot_async (service, data->snapshot, + webkit_web_view_get_uri (data->web_view), + data->mtime, data->cancellable, + (GAsyncReadyCallback)snapshot_saved, result); + return FALSE; } @@ -205,18 +205,18 @@ webview_retrieve_snapshot (SnapshotOp *op) static void webview_load_changed_cb (WebKitWebView *webview, WebKitLoadEvent load_event, - SnapshotOp *op) + GSimpleAsyncResult *result) { - switch (load_event) { - case WEBKIT_LOAD_FINISHED: - /* Load finished doesn't ensure that we actually have visible content yet, - so hold a bit before retrieving the snapshot. */ - g_idle_add ((GSourceFunc) webview_retrieve_snapshot, op); - /* Some pages might end up causing this condition to happen twice, so remove - the handler in order to avoid calling the above idle function twice. */ - g_signal_handlers_disconnect_by_func (webview, webview_load_changed_cb, op); - break; - } + if (load_event != WEBKIT_LOAD_FINISHED) + return; + + /* Load finished doesn't ensure that we actually have visible content yet, + so hold a bit before retrieving the snapshot. */ + g_idle_add ((GSourceFunc) retrieve_snapshot_from_web_view, result); + + /* Some pages might end up causing this condition to happen twice, so remove + the handler in order to avoid calling the above idle function twice. */ + g_signal_handlers_disconnect_by_func (webview, webview_load_changed_cb, result); } static gboolean @@ -224,9 +224,16 @@ webview_load_failed_cb (WebKitWebView *webview, WebKitLoadEvent load_event, const char failing_uri, GError *error, - SnapshotOp *op) + GSimpleAsyncResult *result) { - ephy_snapshot_service_complete_async (op); + g_signal_handlers_disconnect_by_func (webview, webview_load_changed_cb, result); + g_simple_async_result_set_error (result, + EPHY_SNAPSHOT_SERVICE_ERROR, + EPHY_SNAPSHOT_SERVICE_ERROR_WEB_VIEW, + "Error getting snapshot, web view failed to load: %s", + error->message); + g_simple_async_result_complete_in_idle (result); + g_object_unref (result); return FALSE; } @@ -234,22 +241,23 @@ webview_load_failed_cb (WebKitWebView *webview, static void webview_load_status_changed_cb (WebKitWebView *webview, GParamSpec *pspec, - SnapshotOp *op) + GSimpleAsyncResult *result) { - WebKitLoadStatus status; - - status = webkit_web_view_get_load_status (webview); - - switch (status) { + switch (webkit_web_view_get_load_status (webview)) { case WEBKIT_LOAD_FINISHED: /* Load finished doesn't ensure that we actually have visible content yet, so hold a bit before retrieving the snapshot. */ - g_idle_add ((GSourceFunc) webview_retrieve_snapshot, op); - g_signal_handlers_disconnect_by_func (webview, webview_load_status_changed_cb, op); + g_idle_add ((GSourceFunc) retrieve_snapshot_from_web_view, result); + g_signal_handlers_disconnect_by_func (webview, webview_load_status_changed_cb, result); break; case WEBKIT_LOAD_FAILED: - g_signal_handlers_disconnect_by_func (webview, webview_load_status_changed_cb, op); - ephy_snapshot_service_complete_async (op); + g_signal_handlers_disconnect_by_func (webview, webview_load_status_changed_cb, result); + g_simple_async_result_set_error (result, + EPHY_SNAPSHOT_SERVICE_ERROR, + EPHY_SNAPSHOT_SERVICE_ERROR_WEB_VIEW, + "%s", "Error getting snapshot, web view failed to load"); + g_simple_async_result_complete_in_idle (result); + g_object_unref (result); break; default: break; @@ -258,36 +266,83 @@ webview_load_status_changed_cb (WebKitWebView *webview, #endif static gboolean -ephy_snapshot_service_take_from_webview (SnapshotOp *op) +ephy_snapshot_service_take_from_webview (GSimpleAsyncResult *result) { - WebKitWebView *webview = op->webview; + SnapshotAsyncData *data; - if (g_cancellable_is_cancelled (op->cancellable)) { - ephy_snapshot_service_complete_async (op); - return FALSE; - } + data = (SnapshotAsyncData *)g_simple_async_result_get_op_res_gpointer (result); #ifdef HAVE_WEBKIT2 - if (webkit_web_view_get_estimated_load_progress (WEBKIT_WEB_VIEW (webview))== 1.0) - webview_retrieve_snapshot (op); + if (webkit_web_view_get_estimated_load_progress (WEBKIT_WEB_VIEW (data->web_view)) == 1.0) + retrieve_snapshot_from_web_view (result); else { - g_signal_connect (webview, "load-changed", - G_CALLBACK (webview_load_changed_cb), op); - g_signal_connect (webview, "load-failed", - G_CALLBACK (webview_load_failed_cb), op); + g_signal_connect (data->web_view, "load-changed", + G_CALLBACK (webview_load_changed_cb), result); + g_signal_connect (data->web_view, "load-failed", + G_CALLBACK (webview_load_failed_cb), result); } #else - if (webkit_web_view_get_load_status (webview) == WEBKIT_LOAD_FINISHED) - webview_retrieve_snapshot (op); + if (webkit_web_view_get_load_status (data->web_view) == WEBKIT_LOAD_FINISHED) + retrieve_snapshot_from_web_view (result); else - g_signal_connect (webview, "notify::load-status", + g_signal_connect (data->web_view, "notify::load-status", G_CALLBACK (webview_load_status_changed_cb), - op); + result); #endif return FALSE; } +typedef struct { + GdkPixbuf *snapshot; + char *url; + time_t mtime; +} SaveSnapshotAsyncData; + +static SaveSnapshotAsyncData * +save_snapshot_async_data_new (GdkPixbuf *snapshot, + const char *url, + time_t mtime) +{ + SaveSnapshotAsyncData *data; + + data = g_slice_new (SaveSnapshotAsyncData); + data->snapshot = g_object_ref (snapshot); + data->url = g_strdup (url); + data->mtime = mtime; + + return data; +} + +static void +save_snapshot_async_data_free (SaveSnapshotAsyncData *data) +{ + g_object_unref (data->snapshot); + g_free (data->url); + + g_slice_free (SaveSnapshotAsyncData, data); +} + +static void +save_snapshot_thread (GSimpleAsyncResult *result, + EphySnapshotService *service, + GCancellable *cancellable) +{ + SaveSnapshotAsyncData *data; + + data = (SaveSnapshotAsyncData *)g_simple_async_result_get_op_res_gpointer (result); + gnome_desktop_thumbnail_factory_save_thumbnail (service->priv->factory, + data->snapshot, + data->url, + data->mtime); +} + +GQuark +ephy_snapshot_service_error_quark (void) +{ + return g_quark_from_static_string ("ephy-snapshot-service-error-quark"); +} + /** * ephy_snapshot_service_get_default: * @@ -307,12 +362,104 @@ ephy_snapshot_service_get_default (void) } /** - * ephy_snapshot_service_get_snapshot: + * ephy_snapshot_service_get_snapshot_for_url: * @service: a #EphySnapshotService * @url: the URL for which a snapshot is needed * @mtime: @the last * @callback: a #EphySnapshotServiceCallback - * @userdata: user data to pass to @callback + * @user_data: user data to pass to @callback + * + * Schedules a query for a snapshot of @url. If there is an up-to-date + * snapshot in the cache, this will be retrieved. + * + **/ +void +ephy_snapshot_service_get_snapshot_for_url_async (EphySnapshotService *service, + const char *url, + const time_t mtime, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *result; + + g_return_if_fail (EPHY_IS_SNAPSHOT_SERVICE (service)); + g_return_if_fail (url != NULL); + + result = g_simple_async_result_new (G_OBJECT (service), callback, user_data, + ephy_snapshot_service_get_snapshot_for_url_async); + + g_simple_async_result_set_op_res_gpointer (result, + snapshot_for_url_async_data_new (url, mtime), + (GDestroyNotify)snapshot_for_url_async_data_free); + g_simple_async_result_run_in_thread (result, + (GSimpleAsyncThreadFunc)get_snapshot_for_url_thread, + G_PRIORITY_LOW, cancellable); + g_object_unref (result); +} + +/** + * ephy_snapshot_service_get_snapshot_for_url_finish: + * @service: a #EphySnapshotService + * @result: a #GAsyncResult + * @error: a location to store a #GError or %NULL + * + * Finishes the retrieval of a snapshot. Call from the + * #GAsyncReadyCallback passed to + * ephy_snapshot_service_get_snapshot_for_url_async(). + * + * Returns: (transfer full): the snapshot. + **/ +GdkPixbuf * +ephy_snapshot_service_get_snapshot_for_url_finish (EphySnapshotService *service, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; + SnapshotForURLAsyncData *data; + + g_return_val_if_fail (EPHY_IS_SNAPSHOT_SERVICE (service), NULL); + g_return_val_if_fail (g_simple_async_result_is_valid (result, + G_OBJECT (service), + ephy_snapshot_service_get_snapshot_for_url_async), + NULL); + + simple = (GSimpleAsyncResult *)result; + + if (g_simple_async_result_propagate_error (simple, error)) + return NULL; + + data = (SnapshotForURLAsyncData *)g_simple_async_result_get_op_res_gpointer (simple); + + return data->snapshot ? g_object_ref (data->snapshot) : NULL; +} + +static void +got_snapshot_for_url (EphySnapshotService *service, + GAsyncResult *result, + GSimpleAsyncResult *simple) +{ + SnapshotAsyncData *data; + + data = (SnapshotAsyncData *)g_simple_async_result_get_op_res_gpointer (simple); + data->snapshot = ephy_snapshot_service_get_snapshot_for_url_finish (service, result, NULL); + if (data->snapshot) { + g_simple_async_result_complete (simple); + g_object_unref (simple); + + return; + } + + ephy_snapshot_service_take_from_webview (simple); +} + +/** + * ephy_snapshot_service_get_snapshot_async: + * @service: a #EphySnapshotService + * @web_view: the #WebKitWebView for which a snapshot is needed + * @mtime: @the last + * @callback: a #EphySnapshotServiceCallback + * @user_data: user data to pass to @callback * * Schedules a query for a snapshot of @url. If there is an up-to-date * snapshot in the cache, this will be retrieved. Otherwise, this @@ -321,30 +468,34 @@ ephy_snapshot_service_get_default (void) **/ void ephy_snapshot_service_get_snapshot_async (EphySnapshotService *service, - WebKitWebView *webview, - const char *url, + WebKitWebView *web_view, const time_t mtime, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { - SnapshotOp *op; + GSimpleAsyncResult *result; + const char *uri; g_return_if_fail (EPHY_IS_SNAPSHOT_SERVICE (service)); - g_return_if_fail (url != NULL); - - op = g_slice_alloc0 (sizeof(SnapshotOp)); - op->url = g_strdup (url); - op->mtime = mtime; - op->webview = webview ? g_object_ref (webview) : NULL; - op->cancellable = cancellable ? g_object_ref (cancellable) : NULL; - op->callback = callback; - op->user_data = user_data; - - /* Query for the snapshot from the cache using the IO scheduler, so - that there is no UI blocking during the cache query. */ - g_io_scheduler_push_job (io_scheduler_try_cache_query, - op, NULL, G_PRIORITY_LOW, NULL); + g_return_if_fail (WEBKIT_IS_WEB_VIEW (web_view)); + + result = g_simple_async_result_new (G_OBJECT (service), callback, user_data, + ephy_snapshot_service_get_snapshot_async); + + g_simple_async_result_set_op_res_gpointer (result, + snapshot_async_data_new (web_view, mtime, cancellable), + (GDestroyNotify)snapshot_async_data_free); + + /* Try to get the snapshot from the cache first if we have a URL */ + uri = webkit_web_view_get_uri (web_view); + if (uri) + ephy_snapshot_service_get_snapshot_for_url_async (service, + uri, mtime, cancellable, + (GAsyncReadyCallback)got_snapshot_for_url, + result); + else + g_idle_add ((GSourceFunc)ephy_snapshot_service_take_from_webview, result); } /** @@ -365,21 +516,22 @@ ephy_snapshot_service_get_snapshot_finish (EphySnapshotService *service, GError **error) { GSimpleAsyncResult *simple; - SnapshotOp *op; + SnapshotAsyncData *data; + g_return_val_if_fail (EPHY_IS_SNAPSHOT_SERVICE (service), NULL); g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (service), - ephy_snapshot_service_complete_async), + ephy_snapshot_service_get_snapshot_async), NULL); - simple = (GSimpleAsyncResult *) result; + simple = (GSimpleAsyncResult *)result; if (g_simple_async_result_propagate_error (simple, error)) return NULL; - op = g_simple_async_result_get_op_res_gpointer (simple); + data = (SnapshotAsyncData *)g_simple_async_result_get_op_res_gpointer (simple); - return op->snapshot ? g_object_ref (op->snapshot) : NULL; + return data->snapshot ? g_object_ref (data->snapshot) : NULL; } void @@ -391,22 +543,35 @@ ephy_snapshot_service_save_snapshot_async (EphySnapshotService *service, GAsyncReadyCallback callback, gpointer user_data) { - SnapshotOp *op; + GSimpleAsyncResult *result; g_return_if_fail (EPHY_IS_SNAPSHOT_SERVICE (service)); g_return_if_fail (GDK_IS_PIXBUF (snapshot)); g_return_if_fail (url != NULL); - op = g_slice_alloc0 (sizeof(SnapshotOp)); - op->snapshot = g_object_ref (snapshot); - op->url = g_strdup (url); - op->mtime = mtime; - op->cancellable = cancellable ? g_object_ref (cancellable) : NULL; - op->callback = callback; - op->user_data = user_data; + result = g_simple_async_result_new (G_OBJECT (service), callback, user_data, + ephy_snapshot_service_save_snapshot_async); + + g_simple_async_result_set_op_res_gpointer (result, + save_snapshot_async_data_new (snapshot, url, mtime), + (GDestroyNotify)save_snapshot_async_data_free); + g_simple_async_result_run_in_thread (result, + (GSimpleAsyncThreadFunc)save_snapshot_thread, + G_PRIORITY_LOW, cancellable); +} + +gboolean +ephy_snapshot_service_save_snapshot_finish (EphySnapshotService *service, + GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (EPHY_IS_SNAPSHOT_SERVICE (service), FALSE); + g_return_val_if_fail (g_simple_async_result_is_valid (result, + G_OBJECT (service), + ephy_snapshot_service_save_snapshot_async), + FALSE); - g_io_scheduler_push_job (io_scheduler_save_thumbnail, - op, NULL, G_PRIORITY_LOW, NULL); + return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error); } GdkPixbuf * diff --git a/lib/ephy-snapshot-service.h b/lib/ephy-snapshot-service.h index deab02071..dacf21a63 100644 --- a/lib/ephy-snapshot-service.h +++ b/lib/ephy-snapshot-service.h @@ -39,6 +39,8 @@ G_BEGIN_DECLS #define EPHY_IS_SNAPSHOT_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EPHY_TYPE_SNAPSHOT_SERVICE)) #define EPHY_SNAPSHOT_SERVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EPHY_TYPE_SNAPSHOT_SERVICE, EphySnapshotServiceClass)) +#define EPHY_SNAPSHOT_SERVICE_ERROR (ephy_snapshot_service_error_quark()) + typedef struct _EphySnapshotService EphySnapshotService; typedef struct _EphySnapshotServiceClass EphySnapshotServiceClass; typedef struct _EphySnapshotServicePrivate EphySnapshotServicePrivate; @@ -56,38 +58,56 @@ struct _EphySnapshotServiceClass GObjectClass parent_class; }; +typedef enum { + EPHY_SNAPSHOT_SERVICE_ERROR_NOT_FOUND, + EPHY_SNAPSHOT_SERVICE_ERROR_WEB_VIEW, + EPHY_SNAPSHOT_SERVICE_ERROR_INVALID +} EphySnapshotServiceError; + /* Values taken from the Web mockups. */ #define EPHY_THUMBNAIL_WIDTH 180 #define EPHY_THUMBNAIL_HEIGHT 135 -typedef void (* EphySnapshotServiceCallback) (GdkPixbuf *snapshot, - gpointer user_data); - -GType ephy_snapshot_service_get_type (void) G_GNUC_CONST; - -EphySnapshotService *ephy_snapshot_service_get_default (void); - -void ephy_snapshot_service_get_snapshot_async (EphySnapshotService *service, - WebKitWebView *webview, - const char *url, - const time_t mtime, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - -GdkPixbuf * ephy_snapshot_service_get_snapshot_finish (EphySnapshotService *service, - GAsyncResult *result, - GError **error); - -void ephy_snapshot_service_save_snapshot_async (EphySnapshotService *service, - GdkPixbuf *snapshot, - const char *url, - time_t mtime, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - -GdkPixbuf* ephy_snapshot_service_crop_snapshot (cairo_surface_t *surface); +GType ephy_snapshot_service_get_type (void) G_GNUC_CONST; +GQuark ephy_snapshot_service_error_quark (void); + +EphySnapshotService *ephy_snapshot_service_get_default (void); + +void ephy_snapshot_service_get_snapshot_for_url_async (EphySnapshotService *service, + const char *url, + const time_t mtime, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +GdkPixbuf *ephy_snapshot_service_get_snapshot_for_url_finish (EphySnapshotService *service, + GAsyncResult *result, + GError **error); + +void ephy_snapshot_service_get_snapshot_async (EphySnapshotService *service, + WebKitWebView *web_view, + const time_t mtime, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +GdkPixbuf *ephy_snapshot_service_get_snapshot_finish (EphySnapshotService *service, + GAsyncResult *result, + GError **error); + +void ephy_snapshot_service_save_snapshot_async (EphySnapshotService *service, + GdkPixbuf *snapshot, + const char *url, + time_t mtime, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +gboolean ephy_snapshot_service_save_snapshot_finish (EphySnapshotService *service, + GAsyncResult *result, + GError **error); + +GdkPixbuf *ephy_snapshot_service_crop_snapshot (cairo_surface_t *surface); G_END_DECLS diff --git a/lib/widgets/ephy-overview-store.c b/lib/widgets/ephy-overview-store.c index 312a24ffc..99ef2cf45 100644 --- a/lib/widgets/ephy-overview-store.c +++ b/lib/widgets/ephy-overview-store.c @@ -292,39 +292,60 @@ ephy_overview_store_set_default_icon_internal (EphyOverviewStore *store, } static void +set_snapshot (EphyOverviewStore *store, + GdkPixbuf *snapshot, + GtkTreeRowReference *ref, + time_t timestamp) +{ + GtkTreePath *path; + GtkTreeIter iter; + + path = gtk_tree_row_reference_get_path (ref); + gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path); + gtk_tree_path_free (path); + + if (snapshot) + ephy_overview_store_set_snapshot_internal (store, &iter, snapshot, timestamp); + else + ephy_overview_store_set_default_icon_internal (store, &iter, store->priv->default_icon); + + gtk_list_store_set (GTK_LIST_STORE (store), &iter, + EPHY_OVERVIEW_STORE_SNAPSHOT_CANCELLABLE, NULL, + -1); +} + +static void on_snapshot_retrieved_cb (GObject *object, GAsyncResult *res, PeekContext *ctx) { - EphyOverviewStore *store; - GtkTreePath *path; - GtkTreeIter iter; GdkPixbuf *snapshot; - GError *error = NULL; snapshot = ephy_snapshot_service_get_snapshot_finish (EPHY_SNAPSHOT_SERVICE (object), - res, &error); - - if (error) { - g_error_free (error); - error = NULL; - } else { - store = EPHY_OVERVIEW_STORE (gtk_tree_row_reference_get_model (ctx->ref)); - path = gtk_tree_row_reference_get_path (ctx->ref); - gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path); - gtk_tree_path_free (path); - if (snapshot) { - ephy_overview_store_set_snapshot_internal (store, &iter, snapshot, ctx->timestamp); - g_object_unref (snapshot); - - } else { - ephy_overview_store_set_default_icon_internal (store, &iter, - store->priv->default_icon); - } - gtk_list_store_set (GTK_LIST_STORE (store), &iter, - EPHY_OVERVIEW_STORE_SNAPSHOT_CANCELLABLE, NULL, - -1); - } + res, NULL); + + set_snapshot (EPHY_OVERVIEW_STORE (gtk_tree_row_reference_get_model (ctx->ref)), + snapshot, ctx->ref, ctx->timestamp); + if (snapshot) + g_object_unref (snapshot); + + peek_context_free (ctx); +} + +static void +on_snapshot_retrieved_for_url_cb (GObject *object, + GAsyncResult *res, + PeekContext *ctx) +{ + GdkPixbuf *snapshot; + + snapshot = ephy_snapshot_service_get_snapshot_for_url_finish (EPHY_SNAPSHOT_SERVICE (object), + res, NULL); + + set_snapshot (EPHY_OVERVIEW_STORE (gtk_tree_row_reference_get_model (ctx->ref)), + snapshot, ctx->ref, ctx->timestamp); + if (snapshot) + g_object_unref (snapshot); peek_context_free (ctx); } @@ -341,10 +362,16 @@ history_service_url_cb (gpointer service, ctx->timestamp = url->thumbnail_time; - ephy_snapshot_service_get_snapshot_async (snapshot_service, - ctx->webview, ctx->url, ctx->timestamp, ctx->cancellable, - (GAsyncReadyCallback) on_snapshot_retrieved_cb, - ctx); + if (ctx->webview) + ephy_snapshot_service_get_snapshot_async (snapshot_service, + ctx->webview, ctx->timestamp, ctx->cancellable, + (GAsyncReadyCallback) on_snapshot_retrieved_cb, + ctx); + else + ephy_snapshot_service_get_snapshot_for_url_async (snapshot_service, + ctx->url, ctx->timestamp, ctx->cancellable, + (GAsyncReadyCallback) on_snapshot_retrieved_for_url_cb, + ctx); ephy_history_url_free (url); } diff --git a/tests/ephy-snapshot-service-test.c b/tests/ephy-snapshot-service-test.c index 2ece2df1e..5c352e040 100644 --- a/tests/ephy-snapshot-service-test.c +++ b/tests/ephy-snapshot-service-test.c @@ -84,7 +84,6 @@ test_snapshot (void) webkit_web_view_load_uri (webview, TEST_SERVER_URI); ephy_snapshot_service_get_snapshot_async (service, webview, - TEST_SERVER_URI, mtime, NULL, (GAsyncReadyCallback)on_snapshot_ready, @@ -102,7 +101,6 @@ test_cached_snapshot (void) webkit_web_view_load_uri (webview, TEST_SERVER_URI); ephy_snapshot_service_get_snapshot_async (service, webview, - TEST_SERVER_URI, mtime, NULL, (GAsyncReadyCallback)on_snapshot_ready, @@ -121,7 +119,6 @@ test_many_snapshots (void) webkit_web_view_load_uri (webview, TEST_SERVER_URI "/some"); ephy_snapshot_service_get_snapshot_async (service, webview, - TEST_SERVER_URI "/some", mtime, NULL, (GAsyncReadyCallback)on_snapshot_ready, @@ -131,7 +128,6 @@ test_many_snapshots (void) webkit_web_view_load_uri (webview, TEST_SERVER_URI "/other"); ephy_snapshot_service_get_snapshot_async (service, webview, - TEST_SERVER_URI "/other", mtime, NULL, (GAsyncReadyCallback)on_snapshot_ready, @@ -141,7 +137,6 @@ test_many_snapshots (void) webkit_web_view_load_uri (webview, TEST_SERVER_URI "/place"); ephy_snapshot_service_get_snapshot_async (service, webview, - TEST_SERVER_URI "/place", mtime, NULL, (GAsyncReadyCallback)on_snapshot_ready, @@ -160,7 +155,6 @@ test_snapshot_with_cancellable (void) webkit_web_view_load_uri (webview, TEST_SERVER_URI "/and"); ephy_snapshot_service_get_snapshot_async (service, webview, - TEST_SERVER_URI "/and", mtime, cancellable, (GAsyncReadyCallback)on_snapshot_ready, @@ -180,7 +174,6 @@ test_already_cancelled_snapshot (void) g_cancellable_cancel (cancellable); ephy_snapshot_service_get_snapshot_async (service, webview, - TEST_SERVER_URI "/so", mtime, cancellable, (GAsyncReadyCallback)on_snapshot_ready, @@ -207,7 +200,6 @@ test_snapshot_and_timed_cancellation (void) ephy_snapshot_service_get_snapshot_async (service, webview, - TEST_SERVER_URI "/on", mtime, cancellable, (GAsyncReadyCallback)on_snapshot_ready, |