[grilo] core: introduce grilo operations



commit dd0d4605c278fed07770dd6f01f8692f256fd107
Author: Lionel Landwerlin <lionel g landwerlin linux intel com>
Date:   Thu Jun 16 19:15:37 2011 +0100

    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     |   20 ++---
 src/grl-metadata-source.c  |  210 +++++++++++++-------------------------------
 src/grl-metadata-source.h  |    9 --
 src/grl-multiple.c         |   68 ++++----------
 src/grl-multiple.h         |    2 -
 src/grl-operation-priv.h   |   43 +++++++++
 src/grl-operation.c        |  163 ++++++++++++++++++++++++++++++++++
 src/grl-operation.h        |   42 +++++++++
 tools/grilo-test-ui/main.c |    7 +--
 12 files changed, 346 insertions(+), 228 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 1d19c50..97bd46a 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;
@@ -2456,8 +2453,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 9fbdd29..a0d0e5a 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;
@@ -766,7 +765,7 @@ grl_metadata_source_slow_keys (GrlMetadataSource *source)
  * @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 GrlKeyID) (transfer none):
@@ -892,8 +891,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
@@ -1269,7 +1267,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.
@@ -1384,54 +1382,6 @@ grl_metadata_source_set_metadata_sync (GrlMetadataSource *source,
 }
 
 /**
- * grl_metadata_source_cancel:
- * @source: a metadata source
- * @operation_id: the identifier of the running operation, as returned by the
- * function that started it
- *
- * Cancel a running method.
- *
- * The derived class must implement the cancel vmethod in order to honour the
- * request correctly. Otherwise, the operation will not be interrupted.
- *
- * In all cases, if this function is called on an ongoing operation, the
- * corresponding callback will be called with the
- * @GRL_CORE_ERROR_OPERATION_CANCELLED error set, and no more action will be
- * taken for that operation after the said callback with error has been called.
- *
- * Since: 0.1.14
- */
-void
-grl_metadata_source_cancel (GrlMetadataSource *source, guint operation_id)
-{
-  GRL_DEBUG ("grl_metadata_source_cancel");
-
-  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);
-
-  /* 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_metadata_source_supported_operations:
  * @source: a metadata source
  *
@@ -1465,77 +1415,6 @@ grl_metadata_source_supported_operations_impl (GrlMetadataSource *source)
   return caps;
 }
 
-/**
- * grl_metadata_source_set_operation_data:
- * @source: a metadata source
- * @operation_id: the identifier of a running operation
- * @data: the data to attach
- *
- * Attach a pointer to the specific operation.
- *
- * Since: 0.1.14
- */
-void
-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_metadata_source_get_operation_data:
- * @source: a metadata source
- * @operation_id: the identifier of a running operation
- *
- * Obtains the previously attached data
- *
- * Returns: (transfer none): The previously attached data.
- *
- * Since: 0.1.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);
-
-  return klass->operation_id++;
-}
-
 /*
  * Operation states:
  *
@@ -1562,8 +1441,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);
 }
 
 /*
@@ -1578,8 +1456,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;
 }
 
@@ -1597,8 +1475,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;
@@ -1618,8 +1495,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;
 }
 
@@ -1637,8 +1514,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;
@@ -1658,11 +1534,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:
  *
@@ -1678,8 +1585,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);
 }
 
 /*
@@ -1694,7 +1606,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 712794f..1d65eee 100644
--- a/src/grl-metadata-source.h
+++ b/src/grl-metadata-source.h
@@ -324,13 +324,6 @@ 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);
-
-gpointer grl_metadata_source_get_operation_data (GrlMetadataSource *source,
-                                                 guint operation_id);
-
 void grl_metadata_source_set_metadata (GrlMetadataSource *source,
 				       GrlMedia *media,
 				       GList *keys,
@@ -344,8 +337,6 @@ GList *grl_metadata_source_set_metadata_sync (GrlMetadataSource *source,
                                               GrlMetadataWritingFlags flags,
                                               GError **error);
 
-void grl_metadata_source_cancel (GrlMetadataSource *source, guint operation_id);
-
 const gchar *grl_metadata_source_get_id (GrlMetadataSource *source);
 
 const gchar *grl_metadata_source_get_name (GrlMetadataSource *source);
diff --git a/src/grl-multiple.c b/src/grl-multiple.c
index bfe93c2..59bc777 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);
   }
diff --git a/src/grl-multiple.h b/src/grl-multiple.h
index 035c120..9827d3d 100644
--- a/src/grl-multiple.h
+++ b/src/grl-multiple.h
@@ -46,8 +46,6 @@ GList *grl_multiple_search_sync (const GList *sources,
                                  GrlMetadataResolutionFlags flags,
                                  GError **error);
 
-void grl_multiple_cancel (guint search_id);
-
 void grl_multiple_get_media_from_uri (const gchar *uri,
 				      const GList *keys,
 				      GrlMetadataResolutionFlags flags,
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..bcf7c04
--- /dev/null
+++ b/src/grl-operation.c
@@ -0,0 +1,163 @@
+/*
+ * 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 77ea9b6..95cef71 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]