[libgdata] introspection: Add GDestroyNotify to progress callbacks



commit fafa68352959512861bcbc8c9d3f0295a70e767c
Author: Philip Chimento <philip chimento gmail com>
Date:   Sat Jun 18 18:31:28 2011 +0100

    introspection: Add GDestroyNotify to progress callbacks
    
    All query_async functions that take a progress callback should have a
    GDestroyNotify parameter for freeing the progress callback data, since
    there is no suitable (scope) annotation.
    
    This breaks API by changing the signatures for:
     â gdata_access_handler_get_rules_async()
     â gdata_service_query_async()
     â gdata_calendar_service_query_all_calendars_async()
     â gdata_calendar_service_query_own_calendars_async()
     â gdata_calendar_service_query_events_async()
     â gdata_contacts_service_query_contacts_async()
     â gdata_contacts_service_query_groups_async()
     â gdata_documents_service_query_documents_async()
     â gdata_picasaweb_service_query_all_albums_async()
     â gdata_picasaweb_service_query_files_async()
     â gdata_youtube_service_query_standard_feed_async()
     â gdata_youtube_service_query_videos_async()
     â gdata_youtube_service_query_related_async()
    
    Closes: bgo#649728

 HACKING                                            |    3 +
 gdata/gdata-access-handler.c                       |   13 +++-
 gdata/gdata-access-handler.h                       |    1 +
 gdata/gdata-service.c                              |   14 +++-
 gdata/gdata-service.h                              |    2 +-
 gdata/services/calendar/gdata-calendar-service.c   |   27 +++++--
 gdata/services/calendar/gdata-calendar-service.h   |    6 +-
 gdata/services/contacts/gdata-contacts-service.c   |   20 ++++--
 gdata/services/contacts/gdata-contacts-service.h   |    2 +
 gdata/services/documents/gdata-documents-service.c |   10 ++-
 gdata/services/documents/gdata-documents-service.h |    1 +
 gdata/services/picasaweb/gdata-picasaweb-service.c |   23 ++++--
 gdata/services/picasaweb/gdata-picasaweb-service.h |    2 +
 gdata/services/youtube/gdata-youtube-service.c     |   30 ++++++--
 gdata/services/youtube/gdata-youtube-service.h     |    3 +
 gdata/tests/calendar.c                             |   82 +++++++++++++++++++-
 gdata/tests/common.c                               |   26 ++++++
 gdata/tests/common.h                               |   10 +++
 gdata/tests/contacts.c                             |   52 ++++++++++++-
 gdata/tests/documents.c                            |   26 ++++++-
 gdata/tests/picasaweb.c                            |   68 ++++++++++++++++-
 gdata/tests/youtube.c                              |   56 +++++++++++++-
 22 files changed, 427 insertions(+), 50 deletions(-)
---
diff --git a/HACKING b/HACKING
index ae531dc..9d9f699 100644
--- a/HACKING
+++ b/HACKING
@@ -121,6 +121,9 @@ Adding public API
    See http://www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html for information about libtool's versioning system. See also the
    âVersioningâ section below.
 
+ - Any async function which uses non-async-scope callbacks as well as the async ready callback should provide GDestroyNotify callbacks for destroying
+   the user data for those callbacks. See https://bugzilla.gnome.org/show_bug.cgi?id=649728 for details.
+
 Choosing function names
 =======================
 
diff --git a/gdata/gdata-access-handler.c b/gdata/gdata-access-handler.c
index e8e8af7..ba73878 100644
--- a/gdata/gdata-access-handler.c
+++ b/gdata/gdata-access-handler.c
@@ -62,6 +62,7 @@ typedef struct {
 	GDataService *service;
 	GDataQueryProgressCallback progress_callback;
 	gpointer progress_user_data;
+	GDestroyNotify destroy_progress_user_data;
 	GDataFeed *feed;
 } GetRulesAsyncData;
 
@@ -89,15 +90,21 @@ get_rules_thread (GSimpleAsyncResult *result, GDataAccessHandler *access_handler
 		g_simple_async_result_set_from_error (result, error);
 		g_error_free (error);
 	}
+
+	if (data->destroy_progress_user_data != NULL) {
+		data->destroy_progress_user_data (data->progress_user_data);
+	}
 }
 
 /**
- * gdata_access_handler_get_rules_async: (skip)
+ * gdata_access_handler_get_rules_async:
  * @self: a #GDataAccessHandler
  * @service: a #GDataService
  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
  * @progress_callback: (allow-none) (closure progress_user_data): a #GDataQueryProgressCallback to call when a rule is loaded, or %NULL
  * @progress_user_data: (closure): data to pass to the @progress_callback function
+ * @destroy_progress_user_data: (allow-none): the function to call when @progress_callback will not be called any more, or %NULL. This function will be
+ * called with @progress_user_data as a parameter and can be used to free any memory allocated for it.
  * @callback: a #GAsyncReadyCallback to call when the query is finished
  * @user_data: (closure): data to pass to the @callback function
  *
@@ -110,11 +117,12 @@ get_rules_thread (GSimpleAsyncResult *result, GDataAccessHandler *access_handler
  * When the operation is finished, @callback will be called. You can then call gdata_service_query_finish()
  * to get the results of the operation.
  *
- * Since: 0.7.0
+ * Since: 0.9.1
  **/
 void
 gdata_access_handler_get_rules_async (GDataAccessHandler *self, GDataService *service, GCancellable *cancellable,
                                       GDataQueryProgressCallback progress_callback, gpointer progress_user_data,
+                                      GDestroyNotify destroy_progress_user_data,
                                       GAsyncReadyCallback callback, gpointer user_data)
 {
 	GSimpleAsyncResult *result;
@@ -129,6 +137,7 @@ gdata_access_handler_get_rules_async (GDataAccessHandler *self, GDataService *se
 	data->service = g_object_ref (service);
 	data->progress_callback = progress_callback;
 	data->progress_user_data = progress_user_data;
+	data->destroy_progress_user_data = destroy_progress_user_data;
 
 	result = g_simple_async_result_new (G_OBJECT (self), callback, user_data, gdata_service_query_async);
 	g_simple_async_result_set_op_res_gpointer (result, data, (GDestroyNotify) get_rules_async_data_free);
diff --git a/gdata/gdata-access-handler.h b/gdata/gdata-access-handler.h
index d1b8a2a..a1578aa 100644
--- a/gdata/gdata-access-handler.h
+++ b/gdata/gdata-access-handler.h
@@ -83,6 +83,7 @@ GDataFeed *gdata_access_handler_get_rules (GDataAccessHandler *self, GDataServic
                                            GError **error) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
 void gdata_access_handler_get_rules_async (GDataAccessHandler *self, GDataService *service, GCancellable *cancellable,
                                            GDataQueryProgressCallback progress_callback, gpointer progress_user_data,
+                                           GDestroyNotify destroy_progress_user_data,
                                            GAsyncReadyCallback callback, gpointer user_data);
 
 G_END_DECLS
diff --git a/gdata/gdata-service.c b/gdata/gdata-service.c
index 66f9509..b81b30a 100644
--- a/gdata/gdata-service.c
+++ b/gdata/gdata-service.c
@@ -701,6 +701,7 @@ typedef struct {
 	GDataFeed *feed;
 	GDataQueryProgressCallback progress_callback;
 	gpointer progress_user_data;
+	GDestroyNotify destroy_progress_user_data;
 } QueryAsyncData;
 
 static void
@@ -731,10 +732,14 @@ query_thread (GSimpleAsyncResult *result, GDataService *service, GCancellable *c
 		g_simple_async_result_set_from_error (result, error);
 		g_error_free (error);
 	}
+
+	if (data->destroy_progress_user_data != NULL) {
+		data->destroy_progress_user_data (data->progress_user_data);
+	}
 }
 
 /**
- * gdata_service_query_async: (skip)
+ * gdata_service_query_async:
  * @self: a #GDataService
  * @domain: (allow-none): the #GDataAuthorizationDomain the query falls under, or %NULL
  * @feed_uri: the feed URI to query, including the host name and protocol
@@ -743,6 +748,8 @@ query_thread (GSimpleAsyncResult *result, GDataService *service, GCancellable *c
  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
  * @progress_callback: (allow-none) (closure progress_user_data): a #GDataQueryProgressCallback to call when an entry is loaded, or %NULL
  * @progress_user_data: (closure): data to pass to the @progress_callback function
+ * @destroy_progress_user_data: (allow-none): the function to call when @progress_callback will not be called any more, or %NULL. This function will be
+ * called with @progress_user_data as a parameter and can be used to free any memory allocated for it.
  * @callback: a #GAsyncReadyCallback to call when the query is finished
  * @user_data: (closure): data to pass to the @callback function
  *
@@ -754,12 +761,12 @@ query_thread (GSimpleAsyncResult *result, GDataService *service, GCancellable *c
  * When the operation is finished, @callback will be called. You can then call gdata_service_query_finish()
  * to get the results of the operation.
  *
- * Since: 0.9.0
+ * Since: 0.9.1
  **/
 void
 gdata_service_query_async (GDataService *self, GDataAuthorizationDomain *domain, const gchar *feed_uri, GDataQuery *query, GType entry_type,
                            GCancellable *cancellable, GDataQueryProgressCallback progress_callback, gpointer progress_user_data,
-                           GAsyncReadyCallback callback, gpointer user_data)
+                           GDestroyNotify destroy_progress_user_data, GAsyncReadyCallback callback, gpointer user_data)
 {
 	GSimpleAsyncResult *result;
 	QueryAsyncData *data;
@@ -778,6 +785,7 @@ gdata_service_query_async (GDataService *self, GDataAuthorizationDomain *domain,
 	data->entry_type = entry_type;
 	data->progress_callback = progress_callback;
 	data->progress_user_data = progress_user_data;
+	data->destroy_progress_user_data = destroy_progress_user_data;
 
 	result = g_simple_async_result_new (G_OBJECT (self), callback, user_data, gdata_service_query_async);
 	g_simple_async_result_set_op_res_gpointer (result, data, (GDestroyNotify) query_async_data_free);
diff --git a/gdata/gdata-service.h b/gdata/gdata-service.h
index 2527f88..83c2575 100644
--- a/gdata/gdata-service.h
+++ b/gdata/gdata-service.h
@@ -169,7 +169,7 @@ GDataFeed *gdata_service_query (GDataService *self, GDataAuthorizationDomain *do
                                 GError **error) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
 void gdata_service_query_async (GDataService *self, GDataAuthorizationDomain *domain, const gchar *feed_uri, GDataQuery *query, GType entry_type,
                                 GCancellable *cancellable,
-                                GDataQueryProgressCallback progress_callback, gpointer progress_user_data,
+                                GDataQueryProgressCallback progress_callback, gpointer progress_user_data, GDestroyNotify destroy_progress_user_data,
                                 GAsyncReadyCallback callback, gpointer user_data);
 GDataFeed *gdata_service_query_finish (GDataService *self, GAsyncResult *async_result, GError **error) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
 
diff --git a/gdata/services/calendar/gdata-calendar-service.c b/gdata/services/calendar/gdata-calendar-service.c
index e90b80f..240416a 100644
--- a/gdata/services/calendar/gdata-calendar-service.c
+++ b/gdata/services/calendar/gdata-calendar-service.c
@@ -325,12 +325,14 @@ gdata_calendar_service_query_all_calendars (GDataCalendarService *self, GDataQue
 }
 
 /**
- * gdata_calendar_service_query_all_calendars_async: (skip)
+ * gdata_calendar_service_query_all_calendars_async:
  * @self: a #GDataCalendarService
  * @query: (allow-none): a #GDataQuery with the query parameters, or %NULL
  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
  * @progress_callback: (allow-none) (closure progress_user_data): a #GDataQueryProgressCallback to call when an entry is loaded, or %NULL
  * @progress_user_data: (closure): data to pass to the @progress_callback function
+ * @destroy_progress_user_data: (allow-none): the function to call when @progress_callback will not be called any more, or %NULL. This function will be
+ * called with @progress_user_data as a parameter and can be used to free any memory allocated for it.
  * @callback: a #GAsyncReadyCallback to call when authentication is finished
  * @user_data: (closure): data to pass to the @callback function
  *
@@ -340,10 +342,13 @@ gdata_calendar_service_query_all_calendars (GDataCalendarService *self, GDataQue
  *
  * For more details, see gdata_calendar_service_query_all_calendars(), which is the synchronous version of
  * this function, and gdata_service_query_async(), which is the base asynchronous query function.
+ *
+ * Since: 0.9.1
  **/
 void
 gdata_calendar_service_query_all_calendars_async (GDataCalendarService *self, GDataQuery *query, GCancellable *cancellable,
                                                   GDataQueryProgressCallback progress_callback, gpointer progress_user_data,
+                                                  GDestroyNotify destroy_progress_user_data,
                                                   GAsyncReadyCallback callback, gpointer user_data)
 {
 	gchar *request_uri;
@@ -364,7 +369,7 @@ gdata_calendar_service_query_all_calendars_async (GDataCalendarService *self, GD
 
 	request_uri = g_strconcat (_gdata_service_get_scheme (), "://www.google.com/calendar/feeds/default/allcalendars/full", NULL);
 	gdata_service_query_async (GDATA_SERVICE (self), get_calendar_authorization_domain (), request_uri, query, GDATA_TYPE_CALENDAR_CALENDAR,
-	                           cancellable, progress_callback, progress_user_data, callback, user_data);
+	                           cancellable, progress_callback, progress_user_data, destroy_progress_user_data, callback, user_data);
 	g_free (request_uri);
 }
 
@@ -414,12 +419,14 @@ gdata_calendar_service_query_own_calendars (GDataCalendarService *self, GDataQue
 }
 
 /**
- * gdata_calendar_service_query_own_calendars_async: (skip)
+ * gdata_calendar_service_query_own_calendars_async:
  * @self: a #GDataCalendarService
  * @query: (allow-none): a #GDataQuery with the query parameters, or %NULL
  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
  * @progress_callback: (allow-none) (closure progress_user_data): a #GDataQueryProgressCallback to call when an entry is loaded, or %NULL
  * @progress_user_data: (closure): data to pass to the @progress_callback function
+ * @destroy_progress_user_data: (allow-none): the function to call when @progress_callback will not be called any more, or %NULL. This function will be
+ * called with @progress_user_data as a parameter and can be used to free any memory allocated for it.
  * @callback: a #GAsyncReadyCallback to call when authentication is finished
  * @user_data: (closure): data to pass to the @callback function
  *
@@ -429,10 +436,13 @@ gdata_calendar_service_query_own_calendars (GDataCalendarService *self, GDataQue
  *
  * For more details, see gdata_calendar_service_query_own_calendars(), which is the synchronous version of
  * this function, and gdata_service_query_async(), which is the base asynchronous query function.
+ *
+ * Since: 0.9.1
  **/
 void
 gdata_calendar_service_query_own_calendars_async (GDataCalendarService *self, GDataQuery *query, GCancellable *cancellable,
                                                   GDataQueryProgressCallback progress_callback, gpointer progress_user_data,
+                                                  GDestroyNotify destroy_progress_user_data,
                                                   GAsyncReadyCallback callback, gpointer user_data)
 {
 	gchar *request_uri;
@@ -453,7 +463,7 @@ gdata_calendar_service_query_own_calendars_async (GDataCalendarService *self, GD
 
 	request_uri = g_strconcat (_gdata_service_get_scheme (), "://www.google.com/calendar/feeds/default/owncalendars/full", NULL);
 	gdata_service_query_async (GDATA_SERVICE (self), get_calendar_authorization_domain (), request_uri, query, GDATA_TYPE_CALENDAR_CALENDAR,
-	                           cancellable, progress_callback, progress_user_data, callback, user_data);
+	                           cancellable, progress_callback, progress_user_data, destroy_progress_user_data, callback, user_data);
 	g_free (request_uri);
 }
 
@@ -508,13 +518,15 @@ gdata_calendar_service_query_events (GDataCalendarService *self, GDataCalendarCa
 }
 
 /**
- * gdata_calendar_service_query_events_async: (skip)
+ * gdata_calendar_service_query_events_async:
  * @self: a #GDataCalendarService
  * @calendar: a #GDataCalendarCalendar
  * @query: (allow-none): a #GDataQuery with the query parameters, or %NULL
  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
  * @progress_callback: (allow-none) (closure progress_user_data): a #GDataQueryProgressCallback to call when an entry is loaded, or %NULL
  * @progress_user_data: (closure): data to pass to the @progress_callback function
+ * @destroy_progress_user_data: (allow-none): the function to call when @progress_callback will not be called any more, or %NULL. This function will be
+ * called with @progress_user_data as a parameter and can be used to free any memory allocated for it.
  * @callback: a #GAsyncReadyCallback to call when the query is finished
  * @user_data: (closure): data to pass to the @callback function
  *
@@ -526,11 +538,12 @@ gdata_calendar_service_query_events (GDataCalendarService *self, GDataCalendarCa
  * For more details, see gdata_calendar_service_query_events(), which is the synchronous version of this function, and gdata_service_query_async(),
  * which is the base asynchronous query function.
  *
- * Since: 0.8.0
+ * Since: 0.9.1
  **/
 void
 gdata_calendar_service_query_events_async (GDataCalendarService *self, GDataCalendarCalendar *calendar, GDataQuery *query, GCancellable *cancellable,
                                            GDataQueryProgressCallback progress_callback, gpointer progress_user_data,
+                                           GDestroyNotify destroy_progress_user_data,
                                            GAsyncReadyCallback callback, gpointer user_data)
 {
 	const gchar *uri;
@@ -561,7 +574,7 @@ gdata_calendar_service_query_events_async (GDataCalendarService *self, GDataCale
 
 	/* Execute the query */
 	gdata_service_query_async (GDATA_SERVICE (self), get_calendar_authorization_domain (), uri, query, GDATA_TYPE_CALENDAR_EVENT, cancellable,
-	                           progress_callback, progress_user_data, callback, user_data);
+	                           progress_callback, progress_user_data, destroy_progress_user_data, callback, user_data);
 }
 
 /**
diff --git a/gdata/services/calendar/gdata-calendar-service.h b/gdata/services/calendar/gdata-calendar-service.h
index 4c3ce4f..473574b 100644
--- a/gdata/services/calendar/gdata-calendar-service.h
+++ b/gdata/services/calendar/gdata-calendar-service.h
@@ -68,21 +68,21 @@ GDataFeed *gdata_calendar_service_query_all_calendars (GDataCalendarService *sel
                                                        GError **error) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
 void gdata_calendar_service_query_all_calendars_async (GDataCalendarService *self, GDataQuery *query, GCancellable *cancellable,
                                                        GDataQueryProgressCallback progress_callback, gpointer progress_user_data,
-                                                       GAsyncReadyCallback callback, gpointer user_data);
+                                                       GDestroyNotify destroy_progress_user_data, GAsyncReadyCallback callback, gpointer user_data);
 
 GDataFeed *gdata_calendar_service_query_own_calendars (GDataCalendarService *self, GDataQuery *query, GCancellable *cancellable,
                                                        GDataQueryProgressCallback progress_callback, gpointer progress_user_data,
                                                        GError **error) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
 void gdata_calendar_service_query_own_calendars_async (GDataCalendarService *self, GDataQuery *query, GCancellable *cancellable,
                                                        GDataQueryProgressCallback progress_callback, gpointer progress_user_data,
-                                                       GAsyncReadyCallback callback, gpointer user_data);
+                                                       GDestroyNotify destroy_progress_user_data, GAsyncReadyCallback callback, gpointer user_data);
 
 GDataFeed *gdata_calendar_service_query_events (GDataCalendarService *self, GDataCalendarCalendar *calendar, GDataQuery *query,
                                                 GCancellable *cancellable, GDataQueryProgressCallback progress_callback, gpointer progress_user_data,
                                                 GError **error) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
 void gdata_calendar_service_query_events_async (GDataCalendarService *self, GDataCalendarCalendar *calendar, GDataQuery *query,
                                                 GCancellable *cancellable, GDataQueryProgressCallback progress_callback, gpointer progress_user_data,
-                                                GAsyncReadyCallback callback, gpointer user_data);
+                                                GDestroyNotify destroy_progress_user_data, GAsyncReadyCallback callback, gpointer user_data);
 
 #include <gdata/services/calendar/gdata-calendar-event.h>
 
diff --git a/gdata/services/contacts/gdata-contacts-service.c b/gdata/services/contacts/gdata-contacts-service.c
index fa2cdd0..89bc712 100644
--- a/gdata/services/contacts/gdata-contacts-service.c
+++ b/gdata/services/contacts/gdata-contacts-service.c
@@ -268,12 +268,14 @@ gdata_contacts_service_query_contacts (GDataContactsService *self, GDataQuery *q
 }
 
 /**
- * gdata_contacts_service_query_contacts_async: (skip)
+ * gdata_contacts_service_query_contacts_async:
  * @self: a #GDataContactsService
  * @query: (allow-none): a #GDataQuery with the query parameters, or %NULL
  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
  * @progress_callback: (allow-none) (closure progress_user_data): a #GDataQueryProgressCallback to call when an entry is loaded, or %NULL
  * @progress_user_data: (closure): data to pass to the @progress_callback function
+ * @destroy_progress_user_data: (allow-none): the function to call when @progress_callback will not be called any more, or %NULL. This function will be
+ * called with @progress_user_data as a parameter and can be used to free any memory allocated for it.
  * @callback: a #GAsyncReadyCallback to call when the query is finished
  * @user_data: (closure): data to pass to the @callback function
  *
@@ -283,11 +285,12 @@ gdata_contacts_service_query_contacts (GDataContactsService *self, GDataQuery *q
  * For more details, see gdata_contacts_service_query_contacts(), which is the synchronous version of this function,
  * and gdata_service_query_async(), which is the base asynchronous query function.
  *
- * Since: 0.2.0
+ * Since: 0.9.1
  **/
 void
 gdata_contacts_service_query_contacts_async (GDataContactsService *self, GDataQuery *query, GCancellable *cancellable,
                                              GDataQueryProgressCallback progress_callback, gpointer progress_user_data,
+                                             GDestroyNotify destroy_progress_user_data,
                                              GAsyncReadyCallback callback, gpointer user_data)
 {
 	gchar *request_uri;
@@ -308,7 +311,8 @@ gdata_contacts_service_query_contacts_async (GDataContactsService *self, GDataQu
 
 	request_uri = g_strconcat (_gdata_service_get_scheme (), "://www.google.com/m8/feeds/contacts/default/full", NULL);
 	gdata_service_query_async (GDATA_SERVICE (self), get_contacts_authorization_domain (), request_uri, GDATA_QUERY (query),
-	                           GDATA_TYPE_CONTACTS_CONTACT, cancellable, progress_callback, progress_user_data, callback, user_data);
+	                           GDATA_TYPE_CONTACTS_CONTACT, cancellable, progress_callback, progress_user_data,
+	                           destroy_progress_user_data, callback, user_data);
 	g_free (request_uri);
 }
 
@@ -427,12 +431,14 @@ gdata_contacts_service_query_groups (GDataContactsService *self, GDataQuery *que
 }
 
 /**
- * gdata_contacts_service_query_groups_async: (skip)
+ * gdata_contacts_service_query_groups_async:
  * @self: a #GDataContactsService
  * @query: (allow-none): a #GDataQuery with the query parameters, or %NULL
  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
  * @progress_callback: (allow-none) (closure progress_user_data): a #GDataQueryProgressCallback to call when an entry is loaded, or %NULL
  * @progress_user_data: (closure): data to pass to the @progress_callback function
+ * @destroy_progress_user_data: (allow-none): the function to call when @progress_callback will not be called any more, or %NULL. This function will be
+ * called with @progress_user_data as a parameter and can be used to free any memory allocated for it.
  * @callback: a #GAsyncReadyCallback to call when the query is finished
  * @user_data: (closure): data to pass to the @callback function
  *
@@ -442,11 +448,12 @@ gdata_contacts_service_query_groups (GDataContactsService *self, GDataQuery *que
  * For more details, see gdata_contacts_service_query_groups(), which is the synchronous version of this function, and gdata_service_query_async(),
  * which is the base asynchronous query function.
  *
- * Since: 0.7.0
+ * Since: 0.9.1
  **/
 void
 gdata_contacts_service_query_groups_async (GDataContactsService *self, GDataQuery *query, GCancellable *cancellable,
                                            GDataQueryProgressCallback progress_callback, gpointer progress_user_data,
+                                           GDestroyNotify destroy_progress_user_data,
                                            GAsyncReadyCallback callback, gpointer user_data)
 {
 	gchar *request_uri;
@@ -467,7 +474,8 @@ gdata_contacts_service_query_groups_async (GDataContactsService *self, GDataQuer
 
 	request_uri = g_strconcat (_gdata_service_get_scheme (), "://www.google.com/m8/feeds/groups/default/full", NULL);
 	gdata_service_query_async (GDATA_SERVICE (self), get_contacts_authorization_domain (), request_uri, GDATA_QUERY (query),
-	                           GDATA_TYPE_CONTACTS_GROUP, cancellable, progress_callback, progress_user_data, callback, user_data);
+	                           GDATA_TYPE_CONTACTS_GROUP, cancellable, progress_callback, progress_user_data,
+	                           destroy_progress_user_data, callback, user_data);
 	g_free (request_uri);
 }
 
diff --git a/gdata/services/contacts/gdata-contacts-service.h b/gdata/services/contacts/gdata-contacts-service.h
index 36abbd3..23a4459 100644
--- a/gdata/services/contacts/gdata-contacts-service.h
+++ b/gdata/services/contacts/gdata-contacts-service.h
@@ -71,6 +71,7 @@ GDataFeed *gdata_contacts_service_query_contacts (GDataContactsService *self, GD
                                                   GError **error) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
 void gdata_contacts_service_query_contacts_async (GDataContactsService *self, GDataQuery *query, GCancellable *cancellable,
                                                   GDataQueryProgressCallback progress_callback, gpointer progress_user_data,
+                                                  GDestroyNotify destroy_progress_user_data,
                                                   GAsyncReadyCallback callback, gpointer user_data);
 
 #include <gdata/services/contacts/gdata-contacts-contact.h>
@@ -87,6 +88,7 @@ GDataFeed *gdata_contacts_service_query_groups (GDataContactsService *self, GDat
                                                 GError **error) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
 void gdata_contacts_service_query_groups_async (GDataContactsService *self, GDataQuery *query, GCancellable *cancellable,
                                                 GDataQueryProgressCallback progress_callback, gpointer progress_user_data,
+                                                GDestroyNotify destroy_progress_user_data,
                                                 GAsyncReadyCallback callback, gpointer user_data);
 
 GDataContactsGroup *gdata_contacts_service_insert_group (GDataContactsService *self, GDataContactsGroup *group,
diff --git a/gdata/services/documents/gdata-documents-service.c b/gdata/services/documents/gdata-documents-service.c
index c0b407e..5c00258 100644
--- a/gdata/services/documents/gdata-documents-service.c
+++ b/gdata/services/documents/gdata-documents-service.c
@@ -372,12 +372,14 @@ gdata_documents_service_query_documents (GDataDocumentsService *self, GDataDocum
 }
 
 /**
- * gdata_documents_service_query_documents_async: (skip)
+ * gdata_documents_service_query_documents_async:
  * @self: a #GDataDocumentsService
  * @query: (allow-none): a #GDataDocumentsQuery with the query parameters, or %NULL
  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
  * @progress_callback: (allow-none) (closure progress_user_data): a #GDataQueryProgressCallback to call when an entry is loaded, or %NULL
  * @progress_user_data: (closure): data to pass to the @progress_callback function
+ * @destroy_progress_user_data: (allow-none): the function to call when @progress_callback will not be called any more, or %NULL. This function will be
+ * called with @progress_user_data as a parameter and can be used to free any memory allocated for it.
  * @callback: a #GAsyncReadyCallback to call when authentication is finished
  * @user_data: (closure): data to pass to the @callback function
  *
@@ -387,11 +389,12 @@ gdata_documents_service_query_documents (GDataDocumentsService *self, GDataDocum
  * For more details, see gdata_documents_service_query_documents(), which is the synchronous version of this function,
  * and gdata_service_query_async(), which is the base asynchronous query function.
  *
- * Since: 0.4.0
+ * Since: 0.9.1
  **/
 void
 gdata_documents_service_query_documents_async (GDataDocumentsService *self, GDataDocumentsQuery *query, GCancellable *cancellable,
                                                GDataQueryProgressCallback progress_callback, gpointer progress_user_data,
+                                               GDestroyNotify destroy_progress_user_data,
                                                GAsyncReadyCallback callback, gpointer user_data)
 {
 	gchar *request_uri;
@@ -412,7 +415,8 @@ gdata_documents_service_query_documents_async (GDataDocumentsService *self, GDat
 
 	request_uri = g_strconcat (_gdata_service_get_scheme (), "://docs.google.com/feeds/documents/private/full", NULL);
 	gdata_service_query_async (GDATA_SERVICE (self), get_documents_authorization_domain (), request_uri, GDATA_QUERY (query),
-	                           GDATA_TYPE_DOCUMENTS_ENTRY, cancellable, progress_callback, progress_user_data, callback, user_data);
+	                           GDATA_TYPE_DOCUMENTS_ENTRY, cancellable, progress_callback, progress_user_data,
+	                           destroy_progress_user_data, callback, user_data);
 	g_free (request_uri);
 }
 
diff --git a/gdata/services/documents/gdata-documents-service.h b/gdata/services/documents/gdata-documents-service.h
index 6c20f0b..0a3a809 100644
--- a/gdata/services/documents/gdata-documents-service.h
+++ b/gdata/services/documents/gdata-documents-service.h
@@ -90,6 +90,7 @@ GDataDocumentsFeed *gdata_documents_service_query_documents (GDataDocumentsServi
                                                              GError **error) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
 void gdata_documents_service_query_documents_async (GDataDocumentsService *self, GDataDocumentsQuery *query, GCancellable *cancellable,
                                                     GDataQueryProgressCallback progress_callback, gpointer progress_user_data,
+                                                    GDestroyNotify destroy_progress_user_data,
                                                     GAsyncReadyCallback callback, gpointer user_data);
 
 #include <gdata/services/documents/gdata-documents-document.h>
diff --git a/gdata/services/picasaweb/gdata-picasaweb-service.c b/gdata/services/picasaweb/gdata-picasaweb-service.c
index 9276148..a5907ff 100644
--- a/gdata/services/picasaweb/gdata-picasaweb-service.c
+++ b/gdata/services/picasaweb/gdata-picasaweb-service.c
@@ -315,13 +315,15 @@ gdata_picasaweb_service_query_all_albums (GDataPicasaWebService *self, GDataQuer
 }
 
 /**
- * gdata_picasaweb_service_query_all_albums_async: (skip)
+ * gdata_picasaweb_service_query_all_albums_async:
  * @self: a #GDataPicasaWebService
  * @query: (allow-none): a #GDataQuery with the query parameters, or %NULL
  * @username: (allow-none): the username of the user whose albums you wish to retrieve, or %NULL
  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
  * @progress_callback: (allow-none) (closure progress_user_data): a #GDataQueryProgressCallback to call when an entry is loaded, or %NULL
  * @progress_user_data: (closure): data to pass to the @progress_callback function
+ * @destroy_progress_user_data: (allow-none): the function to call when @progress_callback will not be called any more, or %NULL. This function will be
+ * called with @progress_user_data as a parameter and can be used to free any memory allocated for it.
  * @callback: a #GAsyncReadyCallback to call when authentication is finished
  * @user_data: (closure): data to pass to the @callback function
  *
@@ -332,12 +334,12 @@ gdata_picasaweb_service_query_all_albums (GDataPicasaWebService *self, GDataQuer
  * For more details, see gdata_picasaweb_service_query_all_albums(), which is the synchronous version of
  * this function, and gdata_service_query_async(), which is the base asynchronous query function.
  *
- * Since: 0.4.0
+ * Since: 0.9.1
  **/
 void
 gdata_picasaweb_service_query_all_albums_async (GDataPicasaWebService *self, GDataQuery *query, const gchar *username,
                                                 GCancellable *cancellable, GDataQueryProgressCallback progress_callback, gpointer progress_user_data,
-                                                GAsyncReadyCallback callback, gpointer user_data)
+                                                GDestroyNotify destroy_progress_user_data, GAsyncReadyCallback callback, gpointer user_data)
 {
 	gchar *uri;
 
@@ -364,7 +366,7 @@ gdata_picasaweb_service_query_all_albums_async (GDataPicasaWebService *self, GDa
 
 	/* Schedule the async query */
 	gdata_service_query_async (GDATA_SERVICE (self), get_picasaweb_authorization_domain (), uri, query, GDATA_TYPE_PICASAWEB_ALBUM, cancellable,
-	                           progress_callback, progress_user_data, callback, user_data);
+	                           progress_callback, progress_user_data, destroy_progress_user_data, callback, user_data);
 	g_free (uri);
 }
 
@@ -428,13 +430,15 @@ gdata_picasaweb_service_query_files (GDataPicasaWebService *self, GDataPicasaWeb
 }
 
 /**
- * gdata_picasaweb_service_query_files_async: (skip)
+ * gdata_picasaweb_service_query_files_async:
  * @self: a #GDataPicasaWebService
  * @album: (allow-none): a #GDataPicasaWebAlbum from which to retrieve the files, or %NULL
  * @query: (allow-none): a #GDataQuery with the query parameters, or %NULL
  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
  * @progress_callback: (allow-none) (closure progress_user_data): a #GDataQueryProgressCallback to call when an entry is loaded, or %NULL
  * @progress_user_data: (closure): data to pass to the @progress_callback function
+ * @destroy_progress_user_data: (allow-none): the function to call when @progress_callback will not be called any more, or %NULL. This function will be
+ * called with @progress_user_data as a parameter and can be used to free any memory allocated for it.
  * @callback: a #GAsyncReadyCallback to call when the query is finished
  * @user_data: (closure): data to pass to the @callback function
  *
@@ -445,12 +449,12 @@ gdata_picasaweb_service_query_files (GDataPicasaWebService *self, GDataPicasaWeb
  * For more details, see gdata_picasaweb_service_query_files(), which is the synchronous version of this function, and gdata_service_query_async(),
  * which is the base asynchronous query function.
  *
- * Since: 0.8.0
+ * Since: 0.9.1
  **/
 void
 gdata_picasaweb_service_query_files_async (GDataPicasaWebService *self, GDataPicasaWebAlbum *album, GDataQuery *query, GCancellable *cancellable,
-                                           GDataQueryProgressCallback progress_callback, gpointer progress_user_data, GAsyncReadyCallback callback,
-                                           gpointer user_data)
+                                           GDataQueryProgressCallback progress_callback, gpointer progress_user_data,
+                                           GDestroyNotify destroy_progress_user_data, GAsyncReadyCallback callback, gpointer user_data)
 {
 	const gchar *request_uri;
 	GError *child_error = NULL;
@@ -469,7 +473,8 @@ gdata_picasaweb_service_query_files_async (GDataPicasaWebService *self, GDataPic
 	}
 
 	gdata_service_query_async (GDATA_SERVICE (self), get_picasaweb_authorization_domain (), request_uri, GDATA_QUERY (query),
-	                           GDATA_TYPE_PICASAWEB_FILE, cancellable, progress_callback, progress_user_data, callback, user_data);
+	                           GDATA_TYPE_PICASAWEB_FILE, cancellable, progress_callback, progress_user_data, destroy_progress_user_data,
+	                           callback, user_data);
 }
 
 /**
diff --git a/gdata/services/picasaweb/gdata-picasaweb-service.h b/gdata/services/picasaweb/gdata-picasaweb-service.h
index 72e1545..b5eddec 100644
--- a/gdata/services/picasaweb/gdata-picasaweb-service.h
+++ b/gdata/services/picasaweb/gdata-picasaweb-service.h
@@ -77,6 +77,7 @@ GDataFeed *gdata_picasaweb_service_query_all_albums (GDataPicasaWebService *self
                                                      GError **error) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
 void gdata_picasaweb_service_query_all_albums_async (GDataPicasaWebService *self, GDataQuery *query, const gchar *username, GCancellable *cancellable,
                                                      GDataQueryProgressCallback progress_callback, gpointer progress_user_data,
+                                                     GDestroyNotify destroy_progress_user_data,
                                                      GAsyncReadyCallback callback, gpointer user_data);
 
 GDataFeed *gdata_picasaweb_service_query_files (GDataPicasaWebService *self, GDataPicasaWebAlbum *album, GDataQuery *query,
@@ -84,6 +85,7 @@ GDataFeed *gdata_picasaweb_service_query_files (GDataPicasaWebService *self, GDa
                                                 GError **error) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
 void gdata_picasaweb_service_query_files_async (GDataPicasaWebService *self, GDataPicasaWebAlbum *album, GDataQuery *query, GCancellable *cancellable,
                                                 GDataQueryProgressCallback progress_callback, gpointer progress_user_data,
+                                                GDestroyNotify destroy_progress_user_data,
                                                 GAsyncReadyCallback callback, gpointer user_data);
 
 #include <gdata/services/picasaweb/gdata-picasaweb-file.h>
diff --git a/gdata/services/youtube/gdata-youtube-service.c b/gdata/services/youtube/gdata-youtube-service.c
index db8df08..57bbdd3 100644
--- a/gdata/services/youtube/gdata-youtube-service.c
+++ b/gdata/services/youtube/gdata-youtube-service.c
@@ -578,13 +578,15 @@ gdata_youtube_service_query_standard_feed (GDataYouTubeService *self, GDataYouTu
 }
 
 /**
- * gdata_youtube_service_query_standard_feed_async: (skip)
+ * gdata_youtube_service_query_standard_feed_async:
  * @self: a #GDataService
  * @feed_type: the feed type to query, from #GDataYouTubeStandardFeedType
  * @query: (allow-none): a #GDataQuery with the query parameters, or %NULL
  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
  * @progress_callback: (allow-none) (closure progress_user_data): a #GDataQueryProgressCallback to call when an entry is loaded, or %NULL
  * @progress_user_data: (closure): data to pass to the @progress_callback function
+ * @destroy_progress_user_data: (allow-none): the function to call when @progress_callback will not be called any more, or %NULL. This function will be
+ * called with @progress_user_data as a parameter and can be used to free any memory allocated for it.
  * @callback: a #GAsyncReadyCallback to call when authentication is finished
  * @user_data: (closure): data to pass to the @callback function
  *
@@ -595,10 +597,13 @@ gdata_youtube_service_query_standard_feed (GDataYouTubeService *self, GDataYouTu
  *
  * When the operation is finished, @callback will be called. You can then call gdata_service_query_finish()
  * to get the results of the operation.
+ *
+ * Since: 0.9.1
  **/
 void
 gdata_youtube_service_query_standard_feed_async (GDataYouTubeService *self, GDataYouTubeStandardFeedType feed_type, GDataQuery *query,
                                                  GCancellable *cancellable, GDataQueryProgressCallback progress_callback, gpointer progress_user_data,
+                                                 GDestroyNotify destroy_progress_user_data,
                                                  GAsyncReadyCallback callback, gpointer user_data)
 {
 	g_return_if_fail (GDATA_IS_YOUTUBE_SERVICE (self));
@@ -607,7 +612,8 @@ gdata_youtube_service_query_standard_feed_async (GDataYouTubeService *self, GDat
 	g_return_if_fail (callback != NULL);
 
 	gdata_service_query_async (GDATA_SERVICE (self), get_youtube_authorization_domain (), standard_feed_type_to_feed_uri (feed_type), query,
-	                           GDATA_TYPE_YOUTUBE_VIDEO, cancellable, progress_callback, progress_user_data, callback, user_data);
+	                           GDATA_TYPE_YOUTUBE_VIDEO, cancellable, progress_callback, progress_user_data, destroy_progress_user_data,
+	                           callback, user_data);
 }
 
 /**
@@ -641,12 +647,14 @@ gdata_youtube_service_query_videos (GDataYouTubeService *self, GDataQuery *query
 }
 
 /**
- * gdata_youtube_service_query_videos_async: (skip)
+ * gdata_youtube_service_query_videos_async:
  * @self: a #GDataService
  * @query: (allow-none): a #GDataQuery with the query parameters, or %NULL
  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
  * @progress_callback: (allow-none) (closure progress_user_data): a #GDataQueryProgressCallback to call when an entry is loaded, or %NULL
  * @progress_user_data: (closure): data to pass to the @progress_callback function
+ * @destroy_progress_user_data: (allow-none): the function to call when @progress_callback will not be called any more, or %NULL. This function will be
+ * called with @progress_user_data as a parameter and can be used to free any memory allocated for it.
  * @callback: a #GAsyncReadyCallback to call when authentication is finished
  * @user_data: (closure): data to pass to the @callback function
  *
@@ -657,10 +665,13 @@ gdata_youtube_service_query_videos (GDataYouTubeService *self, GDataQuery *query
  *
  * When the operation is finished, @callback will be called. You can then call gdata_service_query_finish()
  * to get the results of the operation.
+ *
+ * Since: 0.9.1
  **/
 void
 gdata_youtube_service_query_videos_async (GDataYouTubeService *self, GDataQuery *query,
                                           GCancellable *cancellable, GDataQueryProgressCallback progress_callback, gpointer progress_user_data,
+                                          GDestroyNotify destroy_progress_user_data,
                                           GAsyncReadyCallback callback, gpointer user_data)
 {
 	g_return_if_fail (GDATA_IS_YOUTUBE_SERVICE (self));
@@ -669,7 +680,8 @@ gdata_youtube_service_query_videos_async (GDataYouTubeService *self, GDataQuery
 	g_return_if_fail (callback != NULL);
 
 	gdata_service_query_async (GDATA_SERVICE (self), get_youtube_authorization_domain (), "https://gdata.youtube.com/feeds/api/videos";, query,
-	                           GDATA_TYPE_YOUTUBE_VIDEO, cancellable, progress_callback, progress_user_data, callback, user_data);
+	                           GDATA_TYPE_YOUTUBE_VIDEO, cancellable, progress_callback, progress_user_data, destroy_progress_user_data,
+	                           callback, user_data);
 }
 
 /**
@@ -723,13 +735,15 @@ gdata_youtube_service_query_related (GDataYouTubeService *self, GDataYouTubeVide
 }
 
 /**
- * gdata_youtube_service_query_related_async: (skip)
+ * gdata_youtube_service_query_related_async:
  * @self: a #GDataService
  * @video: a #GDataYouTubeVideo for which to find related videos
  * @query: (allow-none): a #GDataQuery with the query parameters, or %NULL
  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
  * @progress_callback: (allow-none) (closure progress_user_data): a #GDataQueryProgressCallback to call when an entry is loaded, or %NULL
  * @progress_user_data: (closure): data to pass to the @progress_callback function
+ * @destroy_progress_user_data: (allow-none): the function to call when @progress_callback will not be called any more, or %NULL. This function will be
+ * called with @progress_user_data as a parameter and can be used to free any memory allocated for it.
  * @callback: a #GAsyncReadyCallback to call when authentication is finished
  * @user_data: (closure): data to pass to the @callback function
  *
@@ -740,10 +754,13 @@ gdata_youtube_service_query_related (GDataYouTubeService *self, GDataYouTubeVide
  *
  * When the operation is finished, @callback will be called. You can then call gdata_service_query_finish()
  * to get the results of the operation.
+ *
+ * Since: 0.9.1
  **/
 void
 gdata_youtube_service_query_related_async (GDataYouTubeService *self, GDataYouTubeVideo *video, GDataQuery *query,
                                            GCancellable *cancellable, GDataQueryProgressCallback progress_callback, gpointer progress_user_data,
+                                           GDestroyNotify destroy_progress_user_data,
                                            GAsyncReadyCallback callback, gpointer user_data)
 {
 	GDataLink *related_link;
@@ -767,7 +784,8 @@ gdata_youtube_service_query_related_async (GDataYouTubeService *self, GDataYouTu
 
 	uri = _gdata_service_fix_uri_scheme (gdata_link_get_uri (related_link));
 	gdata_service_query_async (GDATA_SERVICE (self), get_youtube_authorization_domain (), uri, query,
-	                           GDATA_TYPE_YOUTUBE_VIDEO, cancellable, progress_callback, progress_user_data, callback, user_data);
+	                           GDATA_TYPE_YOUTUBE_VIDEO, cancellable, progress_callback, progress_user_data,
+	                           destroy_progress_user_data, callback, user_data);
 	g_free (uri);
 }
 
diff --git a/gdata/services/youtube/gdata-youtube-service.h b/gdata/services/youtube/gdata-youtube-service.h
index 102dab5..4a4f534 100644
--- a/gdata/services/youtube/gdata-youtube-service.h
+++ b/gdata/services/youtube/gdata-youtube-service.h
@@ -118,6 +118,7 @@ GDataFeed *gdata_youtube_service_query_standard_feed (GDataYouTubeService *self,
 void gdata_youtube_service_query_standard_feed_async (GDataYouTubeService *self, GDataYouTubeStandardFeedType feed_type, GDataQuery *query,
                                                       GCancellable *cancellable,
                                                       GDataQueryProgressCallback progress_callback, gpointer progress_user_data,
+                                                      GDestroyNotify destroy_progress_user_data,
                                                       GAsyncReadyCallback callback, gpointer user_data);
 
 GDataFeed *gdata_youtube_service_query_videos (GDataYouTubeService *self, GDataQuery *query,
@@ -125,6 +126,7 @@ GDataFeed *gdata_youtube_service_query_videos (GDataYouTubeService *self, GDataQ
                                                GError **error) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
 void gdata_youtube_service_query_videos_async (GDataYouTubeService *self, GDataQuery *query,
                                                GCancellable *cancellable, GDataQueryProgressCallback progress_callback, gpointer progress_user_data,
+                                               GDestroyNotify destroy_progress_user_data,
                                                GAsyncReadyCallback callback, gpointer user_data);
 
 GDataFeed *gdata_youtube_service_query_related (GDataYouTubeService *self, GDataYouTubeVideo *video, GDataQuery *query,
@@ -132,6 +134,7 @@ GDataFeed *gdata_youtube_service_query_related (GDataYouTubeService *self, GData
                                                 GError **error) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
 void gdata_youtube_service_query_related_async (GDataYouTubeService *self, GDataYouTubeVideo *video, GDataQuery *query,
                                                 GCancellable *cancellable, GDataQueryProgressCallback progress_callback, gpointer progress_user_data,
+                                                GDestroyNotify destroy_progress_user_data,
                                                 GAsyncReadyCallback callback, gpointer user_data);
 
 GDataUploadStream *gdata_youtube_service_upload_video (GDataYouTubeService *self, GDataYouTubeVideo *video, const gchar *slug,
diff --git a/gdata/tests/calendar.c b/gdata/tests/calendar.c
index 3bb7b85..b6f8fa0 100644
--- a/gdata/tests/calendar.c
+++ b/gdata/tests/calendar.c
@@ -157,13 +157,36 @@ test_query_all_calendars_async (gconstpointer service)
 	GMainLoop *main_loop = g_main_loop_new (NULL, TRUE);
 
 	gdata_calendar_service_query_all_calendars_async (GDATA_CALENDAR_SERVICE (service), NULL, NULL, NULL,
-							  NULL, (GAsyncReadyCallback) test_query_all_calendars_async_cb, main_loop);
+							  NULL, NULL, (GAsyncReadyCallback) test_query_all_calendars_async_cb, main_loop);
 
 	g_main_loop_run (main_loop);
 	g_main_loop_unref (main_loop);
 }
 
 static void
+test_query_all_calendars_async_progress_closure (gconstpointer service)
+{
+	GDataAsyncProgressClosure *data = g_slice_new0 (GDataAsyncProgressClosure);
+
+	g_assert (service != NULL);
+
+	data->main_loop = g_main_loop_new (NULL, TRUE);
+
+	gdata_calendar_service_query_all_calendars_async (GDATA_CALENDAR_SERVICE (service), NULL, NULL,
+	                                                  (GDataQueryProgressCallback) gdata_test_async_progress_callback,
+	                                                  data, (GDestroyNotify) gdata_test_async_progress_closure_free,
+	                                                  (GAsyncReadyCallback) gdata_test_async_progress_finish_callback, data);
+	g_main_loop_run (data->main_loop);
+	g_main_loop_unref (data->main_loop);
+
+	/* Check that both callbacks were called exactly once */
+	g_assert_cmpuint (data->progress_destroy_notify_count, ==, 1);
+	g_assert_cmpuint (data->async_ready_notify_count, ==, 1);
+
+	g_slice_free (GDataAsyncProgressClosure, data);
+}
+
+static void
 test_query_own_calendars (gconstpointer service)
 {
 	GDataFeed *feed;
@@ -202,13 +225,36 @@ test_query_own_calendars_async (gconstpointer service)
 	GMainLoop *main_loop = g_main_loop_new (NULL, TRUE);
 
 	gdata_calendar_service_query_own_calendars_async (GDATA_CALENDAR_SERVICE (service), NULL, NULL, NULL,
-							  NULL, (GAsyncReadyCallback) test_query_own_calendars_async_cb, main_loop);
+							  NULL, NULL, (GAsyncReadyCallback) test_query_own_calendars_async_cb, main_loop);
 
 	g_main_loop_run (main_loop);
 	g_main_loop_unref (main_loop);
 }
 
 static void
+test_query_own_calendars_async_progress_closure (gconstpointer service)
+{
+	GDataAsyncProgressClosure *data = g_slice_new0 (GDataAsyncProgressClosure);
+
+	g_assert (service != NULL);
+
+	data->main_loop = g_main_loop_new (NULL, TRUE);
+
+	gdata_calendar_service_query_own_calendars_async (GDATA_CALENDAR_SERVICE (service), NULL, NULL,
+	                                               (GDataQueryProgressCallback) gdata_test_async_progress_callback,
+	                                               data, (GDestroyNotify) gdata_test_async_progress_closure_free,
+	                                               (GAsyncReadyCallback) gdata_test_async_progress_finish_callback, data);
+	g_main_loop_run (data->main_loop);
+	g_main_loop_unref (data->main_loop);
+
+	/* Check that both callbacks were called exactly once */
+	g_assert_cmpuint (data->progress_destroy_notify_count, ==, 1);
+	g_assert_cmpuint (data->async_ready_notify_count, ==, 1);
+
+	g_slice_free (GDataAsyncProgressClosure, data);
+}
+
+static void
 test_query_events (gconstpointer service)
 {
 	GDataFeed *feed;
@@ -255,7 +301,7 @@ test_query_events_async (gconstpointer service)
 	calendar = get_calendar (service, &error);
 	main_loop = g_main_loop_new (NULL, TRUE);
 
-	gdata_calendar_service_query_events_async (GDATA_CALENDAR_SERVICE (service), calendar, NULL, NULL, NULL, NULL,
+	gdata_calendar_service_query_events_async (GDATA_CALENDAR_SERVICE (service), calendar, NULL, NULL, NULL, NULL, NULL,
 	                                           (GAsyncReadyCallback) test_query_events_async_cb, main_loop);
 	g_main_loop_run (main_loop);
 
@@ -264,6 +310,33 @@ test_query_events_async (gconstpointer service)
 }
 
 static void
+test_query_events_async_progress_closure (gconstpointer service)
+{
+	GDataAsyncProgressClosure *data = g_slice_new0 (GDataAsyncProgressClosure);
+	GDataCalendarCalendar *calendar;
+	GError *error = NULL;
+
+	g_assert (service != NULL);
+
+	calendar = get_calendar (service, &error);
+	data->main_loop = g_main_loop_new (NULL, TRUE);
+
+	gdata_calendar_service_query_events_async (GDATA_CALENDAR_SERVICE (service), calendar, NULL, NULL,
+	                                           (GDataQueryProgressCallback) gdata_test_async_progress_callback,
+	                                           data, (GDestroyNotify) gdata_test_async_progress_closure_free,
+	                                           (GAsyncReadyCallback) gdata_test_async_progress_finish_callback, data);
+	g_main_loop_run (data->main_loop);
+	g_main_loop_unref (data->main_loop);
+	g_object_unref (calendar);
+
+	/* Check that both callbacks were called exactly once */
+	g_assert_cmpuint (data->progress_destroy_notify_count, ==, 1);
+	g_assert_cmpuint (data->async_ready_notify_count, ==, 1);
+
+	g_slice_free (GDataAsyncProgressClosure, data);
+}
+
+static void
 test_insert_simple (gconstpointer service)
 {
 	GDataCalendarEvent *event, *new_event;
@@ -1127,10 +1200,13 @@ main (int argc, char *argv[])
 
 		g_test_add_data_func ("/calendar/query/all_calendars", service, test_query_all_calendars);
 		g_test_add_data_func ("/calendar/query/all_calendars_async", service, test_query_all_calendars_async);
+		g_test_add_data_func ("/calendar/query/all_calendars_async_progress_closure", service, test_query_all_calendars_async_progress_closure);
 		g_test_add_data_func ("/calendar/query/own_calendars", service, test_query_own_calendars);
 		g_test_add_data_func ("/calendar/query/own_calendars_async", service, test_query_own_calendars_async);
+		g_test_add_data_func ("/calendar/query/own_calendars_async_progress_closure", service, test_query_own_calendars_async_progress_closure);
 		g_test_add_data_func ("/calendar/query/events", service, test_query_events);
 		g_test_add_data_func ("/calendar/query/events_async", service, test_query_events_async);
+		g_test_add_data_func ("/calendar/query/events_async_progress_closure", service, test_query_events_async_progress_closure);
 
 		g_test_add_data_func ("/calendar/insert/simple", service, test_insert_simple);
 		g_test_add_data_func ("/calendar/insert/simple/async", service, test_insert_simple_async);
diff --git a/gdata/tests/common.c b/gdata/tests/common.c
index 4b1ce39..6aedaec 100644
--- a/gdata/tests/common.c
+++ b/gdata/tests/common.c
@@ -566,3 +566,29 @@ gdata_test_compare_xml (GDataParsable *parsable, const gchar *expected_xml, gboo
 
 	return success;
 }
+
+/* Common code for tests of async query functions that have progress callbacks */
+
+void
+gdata_test_async_progress_callback (GDataEntry *entry, guint entry_key, guint entry_count, GDataAsyncProgressClosure *data)
+{
+    /* No-op */
+}
+
+void
+gdata_test_async_progress_closure_free (GDataAsyncProgressClosure *data)
+{
+    /* Check that this callback is called first */
+    g_assert_cmpuint (data->async_ready_notify_count, ==, 0);
+    data->progress_destroy_notify_count++;
+}
+
+void
+gdata_test_async_progress_finish_callback (GObject *service, GAsyncResult *res, GDataAsyncProgressClosure *data)
+{
+    /* Check that this callback is called second */
+    g_assert_cmpuint (data->progress_destroy_notify_count, ==, 1);
+    data->async_ready_notify_count++;
+
+    g_main_loop_quit (data->main_loop);
+}
diff --git a/gdata/tests/common.h b/gdata/tests/common.h
index 7f17c25..1efe06f 100644
--- a/gdata/tests/common.h
+++ b/gdata/tests/common.h
@@ -62,6 +62,16 @@ gboolean gdata_test_compare_xml (GDataParsable *parsable, const gchar *expected_
 		g_assert (_test_success == TRUE); \
 	} G_STMT_END
 
+/* Common code for tests of async query functions that have progress callbacks */
+typedef struct {
+    guint progress_destroy_notify_count;
+    guint async_ready_notify_count;
+    GMainLoop *main_loop;
+} GDataAsyncProgressClosure;
+void gdata_test_async_progress_callback (GDataEntry *entry, guint entry_key, guint entry_count, GDataAsyncProgressClosure *data);
+void gdata_test_async_progress_closure_free (GDataAsyncProgressClosure *data);
+void gdata_test_async_progress_finish_callback (GObject *service, GAsyncResult *res, GDataAsyncProgressClosure *data);
+
 G_END_DECLS
 
 #endif /* !GDATA_TEST_COMMON_H */
diff --git a/gdata/tests/contacts.c b/gdata/tests/contacts.c
index 2732d86..eb8bf08 100644
--- a/gdata/tests/contacts.c
+++ b/gdata/tests/contacts.c
@@ -181,13 +181,36 @@ test_query_all_contacts_async (gconstpointer service)
 	GMainLoop *main_loop = g_main_loop_new (NULL, TRUE);
 
 	gdata_contacts_service_query_contacts_async (GDATA_CONTACTS_SERVICE (service), NULL, NULL, NULL,
-						     NULL, (GAsyncReadyCallback) test_query_all_contacts_async_cb, main_loop);
+						     NULL, NULL, (GAsyncReadyCallback) test_query_all_contacts_async_cb, main_loop);
 
 	g_main_loop_run (main_loop);
 	g_main_loop_unref (main_loop);
 }
 
 static void
+test_query_all_contacts_async_progress_closure (gconstpointer service)
+{
+	GDataAsyncProgressClosure *data = g_slice_new0 (GDataAsyncProgressClosure);
+
+	g_assert (service != NULL);
+
+	data->main_loop = g_main_loop_new (NULL, TRUE);
+
+	gdata_contacts_service_query_contacts_async (GDATA_CONTACTS_SERVICE (service), NULL, NULL,
+	                                             (GDataQueryProgressCallback) gdata_test_async_progress_callback,
+	                                             data, (GDestroyNotify) gdata_test_async_progress_closure_free,
+	                                             (GAsyncReadyCallback) gdata_test_async_progress_finish_callback, data);
+	g_main_loop_run (data->main_loop);
+	g_main_loop_unref (data->main_loop);
+
+	/* Check that both callbacks were called exactly once */
+	g_assert_cmpuint (data->progress_destroy_notify_count, ==, 1);
+	g_assert_cmpuint (data->async_ready_notify_count, ==, 1);
+
+	g_slice_free (GDataAsyncProgressClosure, data);
+}
+
+static void
 test_insert_simple (gconstpointer service)
 {
 	GDataContactsContact *contact, *new_contact;
@@ -694,7 +717,7 @@ test_query_all_groups_async (gconstpointer service)
 {
 	GMainLoop *main_loop = g_main_loop_new (NULL, TRUE);
 
-	gdata_contacts_service_query_groups_async (GDATA_CONTACTS_SERVICE (service), NULL, NULL, NULL, NULL,
+	gdata_contacts_service_query_groups_async (GDATA_CONTACTS_SERVICE (service), NULL, NULL, NULL, NULL, NULL,
 	                                           (GAsyncReadyCallback) test_query_all_groups_async_cb, main_loop);
 
 	g_main_loop_run (main_loop);
@@ -702,6 +725,29 @@ test_query_all_groups_async (gconstpointer service)
 }
 
 static void
+test_query_all_groups_async_progress_closure (gconstpointer service)
+{
+	GDataAsyncProgressClosure *data = g_slice_new0 (GDataAsyncProgressClosure);
+
+	g_assert (service != NULL);
+
+	data->main_loop = g_main_loop_new (NULL, TRUE);
+
+	gdata_contacts_service_query_groups_async (GDATA_CONTACTS_SERVICE (service), NULL, NULL,
+	                                           (GDataQueryProgressCallback) gdata_test_async_progress_callback,
+	                                           data, (GDestroyNotify) gdata_test_async_progress_closure_free,
+	                                           (GAsyncReadyCallback) gdata_test_async_progress_finish_callback, data);
+	g_main_loop_run (data->main_loop);
+	g_main_loop_unref (data->main_loop);
+
+	/* Check that both callbacks were called exactly once */
+	g_assert_cmpuint (data->progress_destroy_notify_count, ==, 1);
+	g_assert_cmpuint (data->async_ready_notify_count, ==, 1);
+
+	g_slice_free (GDataAsyncProgressClosure, data);
+}
+
+static void
 test_insert_group (gconstpointer service)
 {
 	GDataContactsGroup *group, *new_group;
@@ -2117,6 +2163,7 @@ main (int argc, char *argv[])
 
 		g_test_add_data_func ("/contacts/query/all_contacts", service, test_query_all_contacts);
 		g_test_add_data_func ("/contacts/query/all_contacts_async", service, test_query_all_contacts_async);
+		g_test_add_data_func ("/contacts/query/all_contacts_async_progress_closure", service, test_query_all_contacts_async_progress_closure);
 
 		g_test_add_data_func ("/contacts/photo/has_photo", service, test_photo_has_photo);
 		g_test_add_data_func ("/contacts/photo/add", service, test_photo_add);
@@ -2133,6 +2180,7 @@ main (int argc, char *argv[])
 
 		g_test_add_data_func ("/contacts/groups/query", service, test_query_all_groups);
 		g_test_add_data_func ("/contacts/groups/query_async", service, test_query_all_groups_async);
+		g_test_add_data_func ("/contacts/groups/query_async_progress_closure", service, test_query_all_groups_async_progress_closure);
 		g_test_add_data_func ("/contacts/groups/insert", service, test_insert_group);
 		g_test_add_data_func ("/contacts/groups/insert_async", service, test_insert_group_async);
 	}
diff --git a/gdata/tests/documents.c b/gdata/tests/documents.c
index 310b022..9692eb3 100644
--- a/gdata/tests/documents.c
+++ b/gdata/tests/documents.c
@@ -226,7 +226,7 @@ test_query_all_documents_async (gconstpointer service)
 
 	g_assert (service != NULL);
 
-	gdata_documents_service_query_documents_async (GDATA_DOCUMENTS_SERVICE (service), NULL, NULL, NULL,
+	gdata_documents_service_query_documents_async (GDATA_DOCUMENTS_SERVICE (service), NULL, NULL, NULL, NULL,
 						     NULL, (GAsyncReadyCallback) test_query_all_documents_async_cb, main_loop);
 
 	g_main_loop_run (main_loop);
@@ -234,6 +234,29 @@ test_query_all_documents_async (gconstpointer service)
 }
 
 static void
+test_query_all_documents_async_progress_closure (gconstpointer service)
+{
+	GDataAsyncProgressClosure *data = g_slice_new0 (GDataAsyncProgressClosure);
+
+	g_assert (service != NULL);
+
+	data->main_loop = g_main_loop_new (NULL, TRUE);
+
+	gdata_documents_service_query_documents_async (GDATA_DOCUMENTS_SERVICE (service), NULL, NULL,
+	                                               (GDataQueryProgressCallback) gdata_test_async_progress_callback,
+	                                               data, (GDestroyNotify) gdata_test_async_progress_closure_free,
+	                                               (GAsyncReadyCallback) gdata_test_async_progress_finish_callback, data);
+	g_main_loop_run (data->main_loop);
+	g_main_loop_unref (data->main_loop);
+
+	/* Check that both callbacks were called exactly once */
+	g_assert_cmpuint (data->progress_destroy_notify_count, ==, 1);
+	g_assert_cmpuint (data->async_ready_notify_count, ==, 1);
+
+	g_slice_free (GDataAsyncProgressClosure, data);
+}
+
+static void
 test_upload_metadata (gconstpointer service)
 {
 	GDataDocumentsEntry *document, *new_document;
@@ -1467,6 +1490,7 @@ main (int argc, char *argv[])
 		g_test_add_data_func ("/documents/query/all_documents_with_folder", service, test_query_all_documents_with_folder);
 		g_test_add_data_func ("/documents/query/all_documents", service, test_query_all_documents);
 		g_test_add_data_func ("/documents/query/all_documents_async", service, test_query_all_documents_async);
+		g_test_add_data_func ("/documents/query/all_documents_async_progress_closure", service, test_query_all_documents_async_progress_closure);
 
 		g_test_add ("/documents/folders/add_to_folder", FoldersData, service, setup_folders_add_to_folder,
 		            test_folders_add_to_folder, teardown_folders_add_to_folder);
diff --git a/gdata/tests/picasaweb.c b/gdata/tests/picasaweb.c
index 2014a10..373a711 100644
--- a/gdata/tests/picasaweb.c
+++ b/gdata/tests/picasaweb.c
@@ -575,7 +575,7 @@ test_photo_async (gconstpointer service)
 
 	main_loop = g_main_loop_new (NULL, TRUE);
 
-	gdata_picasaweb_service_query_files_async (GDATA_PICASAWEB_SERVICE (service), album, NULL, NULL, NULL, NULL,
+	gdata_picasaweb_service_query_files_async (GDATA_PICASAWEB_SERVICE (service), album, NULL, NULL, NULL, NULL, NULL,
 	                                           (GAsyncReadyCallback) test_photo_async_cb, main_loop);
 
 	g_main_loop_run (main_loop);
@@ -584,6 +584,45 @@ test_photo_async (gconstpointer service)
 }
 
 static void
+test_photo_async_progress_closure (gconstpointer service)
+{
+	GDataAsyncProgressClosure *data = g_slice_new0 (GDataAsyncProgressClosure);
+	GDataFeed *album_feed;
+	GDataEntry *entry;
+	GDataPicasaWebAlbum *album;
+	GList *albums;
+	GError *error = NULL;
+
+	g_assert (service != NULL);
+
+	/* Find an album */
+	album_feed = gdata_picasaweb_service_query_all_albums (GDATA_PICASAWEB_SERVICE (service), NULL, NULL, NULL, NULL, NULL, &error);
+	g_assert_no_error (error);
+	g_assert (GDATA_IS_FEED (album_feed));
+	g_clear_error (&error);
+
+	albums = gdata_feed_get_entries (album_feed);
+	entry = GDATA_ENTRY (g_list_nth_data (albums, TEST_ALBUM_INDEX));
+	album = GDATA_PICASAWEB_ALBUM (entry);
+
+	data->main_loop = g_main_loop_new (NULL, TRUE);
+
+	gdata_picasaweb_service_query_files_async (GDATA_PICASAWEB_SERVICE (service), album, NULL, NULL,
+	                                           (GDataQueryProgressCallback) gdata_test_async_progress_callback,
+	                                           data, (GDestroyNotify) gdata_test_async_progress_closure_free,
+	                                           (GAsyncReadyCallback) gdata_test_async_progress_finish_callback, data);
+	g_main_loop_run (data->main_loop);
+	g_main_loop_unref (data->main_loop);
+	g_object_unref (album_feed);
+
+	/* Check that both callbacks were called exactly once */
+	g_assert_cmpuint (data->progress_destroy_notify_count, ==, 1);
+	g_assert_cmpuint (data->async_ready_notify_count, ==, 1);
+
+	g_slice_free (GDataAsyncProgressClosure, data);
+}
+
+static void
 test_album (gconstpointer service)
 {
 	GDataFeed *album_feed;
@@ -1003,12 +1042,35 @@ test_query_all_albums_async (gconstpointer service)
 	GMainLoop *main_loop = g_main_loop_new (NULL, TRUE);
 
 	gdata_picasaweb_service_query_all_albums_async (GDATA_PICASAWEB_SERVICE (service), NULL, NULL, NULL, NULL,
-							NULL, (GAsyncReadyCallback) test_query_all_albums_async_cb, main_loop);
+							NULL, NULL, (GAsyncReadyCallback) test_query_all_albums_async_cb, main_loop);
 
 	g_main_loop_run (main_loop);
 	g_main_loop_unref (main_loop);
 }
 
+static void
+test_query_all_albums_async_progress_closure (gconstpointer service)
+{
+	GDataAsyncProgressClosure *data = g_slice_new0 (GDataAsyncProgressClosure);
+
+	g_assert (service != NULL);
+
+	data->main_loop = g_main_loop_new (NULL, TRUE);
+
+	gdata_picasaweb_service_query_all_albums_async (GDATA_PICASAWEB_SERVICE (service), NULL, NULL, NULL,
+	                                                (GDataQueryProgressCallback) gdata_test_async_progress_callback,
+	                                                data, (GDestroyNotify) gdata_test_async_progress_closure_free,
+	                                                (GAsyncReadyCallback) gdata_test_async_progress_finish_callback, data);
+	g_main_loop_run (data->main_loop);
+	g_main_loop_unref (data->main_loop);
+
+	/* Check that both callbacks were called exactly once */
+	g_assert_cmpuint (data->progress_destroy_notify_count, ==, 1);
+	g_assert_cmpuint (data->async_ready_notify_count, ==, 1);
+
+	g_slice_free (GDataAsyncProgressClosure, data);
+}
+
 typedef struct {
 	GDataPicasaWebService *service;
 	GDataPicasaWebFile *photo;
@@ -1457,6 +1519,7 @@ main (int argc, char *argv[])
 		g_test_add_data_func ("/picasaweb/query/all_albums", service, test_query_all_albums);
 		g_test_add_data_func ("/picasaweb/query/user", service, test_query_user);
 		g_test_add_data_func ("/picasaweb/query/all_albums_async", service, test_query_all_albums_async);
+		g_test_add_data_func ("/picasaweb/query/all_albums_async_progress_closure", service, test_query_all_albums_async_progress_closure);
 		g_test_add_data_func ("/picasaweb/query/new_with_limits", service, test_query_new_with_limits);
 		g_test_add_data_func ("/picasaweb/query/album_feed", service, test_album_feed);
 		g_test_add_data_func ("/picasaweb/query/album_feed_entry", service, test_album_feed_entry);
@@ -1470,6 +1533,7 @@ main (int argc, char *argv[])
 		g_test_add_data_func ("/picasaweb/query/photo", service, test_photo);
 		g_test_add_data_func ("/picasaweb/query/photo_single", service, test_photo_single);
 		g_test_add_data_func ("/picasaweb/query/photo/async", service, test_photo_async);
+		g_test_add_data_func ("/picasaweb/query/photo/async_progress_closure", service, test_photo_async_progress_closure);
 
 		g_test_add ("/picasaweb/upload/default_album", UploadData, service, setup_upload, test_upload_default_album, teardown_upload);
 		g_test_add ("/picasaweb/upload/default_album/async", UploadAsyncData, service, setup_upload_async, test_upload_default_album_async,
diff --git a/gdata/tests/youtube.c b/gdata/tests/youtube.c
index 95adc3d..1315755 100644
--- a/gdata/tests/youtube.c
+++ b/gdata/tests/youtube.c
@@ -148,13 +148,36 @@ test_query_standard_feed_async (gconstpointer service)
 {
 	GMainLoop *main_loop = g_main_loop_new (NULL, TRUE);
 
-	gdata_youtube_service_query_standard_feed_async (GDATA_YOUTUBE_SERVICE (service), GDATA_YOUTUBE_TOP_RATED_FEED, NULL,
+	gdata_youtube_service_query_standard_feed_async (GDATA_YOUTUBE_SERVICE (service), GDATA_YOUTUBE_TOP_RATED_FEED, NULL, NULL,
 							 NULL, NULL, NULL, (GAsyncReadyCallback) test_query_standard_feed_async_cb, main_loop);
 
 	g_main_loop_run (main_loop);
 	g_main_loop_unref (main_loop);
 }
 
+static void
+test_query_standard_feed_async_progress_closure (gconstpointer service)
+{
+	GDataAsyncProgressClosure *data = g_slice_new0 (GDataAsyncProgressClosure);
+
+	g_assert (service != NULL);
+
+	data->main_loop = g_main_loop_new (NULL, TRUE);
+
+	gdata_youtube_service_query_standard_feed_async (GDATA_YOUTUBE_SERVICE (service), GDATA_YOUTUBE_TOP_RATED_FEED, NULL, NULL,
+	                                                 (GDataQueryProgressCallback) gdata_test_async_progress_callback,
+	                                                 data, (GDestroyNotify) gdata_test_async_progress_closure_free,
+	                                                 (GAsyncReadyCallback) gdata_test_async_progress_finish_callback, data);
+	g_main_loop_run (data->main_loop);
+	g_main_loop_unref (data->main_loop);
+
+	/* Check that both callbacks were called exactly once */
+	g_assert_cmpuint (data->progress_destroy_notify_count, ==, 1);
+	g_assert_cmpuint (data->async_ready_notify_count, ==, 1);
+
+	g_slice_free (GDataAsyncProgressClosure, data);
+}
+
 static GDataYouTubeVideo *
 get_video_for_related (void)
 {
@@ -268,13 +291,40 @@ test_query_related_async (gconstpointer service)
 
 	video = get_video_for_related ();
 	gdata_youtube_service_query_related_async (GDATA_YOUTUBE_SERVICE (service), video, NULL, NULL, NULL,
-						   NULL, (GAsyncReadyCallback) test_query_related_async_cb, main_loop);
+						   NULL, NULL, (GAsyncReadyCallback) test_query_related_async_cb, main_loop);
 	g_object_unref (video);
 
 	g_main_loop_run (main_loop);
 	g_main_loop_unref (main_loop);
 }
 
+static void
+test_query_related_async_progress_closure (gconstpointer service)
+{
+	GDataAsyncProgressClosure *data = g_slice_new0 (GDataAsyncProgressClosure);
+	GDataYouTubeVideo *video;
+
+	g_assert (service != NULL);
+
+	data->main_loop = g_main_loop_new (NULL, TRUE);
+	video = get_video_for_related ();
+
+	gdata_youtube_service_query_related_async (GDATA_YOUTUBE_SERVICE (service), video, NULL, NULL,
+	                                           (GDataQueryProgressCallback) gdata_test_async_progress_callback,
+	                                           data, (GDestroyNotify) gdata_test_async_progress_closure_free,
+	                                           (GAsyncReadyCallback) gdata_test_async_progress_finish_callback, data);
+	g_object_unref (video);
+
+	g_main_loop_run (data->main_loop);
+	g_main_loop_unref (data->main_loop);
+
+	/* Check that both callbacks were called exactly once */
+	g_assert_cmpuint (data->progress_destroy_notify_count, ==, 1);
+	g_assert_cmpuint (data->async_ready_notify_count, ==, 1);
+
+	g_slice_free (GDataAsyncProgressClosure, data);
+}
+
 typedef struct {
 	GDataYouTubeService *service;
 	GDataYouTubeVideo *video;
@@ -1459,8 +1509,10 @@ main (int argc, char *argv[])
 
 		g_test_add_data_func ("/youtube/query/standard_feed", service, test_query_standard_feed);
 		g_test_add_data_func ("/youtube/query/standard_feed_async", service, test_query_standard_feed_async);
+		g_test_add_data_func ("/youtube/query/standard_feed_async_progress_closure", service, test_query_standard_feed_async_progress_closure);
 		g_test_add_data_func ("/youtube/query/related", service, test_query_related);
 		g_test_add_data_func ("/youtube/query/related_async", service, test_query_related_async);
+		g_test_add_data_func ("/youtube/query/related_async_progress_closure", service, test_query_related_async_progress_closure);
 
 		g_test_add ("/youtube/upload/simple", UploadData, service, setup_upload, test_upload_simple, teardown_upload);
 		g_test_add ("/youtube/upload/async", UploadAsyncData, service, setup_upload_async, test_upload_async, teardown_upload_async);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]