[grilo/0.1.x] core: introduce grilo operations



commit 8733c9c14b56cb9edb876cb979b7f3c33d21ed3b
Author: Juan A. Suarez Romero <jasuarez igalia com>
Date:   Wed Jun 29 08:47:24 2011 +0000

    core: introduce grilo operations
    
    There are several ways to make requests on grilo at the moment. You
    can either use the MediaSource API (to find medias) or the
    MetadataSource API (to find metadatas) or the Multiple API (to find
    medias on a set of media sources). Currently MediaSource and
    MetadataSource share the same API to cancel an operation, but the
    Multiple API remains different.
    
    This patch proposes to unify all the operations and allocate their ids
    at only one place. This benefits the user by making the whole API
    simpler (you no longer have to remember to how to cancel your
    operation, there is only one way to do it).
    
    This other advantage of this patch is to have a centralized place
    where to find all the ongoing operations (that led to fix a memory
    leak earlier), in the future that could help to debug stalled
    operations.
    
    Signed-off-by: Lionel Landwerlin <lionel g landwerlin linux intel com>
    Signed-off-by: Juan A. Suarez Romero <jasuarez igalia com>

 src/Makefile.am            |    5 +-
 src/grilo.c                |    4 +
 src/grilo.h                |    1 +
 src/grl-media-source.c     |   41 +++++-------
 src/grl-metadata-source.c  |  149 +++++++++++++++++++---------------------
 src/grl-metadata-source.h  |   13 ++--
 src/grl-multiple.c         |   88 +++++++++++-------------
 src/grl-multiple.h         |    2 +-
 src/grl-operation-priv.h   |   43 ++++++++++++
 src/grl-operation.c        |  162 ++++++++++++++++++++++++++++++++++++++++++++
 src/grl-operation.h        |   42 +++++++++++
 tools/grilo-test-ui/main.c |    7 +--
 12 files changed, 392 insertions(+), 165 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 5dd865a..81cf803 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -42,6 +42,7 @@ lib GRL_NAME@_la_SOURCES =					\
 	grl-plugin-registry.c					\
 	grl-metadata-key.c grl-metadata-key-priv.h		\
 	grl-metadata-source.c grl-metadata-source-priv.h	\
+	grl-operation.c grl-operation.h				\
 	grl-type-builtins.c grl-type-builtins.h			\
 	grl-marshal.c grl-marshal.h				\
 	grl-media-source.c grl-util.c				\
@@ -76,7 +77,8 @@ lib GRL_NAME@inc_HEADERS =	\
 	grl-log.h 		\
 	grl-multiple.h		\
 	grl-util.h		\
-	grl-definitions.h
+	grl-definitions.h	\
+	grl-operation.h
 
 data_h_headers =		\
 	data/grl-data.h		\
@@ -94,6 +96,7 @@ noinst_HEADERS =			\
 	grl-media-plugin-priv.h		\
 	grl-metadata-source-priv.h	\
 	grl-metadata-key-priv.h		\
+	grl-operation-priv.h		\
 	grl-sync-priv.h			\
 	grl-type-builtins.h		\
 	grl-marshal.h
diff --git a/src/grilo.c b/src/grilo.c
index 83ad940..8b3f80b 100644
--- a/src/grilo.c
+++ b/src/grilo.c
@@ -35,6 +35,7 @@
 
 #include "grilo.h"
 #include "grl-metadata-key-priv.h"
+#include "grl-operation-priv.h"
 #include "grl-log-priv.h"
 #include "config.h"
 
@@ -69,6 +70,9 @@ grl_init (gint *argc,
 
   g_type_init ();
 
+  /* Initialize operations */
+  grl_operation_init ();
+
   /* Check options */
   ctx = g_option_context_new ("- Grilo initialization");
   g_option_context_set_ignore_unknown_options (ctx, TRUE);
diff --git a/src/grilo.h b/src/grilo.h
index 6d4ab71..721031b 100644
--- a/src/grilo.h
+++ b/src/grilo.h
@@ -45,6 +45,7 @@
 #include <grl-multiple.h>
 #include <grl-util.h>
 #include <grl-definitions.h>
+#include <grl-operation.h>
 
 #undef _GRILO_H_INSIDE_
 
diff --git a/src/grl-media-source.c b/src/grl-media-source.c
index 327020f..3d4c2d0 100644
--- a/src/grl-media-source.c
+++ b/src/grl-media-source.c
@@ -41,6 +41,8 @@
 
 #include "grl-media-source.h"
 #include "grl-metadata-source-priv.h"
+#include "grl-operation.h"
+#include "grl-operation-priv.h"
 #include "grl-sync-priv.h"
 #include "data/grl-media.h"
 #include "data/grl-media-box.h"
@@ -981,8 +983,7 @@ full_resolution_check_waiting_list (GList **waiting_list,
 static void
 cancel_resolve (gpointer source, gpointer operation_id, gpointer user_data)
 {
-  grl_metadata_source_cancel (GRL_METADATA_SOURCE (source),
-                              GPOINTER_TO_UINT (operation_id));
+  grl_operation_cancel (GPOINTER_TO_UINT (operation_id));
 }
 
 static void
@@ -1415,8 +1416,7 @@ grl_media_source_browse (GrlMediaSource *source,
     relay_chained = TRUE;
   }
 
-  browse_id =
-    grl_metadata_source_gen_operation_id (GRL_METADATA_SOURCE (source));
+  browse_id = grl_operation_generate_id ();
 
   /* Always hook an own relay callback so we can do some
      post-processing before handing out the results
@@ -1618,8 +1618,7 @@ grl_media_source_search (GrlMediaSource *source,
     relay_chained = TRUE;
   }
 
-  search_id =
-    grl_metadata_source_gen_operation_id (GRL_METADATA_SOURCE (source));
+  search_id = grl_operation_generate_id ();
 
   brc = g_new0 (struct BrowseRelayCb, 1);
   brc->chained = relay_chained;
@@ -1819,8 +1818,7 @@ grl_media_source_query (GrlMediaSource *source,
     relay_chained = TRUE;
   }
 
-  query_id =
-    grl_metadata_source_gen_operation_id (GRL_METADATA_SOURCE (source));
+  query_id = grl_operation_generate_id ();
 
   brc = g_new0 (struct BrowseRelayCb, 1);
   brc->chained = relay_chained;
@@ -1984,8 +1982,7 @@ grl_media_source_metadata (GrlMediaSource *source,
                                      &_keys, FALSE);
   }
 
-  metadata_id =
-    grl_metadata_source_gen_operation_id (GRL_METADATA_SOURCE (source));
+  metadata_id = grl_operation_generate_id ();
 
   if (flags & GRL_RESOLVE_FULL) {
     struct MetadataFullResolutionCtlCb *c;
@@ -2150,7 +2147,7 @@ grl_media_source_supported_operations (GrlMetadataSource *metadata_source)
  * taken for that operation after the said callback with error has been called.
  *
  * Since: 0.1.1
- * Deprecated: 0.1.14: Use grl_metadata_source_cancel() instead
+ * Deprecated: 0.1.14: Use grl_operation_cancel() instead
  */
 void
 grl_media_source_cancel (GrlMediaSource *source, guint operation_id)
@@ -2160,9 +2157,9 @@ grl_media_source_cancel (GrlMediaSource *source, guint operation_id)
   g_return_if_fail (GRL_IS_MEDIA_SOURCE (source));
 
   GRL_WARNING ("grl_media_source_cancel() is deprecated. "
-               "Use grl_metadata_source_cancel() instead");
+               "Use grl_operation_cancel() instead");
 
-  grl_metadata_source_cancel (GRL_METADATA_SOURCE (source), operation_id);
+  grl_operation_cancel (operation_id);
 }
 
 /**
@@ -2174,7 +2171,7 @@ grl_media_source_cancel (GrlMediaSource *source, guint operation_id)
  * Attach a pointer to the specific operation.
  *
  * Since: 0.1.1
- * Deprecated: 0.1.14: Use grl_metadata_source_set_operation_data() instead
+ * Deprecated: 0.1.14: Use grl_operation_set_data() instead
  */
 void
 grl_media_source_set_operation_data (GrlMediaSource *source,
@@ -2186,11 +2183,9 @@ grl_media_source_set_operation_data (GrlMediaSource *source,
   g_return_if_fail (GRL_IS_MEDIA_SOURCE (source));
 
   GRL_WARNING ("grl_media_source_set_operation_data() is deprecated. "
-               "Use instead grl_metadata_source_set_operation_data()");
+               "Use grl_operation_set_data() instead");
 
-  grl_metadata_source_set_operation_data (GRL_METADATA_SOURCE (source),
-                                          operation_id,
-                                          data);
+  grl_operation_set_data (operation_id, data);
 }
 
 /**
@@ -2203,7 +2198,7 @@ grl_media_source_set_operation_data (GrlMediaSource *source,
  * Returns: (transfer none): The previously attached data.
  *
  * Since: 0.1.1
- * Deprecated: 0.1.14: Use grl_metadata_source_get_operation_data() instead
+ * Deprecated: 0.1.14: Use grl_operation_get_data() instead
  */
 gpointer
 grl_media_source_get_operation_data (GrlMediaSource *source,
@@ -2214,10 +2209,9 @@ grl_media_source_get_operation_data (GrlMediaSource *source,
   g_return_val_if_fail (GRL_IS_MEDIA_SOURCE (source), NULL);
 
   GRL_WARNING ("grl_metadata_source_get_operation_data() is deprecated. "
-               "Use instead grl_metadata_source_get_operation_data()");
+               "Use grl_operation_get_data() instead");
 
-  return grl_metadata_source_get_operation_data (GRL_METADATA_SOURCE (source),
-                                                 operation_id);
+  return grl_operation_get_data (operation_id);
 }
 
 /**
@@ -2543,8 +2537,7 @@ grl_media_source_get_media_from_uri (GrlMediaSource *source,
                                      &_keys, FALSE);
   }
 
-  media_from_uri_id =
-    grl_metadata_source_gen_operation_id (GRL_METADATA_SOURCE (source));
+  media_from_uri_id = grl_operation_generate_id ();
 
   /* We cannot prepare for full resolution yet because we don't
      have a GrlMedia t operate with.
diff --git a/src/grl-metadata-source.c b/src/grl-metadata-source.c
index 2373460..4d8d278 100644
--- a/src/grl-metadata-source.c
+++ b/src/grl-metadata-source.c
@@ -45,6 +45,8 @@
 
 #include "grl-metadata-source.h"
 #include "grl-metadata-source-priv.h"
+#include "grl-operation.h"
+#include "grl-operation-priv.h"
 #include "grl-sync-priv.h"
 #include "grl-plugin-registry.h"
 #include "grl-error.h"
@@ -72,7 +74,6 @@ struct _GrlMetadataSourcePrivate {
   gchar *id;
   gchar *name;
   gchar *desc;
-  GHashTable *pending_operations;
 };
 
 struct ResolveRelayCb {
@@ -95,9 +96,11 @@ struct SetMetadataCtlCb {
 };
 
 struct OperationState {
+  GrlMetadataSource *source;
+  guint              operation_id;
+
   gboolean cancelled;
   gboolean completed;
-  gpointer data;
 };
 
 static void grl_metadata_source_finalize (GObject *plugin);
@@ -132,8 +135,6 @@ grl_metadata_source_class_init (GrlMetadataSourceClass *metadata_source_class)
   metadata_source_class->supported_operations =
     grl_metadata_source_supported_operations_impl;
 
-  metadata_source_class->operation_id = 1;
-
   /**
    * GrlMetadataSource:source-id
    *
@@ -185,8 +186,6 @@ static void
 grl_metadata_source_init (GrlMetadataSource *source)
 {
   source->priv = GRL_METADATA_SOURCE_GET_PRIVATE (source);
-  source->priv->pending_operations =
-    g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
 }
 
 static void
@@ -202,8 +201,6 @@ grl_metadata_source_finalize (GObject *object)
   g_free (source->priv->name);
   g_free (source->priv->desc);
 
-  g_hash_table_unref (source->priv->pending_operations);
-
   G_OBJECT_CLASS (grl_metadata_source_parent_class)->finalize (object);
 }
 
@@ -304,7 +301,7 @@ free_set_metadata_ctl_cb_info (struct SetMetadataCtlCb *data)
     iter = g_list_next (iter);
   }
   iter = data->specs;
-  
+
   g_free (data);
 }
 
@@ -382,6 +379,8 @@ resolve_result_relay_cb (GrlMetadataSource *source,
     g_error_free (_error);
   }
 
+  grl_metadata_source_set_operation_finished (source, rrc->spec->resolve_id);
+
   g_object_unref (rrc->spec->source);
   g_object_unref (rrc->spec->media);
   g_list_free (rrc->spec->keys);
@@ -448,7 +447,7 @@ set_metadata_idle (gpointer user_data)
 
   smctlcb = (struct SetMetadataCtlCb *) user_data;
   keymap = (struct SourceKeyMap *) smctlcb->next->data;
-  
+
   sms = g_new0 (GrlMetadataSourceSetMetadataSpec, 1);
   sms->source = keymap->source;
   sms->keys = keymap->keys;
@@ -794,7 +793,7 @@ grl_metadata_source_key_depends (GrlMetadataSource *source, GrlKeyID key_id)
  * @source: a metadata source
  *
  * Similar to grl_metadata_source_supported_keys(), but these keys
- * are marked as writable, meaning the source allows the client 
+ * are marked as writable, meaning the source allows the client
  * to provide new values for these keys that will be stored permanently.
  *
  * Returns: (element-type GObject.ParamSpec) (transfer none):
@@ -951,8 +950,7 @@ grl_metadata_source_resolve (GrlMetadataSource *source,
     grl_metadata_source_filter_slow (source, &_keys, FALSE);
   }
 
-  resolve_id =
-    grl_metadata_source_gen_operation_id (GRL_METADATA_SOURCE (source));
+  resolve_id = grl_operation_generate_id ();
 
   /* Always hook an own relay callback so we can do some
      post-processing before handing out the results
@@ -1328,7 +1326,7 @@ grl_metadata_source_get_description (GrlMetadataSource *source)
  *
  * This is the main method of the #GrlMetadataSource class. It will
  * get the values for @keys from @media and store it permanently. After
- * calling this method, future queries that return this media object 
+ * calling this method, future queries that return this media object
  * shall return this new values for the selected keys.
  *
  * This function is asynchronous and uses the Glib's main loop.
@@ -1467,27 +1465,10 @@ grl_metadata_source_cancel (GrlMetadataSource *source, guint operation_id)
 
   g_return_if_fail (GRL_IS_METADATA_SOURCE (source));
 
-  if (!grl_metadata_source_operation_is_ongoing (source, operation_id)) {
-    GRL_DEBUG ("Tried to cancel invalid or already cancelled operation. "
-               "Skipping...");
-    return;
-  }
-
-  /* Mark the operation as finished, if the source does not implement
-     cancellation or it did not make it in time, we will not emit the results
-     for this operation in any case.  At any rate, we will not free the
-     operation data until we are sure the plugin won't need it any more. In the
-     case of operations dealing with multiple results, like browse() or
-     search(), this will happen when it emits remaining = 0 (which can be
-     because it did not cancel the op or because it managed to cancel it and is
-     signaling so) */
-  grl_metadata_source_set_operation_cancelled (source, operation_id);
+  GRL_WARNING ("grl_metadata_source_cancel() is deprecated. "
+               "Use grl_operation_cancel() instead");
 
-  /* If the source provides an implementation for operation cancellation,
-     let's use that to avoid further unnecessary processing in the plugin */
-  if (GRL_METADATA_SOURCE_GET_CLASS (source)->cancel) {
-    GRL_METADATA_SOURCE_GET_CLASS (source)->cancel (source, operation_id);
-  }
+  grl_operation_cancel (operation_id);
 }
 
 /**
@@ -1539,19 +1520,14 @@ grl_metadata_source_set_operation_data (GrlMetadataSource *source,
                                         guint operation_id,
                                         gpointer data)
 {
-  struct OperationState *op_state;
-
   GRL_DEBUG ("grl_metadata_source_set_operation_data");
 
   g_return_if_fail (GRL_IS_METADATA_SOURCE (source));
 
-  op_state = g_hash_table_lookup (source->priv->pending_operations,
-				  GINT_TO_POINTER (operation_id));
-  if (op_state) {
-    op_state->data = data;
-  } else {
-    GRL_WARNING ("Tried to set operation data but operation does not exist");
-  }
+  GRL_WARNING ("grl_metadata_source_set_operation_data() is deprecated. "
+               "Use grl_operation_set_data() instead");
+
+  grl_operation_set_data (operation_id, data);
 }
 
 /**
@@ -1569,30 +1545,14 @@ gpointer
 grl_metadata_source_get_operation_data (GrlMetadataSource *source,
                                         guint operation_id)
 {
-  struct OperationState *op_state;
-
   GRL_DEBUG ("grl_metadata_source_get_operation_data");
 
   g_return_val_if_fail (GRL_IS_METADATA_SOURCE (source), NULL);
 
-  op_state = g_hash_table_lookup (source->priv->pending_operations,
-				  GINT_TO_POINTER (operation_id));
-  if (op_state) {
-    return op_state->data;
-  } else {
-    GRL_WARNING ("Tried to get operation data but operation does not exist");
-    return NULL;
-  }
-}
-
-guint
-grl_metadata_source_gen_operation_id (GrlMetadataSource *source)
-{
-  GrlMetadataSourceClass *klass;
-
-  klass = GRL_METADATA_SOURCE_GET_CLASS (source);
+  GRL_WARNING ("grl_metadata_source_get_operation_data() is deprecated. "
+               "Use grl_operation_get_data() instead");
 
-  return klass->operation_id++;
+  return grl_operation_get_data (operation_id);
 }
 
 /*
@@ -1621,8 +1581,7 @@ grl_metadata_source_set_operation_finished (GrlMetadataSource *source,
 {
   GRL_DEBUG ("grl_metadata_source_set_operation_finished (%d)", operation_id);
 
-  g_hash_table_remove (source->priv->pending_operations,
-		       GINT_TO_POINTER (operation_id));
+  grl_operation_remove (operation_id);
 }
 
 /*
@@ -1637,8 +1596,8 @@ grl_metadata_source_operation_is_finished (GrlMetadataSource *source,
 {
   struct OperationState *op_state;
 
-  op_state = g_hash_table_lookup (source->priv->pending_operations,
-				  GINT_TO_POINTER (operation_id));
+  op_state = grl_operation_get_private_data (operation_id);
+
   return op_state == NULL;
 }
 
@@ -1656,8 +1615,7 @@ grl_metadata_source_set_operation_completed (GrlMetadataSource *source,
 
   GRL_DEBUG ("grl_metadata_source_set_operation_completed (%d)", operation_id);
 
-  op_state = g_hash_table_lookup (source->priv->pending_operations,
-				  GINT_TO_POINTER (operation_id));
+  op_state = grl_operation_get_private_data (operation_id);
 
   if (op_state) {
     op_state->completed = TRUE;
@@ -1677,8 +1635,8 @@ grl_metadata_source_operation_is_completed (GrlMetadataSource *source,
 {
   struct OperationState *op_state;
 
-  op_state = g_hash_table_lookup (source->priv->pending_operations,
-				  GINT_TO_POINTER (operation_id));
+  op_state = grl_operation_get_private_data (operation_id);
+
   return !op_state || op_state->completed;
 }
 
@@ -1696,8 +1654,7 @@ grl_metadata_source_set_operation_cancelled (GrlMetadataSource *source,
 
   GRL_DEBUG ("grl_metadata_source_set_operation_cancelled (%d)", operation_id);
 
-  op_state = g_hash_table_lookup (source->priv->pending_operations,
-				  GINT_TO_POINTER (operation_id));
+  op_state = grl_operation_get_private_data (operation_id);
 
   if (op_state) {
     op_state->cancelled = TRUE;
@@ -1717,11 +1674,42 @@ grl_metadata_source_operation_is_cancelled (GrlMetadataSource *source,
 {
   struct OperationState *op_state;
 
-  op_state = g_hash_table_lookup (source->priv->pending_operations,
-				  GINT_TO_POINTER (operation_id));
+  op_state = grl_operation_get_private_data (operation_id);
+
   return op_state && op_state->cancelled;
 }
 
+static void
+grl_metadata_source_cancel_cb (struct OperationState *op_state)
+{
+  GrlMetadataSource *source = op_state->source;
+
+  if (!grl_metadata_source_operation_is_ongoing (source,
+                                                 op_state->operation_id)) {
+    GRL_DEBUG ("Tried to cancel invalid or already cancelled operation. "
+               "Skipping...");
+    return;
+  }
+
+  /* Mark the operation as finished, if the source does not implement
+     cancellation or it did not make it in time, we will not emit the results
+     for this operation in any case.  At any rate, we will not free the
+     operation data until we are sure the plugin won't need it any more. In the
+     case of operations dealing with multiple results, like browse() or
+     search(), this will happen when it emits remaining = 0 (which can be
+     because it did not cancel the op or because it managed to cancel it and is
+     signaling so) */
+  grl_metadata_source_set_operation_cancelled (source,
+                                               op_state->operation_id);
+
+  /* If the source provides an implementation for operation cancellation,
+     let's use that to avoid further unnecessary processing in the plugin */
+  if (GRL_METADATA_SOURCE_GET_CLASS (source)->cancel) {
+    GRL_METADATA_SOURCE_GET_CLASS (source)->cancel (source,
+                                                    op_state->operation_id);
+  }
+}
+
 /*
  * grl_metadata_source_set_operation_ongoing:
  *
@@ -1737,8 +1725,13 @@ grl_metadata_source_set_operation_ongoing (GrlMetadataSource *source,
   GRL_DEBUG ("set_operation_ongoing (%d)", operation_id);
 
   op_state = g_new0 (struct OperationState, 1);
-  g_hash_table_insert (source->priv->pending_operations,
-		       GINT_TO_POINTER (operation_id), op_state);
+  op_state->source       = source;
+  op_state->operation_id = operation_id;
+
+  grl_operation_set_private_data (operation_id,
+                                  op_state,
+                                  (GrlOperationCancelCb) grl_metadata_source_cancel_cb,
+                                  g_free);
 }
 
 /*
@@ -1753,7 +1746,7 @@ grl_metadata_source_operation_is_ongoing (GrlMetadataSource *source,
 {
   struct OperationState *op_state;
 
-  op_state = g_hash_table_lookup (source->priv->pending_operations,
-				  GINT_TO_POINTER (operation_id));
+  op_state = grl_operation_get_private_data (operation_id);
+
   return op_state && !op_state->cancelled;
 }
diff --git a/src/grl-metadata-source.h b/src/grl-metadata-source.h
index 5638813..4238da8 100644
--- a/src/grl-metadata-source.h
+++ b/src/grl-metadata-source.h
@@ -330,12 +330,12 @@ GrlMedia *grl_metadata_source_resolve_sync (GrlMetadataSource *source,
                                             GrlMetadataResolutionFlags flags,
                                             GError **error);
 
-void grl_metadata_source_set_operation_data (GrlMetadataSource *source,
-                                             guint operation_id,
-                                             gpointer data);
+G_GNUC_DEPRECATED void grl_metadata_source_set_operation_data (GrlMetadataSource *source,
+                                                               guint operation_id,
+                                                               gpointer data);
 
-gpointer grl_metadata_source_get_operation_data (GrlMetadataSource *source,
-                                                 guint operation_id);
+G_GNUC_DEPRECATED gpointer grl_metadata_source_get_operation_data (GrlMetadataSource *source,
+                                                                   guint operation_id);
 
 void grl_metadata_source_set_metadata (GrlMetadataSource *source,
 				       GrlMedia *media,
@@ -350,7 +350,8 @@ GList *grl_metadata_source_set_metadata_sync (GrlMetadataSource *source,
                                               GrlMetadataWritingFlags flags,
                                               GError **error);
 
-void grl_metadata_source_cancel (GrlMetadataSource *source, guint operation_id);
+G_GNUC_DEPRECATED void grl_metadata_source_cancel (GrlMetadataSource *source,
+                                                   guint operation_id);
 
 const gchar *grl_metadata_source_get_id (GrlMetadataSource *source);
 
diff --git a/src/grl-multiple.c b/src/grl-multiple.c
index c711646..ff8a185 100644
--- a/src/grl-multiple.c
+++ b/src/grl-multiple.c
@@ -35,6 +35,8 @@
 
 #include "grl-multiple.h"
 #include "grl-sync-priv.h"
+#include "grl-operation.h"
+#include "grl-operation-priv.h"
 #include "grl-plugin-registry.h"
 #include "grl-error.h"
 #include "grl-log.h"
@@ -84,11 +86,10 @@ static void multiple_search_cb (GrlMediaSource *source,
 				guint remaining,
 				gpointer user_data,
 				const GError *error);
+static void multiple_search_cancel_cb (struct MultipleSearchData *msd);
 
-/* ================= Globals ================= */
 
-static GHashTable *pending_operations = NULL;
-static gint multiple_search_id = 1;
+/* ================= Globals ================= */
 
 /* ================ Utitilies ================ */
 
@@ -150,7 +151,7 @@ start_multiple_search_operation (guint search_id,
 				 gpointer user_data)
 {
   GRL_DEBUG ("start_multiple_search_operation");
-  
+
   struct MultipleSearchData *msd;
   GList *iter_sources, *iter_skips;
   guint n, first_count, individual_count;
@@ -195,7 +196,7 @@ start_multiple_search_operation (guint search_id,
       rc->count = c;
       g_hash_table_insert (msd->table, source, rc);
 
-      /* Check if we have to apply a "skip" parameter to this source 
+      /* Check if we have to apply a "skip" parameter to this source
 	 (useful when we are chaining queries to complete the result count) */
       if (iter_skips) {
 	skip = GPOINTER_TO_INT (iter_skips->data);
@@ -228,8 +229,10 @@ start_multiple_search_operation (guint search_id,
   }
 
   /* This frees the previous msd structure (if this operation is chained) */
-  g_hash_table_insert (pending_operations,
-		       GINT_TO_POINTER (msd->search_id), msd);
+  grl_operation_set_private_data (msd->search_id,
+                                  msd,
+                                  (GrlOperationCancelCb) multiple_search_cancel_cb,
+                                  (GDestroyNotify) free_multiple_search_data);
 
   return msd;
 }
@@ -361,7 +364,7 @@ multiple_search_cb (GrlMediaSource *source,
 
   rc = (struct ResultCount *)
     g_hash_table_lookup (msd->table, (gpointer) source);
-  
+
   if (media) {
     rc->received++;
   }
@@ -432,7 +435,8 @@ multiple_search_cb (GrlMediaSource *source,
 
  operation_done:
   GRL_DEBUG ("Multiple operation finished (%u)", msd->search_id);
-  g_hash_table_remove (pending_operations, GINT_TO_POINTER (msd->search_id));
+
+  grl_operation_remove (msd->search_id);
 }
 
 static void
@@ -509,20 +513,13 @@ grl_multiple_search (const GList *sources,
   GList *sources_list;
   struct MultipleSearchData *msd;
   gboolean allocated_sources_list = FALSE;
+  guint operation_id;
 
   GRL_DEBUG ("grl_multiple_search");
 
   g_return_val_if_fail (count > 0, 0);
   g_return_val_if_fail (callback != NULL, 0);
 
-  if (!pending_operations) {
-    pending_operations =
-      g_hash_table_new_full (g_direct_hash,
-			     g_direct_equal,
-			     NULL,
-			     (GDestroyNotify) free_multiple_search_data);
-  }
-
   /* If no sources have been provided then get the list of all
      searchable sources from the registry */
   if (!sources) {
@@ -543,8 +540,8 @@ grl_multiple_search (const GList *sources,
   }
 
   /* Start multiple search operation */
-  multiple_search_id++;
-  msd = start_multiple_search_operation (multiple_search_id,
+  operation_id = grl_operation_generate_id ();
+  msd = start_multiple_search_operation (operation_id,
 					 sources,
 					 text,
 					 keys,
@@ -560,37 +557,11 @@ grl_multiple_search (const GList *sources,
   return msd->search_id;
 }
 
-/**
- * grl_multiple_cancel:
- * @search_id: the identifier of the multiple operation to cancel
- *
- * Cancel a running multiple search by issuing a cancel operation on each
- * source involved involved in the operation.
- *
- * Since: 0.1.6
- */
-void
-grl_multiple_cancel (guint search_id)
+static void
+multiple_search_cancel_cb (struct MultipleSearchData *msd)
 {
-  GRL_DEBUG ("grl_multiple_cancel");
-
-  struct MultipleSearchData *msd;
   GList *sources, *ids;
 
-  if (!pending_operations) {
-    GRL_DEBUG ("No pending operations. Skipping...");
-    return;
-  }
-
-  /* Retrieve the tracking data for operation 'search_id' */
-  msd = (struct MultipleSearchData *)
-    g_hash_table_lookup (pending_operations, GINT_TO_POINTER (search_id));
-  if (!msd) {
-    GRL_DEBUG ("Tried to cancel invalid or already cancelled multiple "
-               "operation. Skipping...");
-    return;
-  }
-
   /* Go through all the sources involved in that operation and issue
      cancel() operations for each one */
   sources = msd->sources;
@@ -599,8 +570,7 @@ grl_multiple_cancel (guint search_id)
     GRL_DEBUG ("cancelling operation %s:%u",
                grl_metadata_source_get_name (GRL_METADATA_SOURCE (sources->data)),
                GPOINTER_TO_UINT (ids->data));
-    grl_metadata_source_cancel (GRL_METADATA_SOURCE (sources->data),
-                                GPOINTER_TO_INT (ids->data));
+    grl_operation_cancel (GPOINTER_TO_INT (ids->data));
     sources = g_list_next (sources);
     ids = g_list_next (ids);
   }
@@ -612,6 +582,26 @@ grl_multiple_cancel (guint search_id)
 }
 
 /**
+ * grl_multiple_cancel:
+ * @search_id: the identifier of the multiple operation to cancel
+ *
+ * Cancel a running multiple search by issuing a cancel operation on each
+ * source involved involved in the operation.
+ *
+ * Since: 0.1.6
+ */
+void
+grl_multiple_cancel (guint search_id)
+{
+  GRL_DEBUG ("grl_multiple_cancel");
+
+  GRL_WARNING ("grl_multiple_cancel() is deprecated. "
+               "Use grl_operation_cancel() instead");
+
+  grl_operation_cancel (search_id);
+}
+
+/**
  * grl_multiple_search_sync:
  * @sources: (element-type Grl.MediaSource) (allow-none):
  * a #GList of #GrlMediaSource<!-- -->s where to search from (%NULL for all
diff --git a/src/grl-multiple.h b/src/grl-multiple.h
index 035c120..b968b08 100644
--- a/src/grl-multiple.h
+++ b/src/grl-multiple.h
@@ -46,7 +46,7 @@ GList *grl_multiple_search_sync (const GList *sources,
                                  GrlMetadataResolutionFlags flags,
                                  GError **error);
 
-void grl_multiple_cancel (guint search_id);
+G_GNUC_DEPRECATED void grl_multiple_cancel (guint search_id);
 
 void grl_multiple_get_media_from_uri (const gchar *uri,
 				      const GList *keys,
diff --git a/src/grl-operation-priv.h b/src/grl-operation-priv.h
new file mode 100644
index 0000000..bdf4302
--- /dev/null
+++ b/src/grl-operation-priv.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2011 Igalia S.L.
+ *
+ * Contact: Iago Toral Quiroga <itoral igalia com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef _GRL_OPERATION_PRIV_H_
+#define _GRL_OPERATION_PRIV_H_
+
+#include <glib.h>
+
+typedef void (*GrlOperationCancelCb) (gpointer data);
+
+void grl_operation_init (void);
+
+guint grl_operation_generate_id (void);
+
+void grl_operation_set_private_data (guint                operation_id,
+                                     gpointer             private_data,
+                                     GrlOperationCancelCb cancel_cb,
+                                     GDestroyNotify       destroy_cb);
+
+gpointer grl_operation_get_private_data (guint operation_id);
+
+void grl_operation_remove (guint operation_id);
+
+#endif /* _GRL_OPERATION_PRIV_H_ */
diff --git a/src/grl-operation.c b/src/grl-operation.c
new file mode 100644
index 0000000..4154946
--- /dev/null
+++ b/src/grl-operation.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2011 Igalia S.L.
+ *
+ * Contact: Iago Toral Quiroga <itoral igalia com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "grl-operation.h"
+#include "grl-operation-priv.h"
+
+typedef struct
+{
+  GrlOperationCancelCb cancel_cb;
+  GDestroyNotify       destroy_cb;
+  gpointer             private_data;
+  gpointer             user_data;
+} OperationData;
+
+static guint       operations_id;
+static GHashTable *operations;
+
+static void
+operation_data_free (OperationData *data)
+{
+  if (data->destroy_cb) {
+    data->destroy_cb (data->private_data);
+  }
+
+  g_slice_free (OperationData, data);
+}
+
+void
+grl_operation_init (void)
+{
+  static gboolean initialized = FALSE;
+
+  if (G_LIKELY (initialized))
+    return;
+
+  initialized = TRUE;
+  operations = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+                                      NULL,
+                                      (GDestroyNotify) operation_data_free);
+  operations_id = 1;
+}
+
+guint
+grl_operation_generate_id (void)
+{
+  guint operation_id = operations_id++;
+  OperationData *data = g_slice_new0 (OperationData);
+
+  g_hash_table_insert (operations, GUINT_TO_POINTER (operation_id), data);
+
+  return operation_id;
+}
+
+void
+grl_operation_set_private_data (guint                operation_id,
+                                gpointer             private_data,
+                                GrlOperationCancelCb cancel_cb,
+                                GDestroyNotify       destroy_cb)
+{
+  OperationData *data = g_hash_table_lookup (operations,
+                                             GUINT_TO_POINTER (operation_id));
+
+  g_return_if_fail (data != NULL);
+
+  data->cancel_cb    = cancel_cb;
+  data->destroy_cb   = destroy_cb;
+  data->private_data = private_data;
+}
+
+gpointer
+grl_operation_get_private_data (guint operation_id)
+{
+  OperationData *data = g_hash_table_lookup (operations,
+                                             GUINT_TO_POINTER (operation_id));
+
+  g_return_val_if_fail (data != NULL, NULL);
+
+  return data->private_data;
+}
+
+void
+grl_operation_remove (guint operation_id)
+{
+  g_hash_table_remove (operations, GUINT_TO_POINTER (operation_id));
+}
+
+/*** PUBLIC API ***/
+
+/**
+ * grl_operation_cancel:
+ * @operation_id: the identifier of a running operation
+ *
+ * Cancel an operation.
+ */
+void
+grl_operation_cancel (guint operation_id)
+{
+  OperationData *data = g_hash_table_lookup (operations,
+                                             GUINT_TO_POINTER (operation_id));
+
+  g_return_if_fail (data != NULL);
+
+  if (data->cancel_cb) {
+    data->cancel_cb (data->private_data);
+  }
+}
+
+/**
+ * grl_operation_get_data:
+ * @operation_id: the identifier of a running operation
+ *
+ * Obtains the previously attached data
+ *
+ * Returns: (transfer none): The previously attached data.
+ */
+gpointer
+grl_operation_get_data (guint operation_id)
+{
+  OperationData *data = g_hash_table_lookup (operations,
+                                             GUINT_TO_POINTER (operation_id));
+
+  g_return_val_if_fail (data != NULL, NULL);
+
+  return data->user_data;
+}
+
+/**
+ * grl_operation_set_data:
+ * @operation_id: the identifier of a running operation
+ * @data: the data to attach
+ *
+ * Attach a pointer to the specific operation.
+ */
+void
+grl_operation_set_data (guint operation_id, gpointer user_data)
+{
+  OperationData *data = g_hash_table_lookup (operations,
+                                             GUINT_TO_POINTER (operation_id));
+
+  g_return_if_fail (data != NULL);
+
+  data->user_data = user_data;
+}
diff --git a/src/grl-operation.h b/src/grl-operation.h
new file mode 100644
index 0000000..c96356c
--- /dev/null
+++ b/src/grl-operation.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2011 Igalia S.L.
+ *
+ * Contact: Iago Toral Quiroga <itoral igalia com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#if !defined (_GRILO_H_INSIDE_) && !defined (GRILO_COMPILATION)
+#error "Only <grilo.h> can be included directly."
+#endif
+
+#ifndef _GRL_OPERATION_H_
+#define _GRL_OPERATION_H_
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+void grl_operation_cancel (guint operation_id);
+
+gpointer grl_operation_get_data (guint operation_id);
+
+void grl_operation_set_data (guint operation_id, gpointer user_data);
+
+G_END_DECLS
+
+#endif /* _GRL_OPERATION_H_ */
diff --git a/tools/grilo-test-ui/main.c b/tools/grilo-test-ui/main.c
index 37ac2fd..b21a0d7 100644
--- a/tools/grilo-test-ui/main.c
+++ b/tools/grilo-test-ui/main.c
@@ -506,12 +506,7 @@ static void
 cancel_current_operation (void)
 {
   if (ui_state->op_ongoing) {
-    if (!ui_state->multiple) {
-      grl_metadata_source_cancel (GRL_METADATA_SOURCE (ui_state->cur_op_source),
-                                  ui_state->cur_op_id);
-    } else {
-      grl_multiple_cancel (ui_state->cur_op_id);
-    }
+    grl_operation_cancel (ui_state->cur_op_id);
     ui_state->op_ongoing = FALSE;
   }
 }



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