[gupnp-tools/wip/search: 1/2] av-cp: Implement sliced search
- From: Jens Georg <jensgeorg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gupnp-tools/wip/search: 1/2] av-cp: Implement sliced search
- Date: Thu, 18 Aug 2016 13:42:08 +0000 (UTC)
commit f46e85fdac295f24f78e4461a839d7dc30eb323f
Author: Jens Georg <mail jensge org>
Date: Thu Aug 18 12:50:03 2016 +0200
av-cp: Implement sliced search
Signed-off-by: Jens Georg <mail jensge org>
src/av-cp/search-dialog.c | 303 ++++++++++++++++++++++++++++++++++++---------
1 files changed, 243 insertions(+), 60 deletions(-)
---
diff --git a/src/av-cp/search-dialog.c b/src/av-cp/search-dialog.c
index 8bec57c..018eeea 100644
--- a/src/av-cp/search-dialog.c
+++ b/src/av-cp/search-dialog.c
@@ -27,6 +27,8 @@
#include "server-device.h"
#include "icons.h"
+typedef struct _SearchTask SearchTask;
+
struct _SearchDialog {
GtkDialog parent;
};
@@ -42,6 +44,7 @@ struct _SearchDialogPrivate {
char *title;
AVCPMediaServer *server;
guint pulse_timer;
+ SearchTask *task;
};
typedef struct _SearchDialogPrivate SearchDialogPrivate;
@@ -53,6 +56,192 @@ search_dialog_on_search_activate (SearchDialog *self, GtkEntry *entry);
static void
search_dialog_finalize (GObject *object);
+struct _SearchTask {
+ AVCPMediaServer *server;
+ char *search_expression;
+ char *container_id;
+ GtkListStore *target;
+ int start;
+ int count;
+ int total;
+ gboolean running;
+ GUPnPDIDLLiteParser *parser;
+ GError *error;
+ GSourceFunc callback;
+ gpointer user_data;
+};
+
+static void
+search_task_on_didl_object_available (GUPnPDIDLLiteParser *parser,
+ GUPnPDIDLLiteObject *object,
+ gpointer user_data);
+
+static SearchTask *
+search_task_new (AVCPMediaServer *server,
+ GtkListStore *target,
+ const char *container_id,
+ const char *search_expression,
+ int count,
+ GSourceFunc callback,
+ gpointer user_data)
+{
+ SearchTask *task = g_new0 (SearchTask, 1);
+
+ task->search_expression = g_strdup (search_expression);
+ task->target = g_object_ref (target);
+ task->server = g_object_ref (server);
+ task->container_id = g_strdup (container_id);
+ task->start = 0;
+ task->count = count;
+ task->total = -1;
+ task->parser = gupnp_didl_lite_parser_new ();
+ task->error = NULL;
+ task->callback = callback;
+ task->user_data = user_data;
+
+ g_signal_connect (G_OBJECT (task->parser),
+ "object-available",
+ G_CALLBACK (search_task_on_didl_object_available),
+ task);
+
+ return task;
+}
+
+static void
+search_task_free (SearchTask *task) {
+ g_clear_object (&task->target);
+ g_clear_object (&task->server);
+ g_clear_object (&task->parser);
+ g_free (task->search_expression);
+ g_free (task->container_id);
+ if (task->error != NULL) {
+ g_error_free (task->error);
+ }
+ g_free (task);
+}
+
+static gboolean
+search_task_idle_callback (gpointer user_data)
+{
+ SearchTask *task = (SearchTask *)user_data;
+ if (task->callback != NULL) {
+ task->callback (task->user_data);
+ }
+
+ return FALSE;
+}
+
+static void
+search_task_set_finished (SearchTask *task, GError *error)
+{
+ task->running = FALSE;
+ task->error = error;
+
+ g_idle_add (search_task_idle_callback, task);
+}
+
+static void
+search_task_on_search_ready (GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ SearchTask *task = (SearchTask *)user_data;
+ GError *error = NULL;
+ char *didl_xml = NULL;
+ guint32 total = 0;
+ guint32 returned = 0;
+ gboolean result;
+ gboolean finished = FALSE;
+
+ result = av_cp_media_server_search_finish (AV_CP_MEDIA_SERVER (source),
+ res,
+ &didl_xml,
+ &total,
+ &returned,
+ &error);
+
+ g_message ("Received search slice result for %s with expression %s, result is %s",
+ task->container_id,
+ task->search_expression,
+ result ? "TRUE" : "FALSE");
+
+
+ if (!result) {
+ finished = TRUE;
+
+ goto out;
+ }
+
+ /* Nothing returned by the server */
+ if (returned == 0) {
+ finished = TRUE;
+
+ goto out;
+ }
+
+ if (didl_xml == NULL) {
+ finished = TRUE;
+ goto out;
+ }
+
+ gupnp_didl_lite_parser_parse_didl (task->parser, didl_xml, &error);
+ if (error != NULL) {
+ finished = TRUE;
+
+ goto out;
+ }
+
+ if (total != 0) {
+ task->total = total;
+ }
+
+ task->start += returned;
+
+out:
+ g_clear_pointer (&didl_xml, g_free);
+ if (finished) {
+ g_message ("Finished search, error: %s",
+ error ? error->message : "none");
+ search_task_set_finished (task, error);
+ } else {
+ g_message ("Starting new slice %u/%u (total %u)",
+ task->start,
+ task->count,
+ task->total);
+
+ av_cp_media_server_search_async (task->server,
+ NULL,
+ search_task_on_search_ready,
+ task->container_id,
+ task->search_expression,
+ task->start,
+ task->count,
+ task);
+ }
+}
+
+static void
+search_task_run (SearchTask *task) {
+ if (task->running) {
+ g_debug ("Search task is already running, not doing anything.");
+
+ return;
+ }
+
+ g_message ("Starting search task for %s with expression %s",
+ task->container_id,
+ task->search_expression);
+
+ task->running = TRUE;
+
+ av_cp_media_server_search_async (task->server,
+ NULL,
+ search_task_on_search_ready,
+ task->container_id,
+ task->search_expression,
+ task->start,
+ task->count,
+ task);
+}
+
#define ITEM_CLASS_IMAGE "object.item.imageItem"
#define ITEM_CLASS_AUDIO "object.item.audioItem"
#define ITEM_CLASS_VIDEO "object.item.videoItem"
@@ -87,6 +276,21 @@ get_item_icon (GUPnPDIDLLiteObject *object)
return icon;
}
+static void
+search_task_on_didl_object_available (GUPnPDIDLLiteParser *parser,
+ GUPnPDIDLLiteObject *object,
+ gpointer user_data)
+{
+ SearchTask *task = (SearchTask *)user_data;
+ GtkTreeIter iter;
+
+ gtk_list_store_insert_with_values (task->target,
+ &iter,
+ -1,
+ 0, get_item_icon (object),
+ 1, gupnp_didl_lite_object_get_title (object),
+ -1);
+}
static void
search_dialog_class_init (SearchDialogClass *klass)
@@ -142,72 +346,39 @@ search_dialog_finalize (GObject *object)
}
}
-static void
-on_didl_object_available (GUPnPDIDLLiteParser *parser,
- GUPnPDIDLLiteObject *object,
- gpointer user_data)
-{
- SearchDialog *self = SEARCH_DIALOG (user_data);
- SearchDialogPrivate *priv = search_dialog_get_instance_private (self);
- GtkTreeIter iter;
-
- gtk_list_store_insert_with_values (priv->search_dialog_liststore,
- &iter,
- -1,
- 0, get_item_icon (object),
- 1, gupnp_didl_lite_object_get_title (object),
- -1);
-
-}
-
-static void
-search_dialog_on_search_done (GObject *source, GAsyncResult *res, gpointer user_data)
+static gboolean
+search_dialog_on_search_task_done (gpointer user_data)
{
SearchDialog *self = SEARCH_DIALOG (user_data);
SearchDialogPrivate *priv = search_dialog_get_instance_private (self);
- GError *error = NULL;
- char *xml = NULL;
- guint32 total = 0;
- guint32 returned = 0;
- GUPnPDIDLLiteParser *parser;
-
+ g_source_remove (priv->pulse_timer);
+ gtk_entry_set_progress_fraction (priv->search_dialog_entry, 0);
+ gtk_widget_set_sensitive (GTK_WIDGET (priv->search_dialog_entry), TRUE);
- if (!av_cp_media_server_search_finish (AV_CP_MEDIA_SERVER (source),
- res,
- &xml,
- &total,
- &returned,
- &error)) {
+ if (priv->task->error != NULL) {
GtkWidget *dialog = NULL;
dialog = gtk_message_dialog_new (GTK_WINDOW (self),
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_WARNING,
GTK_BUTTONS_CLOSE,
- "Search failed: %s",
- error->message);
+ "%s",
+ _("Search failed"));
+
+ gtk_message_dialog_format_secondary_text
+ (GTK_MESSAGE_DIALOG (dialog),
+ _("Error message was: %s"),
+ priv->task->error->message);
gtk_dialog_run (GTK_DIALOG (dialog));
gtk_widget_destroy (dialog);
- g_critical ("Failed to search: %s", error->message),
- g_error_free (error);
-
- goto out;
+ g_critical ("Failed to search: %s", priv->task->error->message);
}
- parser = gupnp_didl_lite_parser_new ();
- g_signal_connect (G_OBJECT (parser), "object-available",
- G_CALLBACK (on_didl_object_available),
- self);
- gupnp_didl_lite_parser_parse_didl (parser, xml, &error);
- g_free (xml);
+ g_clear_pointer (&priv->task, search_task_free);
-out:
- g_clear_object (&parser);
- g_source_remove (priv->pulse_timer);
- gtk_entry_set_progress_fraction (priv->search_dialog_entry, 0.0);
- gtk_widget_set_sensitive (GTK_WIDGET (priv->search_dialog_entry), TRUE);
+ return FALSE;
}
void
@@ -258,7 +429,17 @@ search_dialog_set_container_title (SearchDialog *self, char *title)
static gboolean
pulse_timer (gpointer user_data)
{
- gtk_entry_progress_pulse (GTK_ENTRY (user_data));
+ SearchDialog *self = SEARCH_DIALOG (user_data);
+ SearchDialogPrivate *priv = search_dialog_get_instance_private (self);
+ if (priv->task->total == -1) {
+ gtk_entry_progress_pulse (GTK_ENTRY (priv->search_dialog_entry));
+ } else {
+ gdouble progress = (gdouble) priv->task->start /
+ (gdouble) priv->task->total;
+ gtk_entry_set_progress_fraction
+ (GTK_ENTRY (priv->search_dialog_entry),
+ progress);
+ }
return TRUE;
}
@@ -270,15 +451,17 @@ search_dialog_on_search_activate (SearchDialog *self, GtkEntry *entry)
SearchDialogPrivate *priv = search_dialog_get_instance_private (self);
gtk_list_store_clear (priv->search_dialog_liststore);
gtk_widget_set_sensitive (GTK_WIDGET (entry), FALSE);
- priv->pulse_timer = g_timeout_add_seconds (1, pulse_timer, entry);
-
- av_cp_media_server_search_async (priv->server,
- NULL,
- search_dialog_on_search_done,
- priv->id,
- gtk_entry_get_text (entry),
- 0,
- 0,
- self);
+ priv->pulse_timer = g_timeout_add_seconds (1, pulse_timer, self);
+
+ g_clear_pointer (&priv->task, search_task_free);
+
+ priv->task = search_task_new (priv->server,
+ priv->search_dialog_liststore,
+ priv->id,
+ gtk_entry_get_text (entry),
+ 30,
+ search_dialog_on_search_task_done,
+ self);
+ search_task_run (priv->task);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]