gnunet-svn
[Top][All Lists]
Advanced

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

[GNUnet-SVN] r19594 - gnunet-gtk/src/fs


From: gnunet
Subject: [GNUnet-SVN] r19594 - gnunet-gtk/src/fs
Date: Wed, 1 Feb 2012 12:50:19 +0100

Author: grothoff
Date: 2012-02-01 12:50:19 +0100 (Wed, 01 Feb 2012)
New Revision: 19594

Modified:
   gnunet-gtk/src/fs/gnunet-fs-gtk-event_handler.c
   gnunet-gtk/src/fs/gnunet-fs-gtk-event_handler.h
Log:
-more code cleanup, simplifications, bugfixes, etc.

Modified: gnunet-gtk/src/fs/gnunet-fs-gtk-event_handler.c
===================================================================
--- gnunet-gtk/src/fs/gnunet-fs-gtk-event_handler.c     2012-02-01 09:53:50 UTC 
(rev 19593)
+++ gnunet-gtk/src/fs/gnunet-fs-gtk-event_handler.c     2012-02-01 11:50:19 UTC 
(rev 19594)
@@ -89,9 +89,10 @@
 
 
 /**
- * Information we keep for each search result.  Used to quickly
- * identify the tab and row of the result; stored in the user-context
- * of the FS library for the search result.
+ * Information we keep for each search result entry in any search tab.
+ * An entry like this is also generated for downloads by-URI.  Used to
+ * quickly identify the tab and row of the result; stored in the
+ * user-context of the FS library for the search result.
  */
 struct SearchResult
 {
@@ -154,6 +155,8 @@
 
 
 
+/* ***************** Search event handling ****************** */
+
 /**
  * This should get the default download directory (so that GNUnet
  * won't offer the user to download files to the 'bin' subdirectory,
@@ -735,92 +738,932 @@
 }
 
 
+/**
+ * Recalculate and update the label for a search, as we have
+ * received additional search results.
+ *
+ * @param tab search tab for which we should update the label
+ */
+static void
+update_search_label (struct SearchTab *tab)
+{
+  char *label_text;
 
+  while (tab->parent != NULL)
+    tab = tab->parent->tab;
+  if (tab->num_results > 0)
+    GNUNET_asprintf (&label_text, "%.*s%s (%u)", 20, tab->query_txt,
+                     strlen (tab->query_txt) > 20 ? "..." : "",
+                     tab->num_results);
+  else
+    GNUNET_asprintf (&label_text, "%.*s%s", 20, tab->query_txt,
+                     strlen (tab->query_txt) > 20 ? "..." : "");
+  gtk_label_set_text (tab->label, label_text);
+  gtk_widget_set_tooltip_text (GTK_WIDGET (tab->label), tab->query_txt);
+  GNUNET_free (label_text);
+}
 
 
-/* FIXME: go over code from here on and document & clean up... */
+/**
+ * Close a search tab and free associated state.  Assumes that the
+ * respective tree model has already been cleaned up (this just
+ * updates the notebook and frees the 'tab' itself).
+ *
+ * @param tab search tab to close
+ */
+static void
+close_search_tab (struct SearchTab *tab)
+{
+  GtkNotebook *notebook;
+  int index;
+  int i;
 
+  if (tab->parent != NULL)
+  {
+    /* not a top-level search (namespace update search), do not close
+       tab here! */
+    GNUNET_free (tab);
+    return;
+  }
+  notebook =
+      GTK_NOTEBOOK (GNUNET_FS_GTK_get_main_window_object
+                    ("GNUNET_GTK_main_window_notebook"));
+  index = -1;
+  for (i = gtk_notebook_get_n_pages (notebook) - 1; i >= 0; i--)
+    if (tab->frame == gtk_notebook_get_nth_page (notebook, i))
+      index = i;
+  gtk_notebook_remove_page (notebook, index);
+  g_object_unref (tab->builder);
+  GNUNET_free (tab->query_txt);
+  GNUNET_CONTAINER_DLL_remove (search_tab_head, search_tab_tail, tab);
+  if (tab == uri_tab)
+    uri_tab = NULL;
+  GNUNET_free (tab);
+}
 
 
+/**
+ * Free a particular search result and remove the respective
+ * entries from the respective tree store.  This function
+ * is called when a search is stopped to clean up the state
+ * of the tab.
+ *
+ * @param sr the search result to clean up
+ */
+static void
+free_search_result (struct SearchResult *sr)
+{
+  GtkTreePath *tp;
+  GtkTreeModel *tm;
+  GtkTreeIter iter;
+  struct GNUNET_FS_Uri *uri;
+  struct GNUNET_CONTAINER_MetaData *meta;
 
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Freeing a search result SR=%p\n", 
+             sr);
+  if ( (NULL == sr) ||
+       (NULL == sr->rr) ||
+       (NULL == (tm = gtk_tree_row_reference_get_model (sr->rr))) ||
+       (NULL == (tp = gtk_tree_row_reference_get_path (sr->rr))) )
+  {
+    GNUNET_break (0);
+    return;
+  }
+  if (! gtk_tree_model_get_iter (tm, &iter, tp))
+  {
+    GNUNET_break (0);
+    gtk_tree_path_free (tp);
+    return;
+  }
+  gtk_tree_path_free (tp);
+  gtk_tree_model_get (tm, &iter, 0, &meta, 1, &uri, -1);
+  if (uri != NULL)
+    GNUNET_FS_uri_destroy (uri);
+  if (meta != NULL)
+    GNUNET_CONTAINER_meta_data_destroy (meta);
+  gtk_tree_row_reference_free (sr->rr);
+  (void) gtk_tree_store_remove (GTK_TREE_STORE (tm), &iter);
+  GNUNET_free (sr);
+}
 
 
-static struct DownloadEntry *
-change_download_colour (struct DownloadEntry *de, 
-                       const char *colour)
+/**
+ * Selected row has changed in search result tree view, update preview
+ * and metadata areas.
+ *
+ * @param tv the tree view in a search tab where the selection changed
+ * @param user_data the 'struct SearchTab' that contains the tree view
+ */
+static void
+update_meta_data_views (GtkTreeView *tv, gpointer user_data)
 {
+  struct SearchTab *tab = user_data;
+  GtkImage *image;
+  GtkListStore *ms;
+  GtkTreeSelection *sel;
+  GtkTreeModel *model;
   GtkTreeIter iter;
-  GtkTreePath *path;
+  struct GNUNET_CONTAINER_MetaData *meta;
+  GdkPixbuf *pixbuf;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Changing download DE=%p color to 
%s\n", de, colour);
-  path = gtk_tree_row_reference_get_path (de->rr);
-  GNUNET_assert (NULL != path);
-  if (TRUE != gtk_tree_model_get_iter (GTK_TREE_MODEL (de->ts), &iter, path))
+  GNUNET_assert (tab->query_txt != NULL);
+  image =
+      GTK_IMAGE (GNUNET_FS_GTK_get_main_window_object
+                 ("GNUNET_GTK_main_window_preview_image"));
+  ms = GTK_LIST_STORE (GNUNET_FS_GTK_get_main_window_object
+                       ("GNUNET_GTK_meta_data_list_store"));
+  sel = gtk_tree_view_get_selection (tv);
+  gtk_list_store_clear (ms);
+  if (! gtk_tree_selection_get_selected (sel, &model, &iter))
   {
+    /* nothing selected, clear preview */
+    gtk_image_clear (image);
+    return;
+  }
+  meta = NULL;
+  pixbuf = NULL;
+  gtk_tree_model_get (model, &iter, 0, &meta, 3, &pixbuf, -1);
+  if (NULL != pixbuf)
+  {
+    gtk_image_set_from_pixbuf (image, pixbuf);
+    g_object_unref (G_OBJECT (pixbuf));
+  }
+  if (NULL != meta)  
+    GNUNET_CONTAINER_meta_data_iterate (meta,
+                                        
&GNUNET_FS_GTK_add_meta_data_to_list_store,
+                                        ms);
+}
+
+
+/**
+ * Page switched in main notebook, update thumbnail and
+ * metadata views.
+ *
+ * @param dummy widget emitting the event, unused
+ * @param data master Gtk builder, unused
+ */
+void
+GNUNET_GTK_main_window_notebook_switch_page_cb (GtkWidget * dummy,
+                                                gpointer data)
+{
+  GtkNotebook *notebook;
+  gint page;
+  GtkWidget *w;
+  struct SearchTab *tab;
+  GtkImage *image;
+  GtkListStore *ms;
+  GtkTreeView *tv;
+
+  notebook =
+      GTK_NOTEBOOK (GNUNET_FS_GTK_get_main_window_object
+                    ("GNUNET_GTK_main_window_notebook"));
+  page = gtk_notebook_get_current_page (notebook);
+  w = gtk_notebook_get_nth_page (notebook, page);
+  for (tab = search_tab_head; NULL != tab; tab = tab->next)
+  {
+    if (tab->frame != w)
+      continue;
+    tv = GTK_TREE_VIEW (gtk_builder_get_object
+                       (tab->builder, "_search_result_frame"));
+    update_meta_data_views (tv, tab);
+    return;
+  }
+  /* active tab is not a search tab (likely the 'publish' tab), 
+     clear meta data and preview widgets */
+  image =
+      GTK_IMAGE (GNUNET_FS_GTK_get_main_window_object
+                 ("GNUNET_GTK_main_window_preview_image"));
+  gtk_image_clear (image);
+  ms = GTK_LIST_STORE (GNUNET_FS_GTK_get_main_window_object
+                       ("GNUNET_GTK_meta_data_list_store"));
+  gtk_list_store_clear (ms);
+}
+
+
+/**
+ * User clicked on the 'close' button for a search tab.  Tell FS to stop the 
search.
+ *
+ * @param button the 'close' button
+ * @param user_data the 'struct SearchTab' of the tab to close
+ */
+static void
+stop_search (GtkButton *button, gpointer user_data)
+{
+  struct SearchTab *tab = user_data;
+  struct GNUNET_FS_SearchContext *sc;
+
+  sc = tab->sc;
+  if (NULL == sc)
+  {
     GNUNET_break (0);
-    gtk_tree_path_free (path);
-    return de;
+    return;
   }
-  gtk_tree_path_free (path);
-  gtk_tree_store_set (de->ts, &iter, 8, colour, -1);
-  return de;
+  tab->sc = NULL;
+  GNUNET_FS_search_stop (sc);
+  gtk_widget_hide (GTK_WIDGET (button));
+  gtk_widget_hide (tab->pause_button);
+  gtk_widget_hide (tab->play_button);  
 }
 
 
-static struct PublishEntry *
-change_publish_colour (struct PublishEntry *pe, const char *colour)
+/**
+ * The user clicked on the 'pause' button for a search tab.  Tell FS to pause 
the search.
+ *
+ * @param button the 'pause' button
+ * @param user_data the 'struct SearchTab' of the tab to pause
+ */
+static void
+pause_search (GtkButton *button, gpointer user_data)
 {
+  struct SearchTab *tab = user_data;
+
+  if (NULL == tab->sc)
+  {
+    GNUNET_break (0);
+    return;
+  }
+  GNUNET_FS_search_pause (tab->sc);
+  gtk_widget_show (tab->play_button);
+  gtk_widget_hide (tab->pause_button);
+}
+
+
+/**
+ * The user clicked on the 'resume' button for a search tab.  Tell FS to 
resume the search.
+ *
+ * @param button the 'resume' button
+ * @param user_data the 'struct SearchTab' of the tab to resume
+ */
+static void
+continue_search (GtkButton * button, gpointer user_data)
+{
+  struct SearchTab *tab = user_data;
+
+  if (NULL == tab->sc)
+  {
+    GNUNET_break (0);
+    return;
+  }
+  GNUNET_FS_search_continue (tab->sc);
+  gtk_widget_show (tab->pause_button);
+  gtk_widget_hide (tab->play_button); 
+}
+
+
+/**
+ * User clicked on the 'clean' button of a search tab.
+ * Stop completed downloads (or those that failed).  Should
+ * iterate over the underlying tree store and stop all
+ * completed entries.  Furthermore, if the resulting tree
+ * store is empty and has no search associated with it,
+ * the tab should be closed.
+ *
+ * @param button the button pressed by the user
+ * @param user_data the 'struct SearchTab' of the respective tab to clean up
+ */
+static void
+clear_downloads (GtkButton * button, gpointer user_data)
+{
+  struct SearchTab *tab = user_data;
+  struct SearchResult *sr;
+  GtkTreeModel *tm;
   GtkTreeIter iter;
+
+  tm = GTK_TREE_MODEL (tab->ts);
+  if (TRUE != gtk_tree_model_get_iter_first (tm, &iter))
+    return;
+  /* FIXME: this is a tree, what about cleaning up
+     of the children? */
+  do
+  {
+    gtk_tree_model_get (tm, &iter, 9, &sr, -1);
+    if ( (sr->download != NULL) &&
+        (sr->download->is_done == GNUNET_YES) )
+    {
+      /* got a finished download, stop it */
+      GNUNET_FS_download_stop (sr->download->dc, GNUNET_YES);
+    }
+    if ( (NULL == sr->download) &&
+        (NULL == sr->result) )
+    {
+      /* no active download and no associated FS-API search result;
+        so this must be some left-over entry from an opened 
+        directory; clean it up */
+      free_search_result (sr);
+    }
+  }
+  while (TRUE == gtk_tree_model_iter_next (tm, &iter));
+}
+
+
+/**
+ * We received a search error message from the FS library.
+ * Present it to the user in an appropriate form.
+ *
+ * @param tab search tab affected by the error message
+ * @param emsg the error message
+ */
+static void
+handle_search_error (struct SearchTab *tab, 
+                    const char *emsg)
+{
+  gtk_label_set_text (tab->label, _("Error!"));
+  gtk_widget_set_tooltip_text (GTK_WIDGET (tab->label), emsg);
+}
+
+
+/**
+ * Obtain the string we will use to describe a search result from
+ * the respective meta data.
+ *
+ * @param meta meta data to inspect
+ * @return description of the result in utf-8, never NULL
+ */
+static char *
+get_description_from_metadata (const struct GNUNET_CONTAINER_MetaData *meta)
+{
+  char *desc;
+  char *utf8_desc;
+
+  desc =
+      GNUNET_CONTAINER_meta_data_get_first_by_types (meta,
+                                                     
EXTRACTOR_METATYPE_PACKAGE_NAME,
+                                                     EXTRACTOR_METATYPE_TITLE,
+                                                     
EXTRACTOR_METATYPE_BOOK_TITLE,
+                                                     
EXTRACTOR_METATYPE_FILENAME,
+                                                     
EXTRACTOR_METATYPE_DESCRIPTION,
+                                                     
EXTRACTOR_METATYPE_SUMMARY,
+                                                     EXTRACTOR_METATYPE_ALBUM,
+                                                     
EXTRACTOR_METATYPE_COMMENT,
+                                                     
EXTRACTOR_METATYPE_SUBJECT,
+                                                     
EXTRACTOR_METATYPE_KEYWORDS,
+                                                     -1);
+  if (desc == NULL)
+    return GNUNET_strdup (_("no description supplied"));
+  utf8_desc =
+    GNUNET_FS_GTK_dubious_meta_to_utf8 (EXTRACTOR_METAFORMAT_UTF8, desc,
+                                       strlen (desc) + 1);
+  GNUNET_free (desc);
+  if (utf8_desc == NULL)
+    return GNUNET_strdup (_("no description supplied"));
+  return utf8_desc;
+}
+
+
+/**
+ * Obtain the mime type (or format description) will use to describe a search 
result from
+ * the respective meta data.
+ *
+ * @param meta meta data to inspect
+ * @return mime type to use, possibly NULL
+ */
+static char *
+get_mimetype_from_metadata (const struct GNUNET_CONTAINER_MetaData *meta)
+{
+  return GNUNET_CONTAINER_meta_data_get_first_by_types (meta,
+                                                       
EXTRACTOR_METATYPE_MIMETYPE,
+                                                       
EXTRACTOR_METATYPE_FORMAT,
+                                                       -1);
+}
+
+
+/**
+ * Some additional information about a search result has been
+ * received.  Update the view accordingly.
+ *
+ * @param sr search result that is being updated
+ * @param meta updated meta data
+ * @param availability_rank updated availability information
+ * @param availability_certainty updated availability certainty
+ * @param applicability_rank updated applicability information
+ */
+static void
+update_search_result (struct SearchResult *sr,
+                      const struct GNUNET_CONTAINER_MetaData *meta,
+                      int32_t availability_rank,
+                      uint32_t availability_certainty,
+                      uint32_t applicability_rank)
+{
+  GtkTreeIter iter;
+  struct GNUNET_CONTAINER_MetaData *ometa;
+  GtkTreeView *tv;
+  GtkTreePath *tp;
+  GtkTreeStore *ts;
+  GtkTreeModel *tm;
+  char *desc;
+  char *mime;
+  GdkPixbuf *pixbuf;
+  guint percent_avail;
+  GtkNotebook *notebook;
+  gint page;
+
+  if (sr == NULL)
+  {
+    GNUNET_break (0);
+    return;
+  }
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Updating search result SR=%p with %d, %u, %u\n",
+             sr, availability_rank,
+             availability_certainty, applicability_rank);
+  desc = get_description_from_metadata (meta);
+  mime = get_mimetype_from_metadata (meta);
+  pixbuf = GNUNET_FS_GTK_get_thumbnail_from_meta_data (meta);
+  tp = gtk_tree_row_reference_get_path (sr->rr);
+  tm = gtk_tree_row_reference_get_model (sr->rr);
+  ts = GTK_TREE_STORE (tm);
+  gtk_tree_model_get_iter (tm, &iter, tp);
+  gtk_tree_path_free (tp);
+  gtk_tree_model_get (tm, &iter, 0, &ometa, -1);
+  if (NULL != ometa)
+    GNUNET_CONTAINER_meta_data_destroy (ometa);
+  if (availability_certainty > 0)
+    percent_avail =
+        (availability_certainty +
+         availability_rank) * 50 / availability_certainty;
+  else
+    percent_avail = 0;
+  gtk_tree_store_set (ts, &iter, 
+                     0, GNUNET_CONTAINER_meta_data_duplicate (meta),
+                      3, pixbuf /* preview */ ,
+                      5, (guint) percent_avail /* percent availability */ ,
+                      6, desc /* filename/description */ ,
+                      10, mime, 11, (guint) applicability_rank, 12,
+                      (guint) availability_certainty, 13,
+                      (gint) availability_rank, -1);
+  if (pixbuf != NULL)
+    g_object_unref (pixbuf);
+  GNUNET_free (desc);
+  GNUNET_free_non_null (mime);
+
+  notebook =
+      GTK_NOTEBOOK (GNUNET_FS_GTK_get_main_window_object
+                    ("GNUNET_GTK_main_window_notebook"));
+  page = gtk_notebook_get_current_page (notebook);
+  if (gtk_notebook_get_nth_page (notebook, page) == sr->tab->frame)
+  {
+    tv = GTK_TREE_VIEW (gtk_builder_get_object
+                        (sr->tab->builder, "_search_result_frame"));
+    update_meta_data_views (tv, sr->tab);
+  }
+}
+
+
+/**
+ * Add a search result to the given search tab.  This function is called 
+ * not only for 'normal' search results but also for directories that
+ * are being opened and if the user manually enters a URI.
+ *
+ * @param tab search tab to extend, never NULL
+ * @param iter set to position where search result is added (OUT only)
+ * @param parent_rr reference to parent entry in search tab, NULL for normal
+ *                  search results, 
+ * @param uri uri to add, can be NULL for top-level entry of a directory 
opened from disk
+ *                        (in this case, we don't know the URI and should 
probably not
+ *                         bother to calculate it)
+ * @param meta metadata of the entry
+ * @param result associated FS search result (can be NULL if this result
+ *                        was part of a directory)
+ * @param applicability_rank how relevant is the result
+ * @return struct representing the search result (also stored in the tree
+ *                model at 'iter')
+ */
+struct SearchResult *
+GNUNET_GTK_add_search_result (struct SearchTab *tab, 
+                             GtkTreeIter *iter,
+                              GtkTreeRowReference *parent_rr,
+                              const struct GNUNET_FS_Uri *uri,
+                              const struct GNUNET_CONTAINER_MetaData *meta,
+                              struct GNUNET_FS_SearchResult *result,
+                              uint32_t applicability_rank)
+{
+  struct SearchResult *sr;
+  GtkTreePath *tp;
+  const char *status_colour;
+  char *desc;
+  char *mime;
+  char *uris;
+  GdkPixbuf *pixbuf;
+  GtkTreeIter *pitr;
+  GtkTreeIter pmem;
   GtkTreePath *path;
+  GtkTreeModel *tm;
+  GtkTreeStore *ts;
+  uint64_t fsize;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Changing publish PE=%p color to %s\n", 
pe, colour);
-  if (pe == NULL)
+  if (NULL == uri)
   {
+    /* opened directory file */
+    fsize = 0;
+    status_colour = "gray";
+    mime = NULL; /* FIXME: should we set mime to directory? */
+    uris = GNUNET_strdup (_("no URI"));
+  }
+  else
+  {
+    if ( (GNUNET_FS_uri_test_loc (uri)) ||
+        (GNUNET_FS_uri_test_chk (uri)) )
+    {
+      fsize = GNUNET_FS_uri_chk_get_file_size (uri);
+      mime = get_mimetype_from_metadata (meta);
+      status_colour = "white";
+    }
+    else
+    {
+      /* FIXME: create mime type for namespaces? */
+      /* FIXME: can we encounter ksk URIs here too? */
+      fsize = 0;
+      mime = GNUNET_strdup ("GNUnet namespace"); 
+      status_colour = "lightgreen";
+    }
+    uris = GNUNET_FS_uri_to_string (uri);
+  }
+  desc = get_description_from_metadata (meta);
+  pixbuf = GNUNET_FS_GTK_get_thumbnail_from_meta_data (meta);
+
+  sr = GNUNET_malloc (sizeof (struct SearchResult));
+  sr->result = result;
+  sr->tab = tab;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Allocated a search result SR=%p\n",
+             sr);
+  if (parent_rr != NULL)
+  {
+    /* get piter from parent */
+    path = gtk_tree_row_reference_get_path (parent_rr);
+    tm = gtk_tree_row_reference_get_model (parent_rr);
+    if (! gtk_tree_model_get_iter (GTK_TREE_MODEL (tm), &pmem, path))
+    {
+      GNUNET_break (0);
+      gtk_tree_path_free (path);
+      /* desperate measure: make top-level entry */
+      pitr = NULL;
+    }
+    else
+    {
+      pitr = &pmem;
+    }
+    ts = GTK_TREE_STORE (tm);
+  }
+  else
+  {
+    /* top-level result */
+    pitr = NULL;
+    ts = tab->ts;
+  }
+  gtk_tree_store_insert_with_values (ts, iter, pitr, G_MAXINT, 
+                                    0, GNUNET_CONTAINER_meta_data_duplicate 
(meta), 
+                                    1, (uri == NULL) ? NULL : 
GNUNET_FS_uri_dup (uri), 
+                                    2, fsize, 
+                                    3, pixbuf /* preview */ ,
+                                     4, 0 /* percent progress */ ,
+                                     5, 0 /* percent availability */ ,
+                                     6, desc /* filename/description */ ,
+                                     7, uris, 
+                                    8, status_colour, 
+                                    9, sr, 
+                                    10, mime,
+                                     11, applicability_rank, 
+                                    12, 0 /* avail-cert */ ,
+                                     13, 0, /* avail-rank */
+                                     14, (guint64) 0, /* completed */
+                                     15, NULL, /* downloaded_filename */
+                                     16, -1, /* downloaded_anonymity */
+                                     -1);
+  if (pixbuf != NULL)
+    g_object_unref (pixbuf);
+  GNUNET_free (uris);
+  GNUNET_free (desc);
+  GNUNET_free_non_null (mime);
+
+  /* remember in 'sr' where we added the result */
+  tp = gtk_tree_model_get_path (GTK_TREE_MODEL (ts), iter);
+  sr->rr = gtk_tree_row_reference_new (GTK_TREE_MODEL (ts), tp);
+  gtk_tree_path_free (tp);
+
+  /* move up to the outermost tab, in case this is an 'inner'
+     search (namespace update case) */
+  while (tab->parent != NULL)
+    tab = tab->parent->tab;
+  tab->num_results++;
+  
+  return sr;
+}
+
+
+/**
+ * We have received a search result from the FS API.  Add it to the
+ * respective search tab.  The search result can be an 'inner'
+ * search result (updated result for a namespace search) or a
+ * top-level search result.  Update the tree view and the label
+ * of the search tab accordingly.
+ *
+ * @param tab the search tab where the new result should be added
+ * @param parent parent search result (if this is a namespace update result), 
or NULL
+ * @param uri URI of the search result
+ * @param meta meta data for the result
+ * @param result FS API handle to the result
+ * @param applicability_rank how applicable is the result to the query
+ * @return struct representing the search result (also stored in the tree
+ *                model at 'iter')
+ */
+static struct SearchResult *
+process_search_result (struct SearchTab *tab, 
+                      struct SearchResult *parent,
+                       const struct GNUNET_FS_Uri *uri,
+                       const struct GNUNET_CONTAINER_MetaData *meta,
+                       struct GNUNET_FS_SearchResult *result,
+                       uint32_t applicability_rank)
+{
+  struct SearchResult *sr;
+  GtkTreeIter iter;
+
+  sr = GNUNET_GTK_add_search_result (tab, &iter,
+                                     (parent != NULL) ? parent->rr : NULL,
+                                    uri,
+                                     meta, result, applicability_rank);
+  update_search_label (tab);
+  return sr;
+}
+
+
+/**
+ * Setup a new search tab.
+ *
+ * @param sc context with FS for the search
+ * @param query the query
+ * @param anonymity anonymity level
+ */
+static struct SearchTab *
+setup_search (struct GNUNET_FS_SearchContext *sc,
+              const struct GNUNET_FS_Uri *query)
+{
+  struct SearchTab *tab;
+  GtkTreeView *tv;
+  GtkNotebook *notebook;
+  GtkWindow *sf;
+  gint pages;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+      "Setting up a search for %p\n", sc);
+
+  tab = GNUNET_malloc (sizeof (struct SearchTab));
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+      "Allocated a tab %p\n", tab);
+  GNUNET_CONTAINER_DLL_insert (search_tab_head, search_tab_tail, tab);
+  tab->sc = sc;
+  if (query == NULL)
+  {
+    tab->query_txt = GNUNET_strdup ("*");
+  }
+  else
+  {
+    /* FS_uri functions should produce UTF-8, so let them be */
+    if (GNUNET_FS_uri_test_ksk (query))
+      tab->query_txt = GNUNET_FS_uri_ksk_to_string_fancy (query);
+    else
+      tab->query_txt = GNUNET_FS_uri_to_string (query);
+  }
+  tab->builder = GNUNET_GTK_get_new_builder ("gnunet_fs_gtk_search_tab.glade",
+                                            tab);
+  tab->ts =
+      GTK_TREE_STORE (gtk_builder_get_object
+                      (tab->builder,
+                       "GNUNET_GTK_file_sharing_result_tree_store"));
+  /* load frame */
+  sf = GTK_WINDOW (gtk_builder_get_object
+                   (tab->builder, "_search_result_frame_window"));
+  tab->frame = gtk_bin_get_child (GTK_BIN (sf));
+  g_object_ref (tab->frame);
+  gtk_container_remove (GTK_CONTAINER (sf), tab->frame);
+  gtk_widget_destroy (GTK_WIDGET (sf));
+
+  /* load tab_label */
+  sf = GTK_WINDOW (gtk_builder_get_object
+                   (tab->builder, "_search_result_label_window"));
+  tab->tab_label = gtk_bin_get_child (GTK_BIN (sf));
+  g_object_ref (tab->tab_label);
+  gtk_container_remove (GTK_CONTAINER (sf), tab->tab_label);
+  gtk_widget_destroy (GTK_WIDGET (sf));
+
+  /* get refs to widgets */
+  tab->label =
+      GTK_LABEL (gtk_builder_get_object
+                 (tab->builder, "_search_result_label_window_label"));
+
+  /* FIXME: connect these signals using glade!!! */
+  tab->close_button =
+      GTK_WIDGET (gtk_builder_get_object
+                  (tab->builder, "_search_result_label_close_button"));
+  g_signal_connect (G_OBJECT (tab->close_button), "clicked",
+                    G_CALLBACK (stop_search), tab);
+  tab->clear_button =
+      GTK_WIDGET (gtk_builder_get_object
+                  (tab->builder, "_search_result_label_clear_button"));
+  g_signal_connect (G_OBJECT (tab->clear_button), "clicked",
+                    G_CALLBACK (clear_downloads), tab);
+  tab->play_button =
+      GTK_WIDGET (gtk_builder_get_object
+                  (tab->builder, "_search_result_label_play_button"));
+  g_signal_connect (G_OBJECT (tab->play_button), "clicked",
+                    G_CALLBACK (continue_search), tab);
+  tab->pause_button =
+      GTK_WIDGET (gtk_builder_get_object
+                  (tab->builder, "_search_result_label_pause_button"));
+  g_signal_connect (G_OBJECT (tab->pause_button), "clicked",
+                    G_CALLBACK (pause_search), tab);
+  /* patch text */
+  update_search_label (tab);
+
+  /* add signal handlers; FIXME: again, connect these with glade...  */
+  tv = GTK_TREE_VIEW (gtk_builder_get_object
+                      (tab->builder, "_search_result_frame"));
+  g_signal_connect (G_OBJECT (tv), "row-activated", 
+                   G_CALLBACK (start_download_row_activated), tab);
+  g_signal_connect (G_OBJECT (tv), "cursor-changed",
+                    G_CALLBACK (update_meta_data_views), tab);
+  g_signal_connect (G_OBJECT (tv), "button_press_event",
+                    G_CALLBACK (search_list_on_menu), tab);
+  g_signal_connect (G_OBJECT (tv), "popup-menu",
+                    G_CALLBACK (search_list_on_popup), tab);
+
+
+  /* make visible */
+  notebook =
+      GTK_NOTEBOOK (GNUNET_FS_GTK_get_main_window_object
+                    ("GNUNET_GTK_main_window_notebook"));
+  pages = gtk_notebook_get_n_pages (notebook);
+  gtk_notebook_insert_page (notebook, tab->frame, tab->tab_label, pages - 1);
+  gtk_notebook_set_current_page (notebook, pages - 1);
+  gtk_widget_show (GTK_WIDGET (notebook));
+  return tab;
+}
+
+
+/**
+ * Setup an "inner" search, that is a subtree representing namespace
+ * 'update' results.  We use a 'struct SearchTab' to represent this
+ * sub-search.  In the GUI, the presentation is similar to search
+ * results in a directory, except that this is for a namespace search
+ * result that gave pointers to an alternative keyword to use and this
+ * is the set of the results found for this alternative keyword.
+ *
+ * All of the 'widget' elements of the returned 'search tab' reference
+ * the parent search.  The whole construction is essentially a trick
+ * to allow us to store the FS-API's 'SearchContext' somewhere and to
+ * find it when we get this kind of 'inner' search results (so that we
+ * can then place them in the tree view in the right spot).
+ *
+ * FIXME: don't we need a bit more information then? Like exactly where
+ * this 'right spot' is?  Not sure how just having 'sc' helps there,
+ * as it is not a search result (!) to hang this up on!  This might
+ * essentially boil down to an issue with the FS API, not sure...
+ *
+ * @param sc context with FS for the search
+ * @param parent parent search tab
+ * @return struct representing the search result (also stored in the tree
+ *                model at 'iter')
+ */
+static struct SearchTab *
+setup_inner_search (struct GNUNET_FS_SearchContext *sc,
+                    struct SearchResult *parent)
+{
+  struct SearchTab *ret;
+
+  ret = GNUNET_malloc (sizeof (struct SearchTab));
+  ret->parent = parent;
+  ret->sc = sc;
+  ret->query_txt = parent->tab->query_txt;
+  ret->builder = parent->tab->builder;
+  ret->frame = parent->tab->frame;
+  ret->tab_label = parent->tab->tab_label;
+  ret->close_button = parent->tab->close_button;
+  ret->clear_button = parent->tab->clear_button;
+  ret->play_button = parent->tab->play_button;
+  ret->label = parent->tab->label;
+
+  return ret;
+}
+
+
+
+
+/**
+ * Setup a new top-level entry in the URI tab.  If necessary, create
+ * the URI tab first.
+ *
+ * @param iter set to the new entry
+ * @param srp set to search result
+ * @param meta metadata for the new entry
+ * @param uri URI for the new entry
+ * @return NULL on error, otherwise tree store matching iter
+ */
+struct SearchTab *
+GNUNET_GTK_add_to_uri_tab (GtkTreeIter * iter, struct SearchResult **srp,
+                           const struct GNUNET_CONTAINER_MetaData *meta,
+                           const struct GNUNET_FS_Uri *uri)
+{
+  struct SearchResult *sr;
+  GtkNotebook *notebook;
+  gint page;
+
+  if (uri_tab == NULL)
+  {
+    uri_tab = setup_search (NULL, NULL);
+    gtk_widget_set_visible (uri_tab->close_button, FALSE);
+    gtk_widget_set_visible (uri_tab->pause_button, FALSE);
+  }
+  else
+  {
+    /* make 'utab' the current page */
+    notebook =
+        GTK_NOTEBOOK (GNUNET_FS_GTK_get_main_window_object
+                      ("GNUNET_GTK_main_window_notebook"));
+    for (page = 0; page < gtk_notebook_get_n_pages (notebook); page++)
+      if (uri_tab->frame == gtk_notebook_get_nth_page (notebook, page))
+      {
+        gtk_notebook_set_current_page (notebook, page);
+        break;
+      }
+  }
+  sr = GNUNET_GTK_add_search_result (uri_tab, iter, NULL, uri, meta, NULL, 0);
+
+  if (NULL != srp)
+    *srp = sr;
+  return uri_tab;
+}
+
+
+
+
+
+
+/* ***************** Download event handling ****************** */
+
+
+/**
+ * Change the (background) color of the given download entry.
+ *
+ * @param de entry to change 
+ * @param color name of the color to use
+ */
+static void
+change_download_color (struct DownloadEntry *de, 
+                       const char *color)
+{
+  GtkTreeIter iter;
+  GtkTreePath *path;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
+             "Changing download DE=%p color to %s\n", 
+             de, color);
+  path = gtk_tree_row_reference_get_path (de->rr);
+  if (NULL == path)
+  {
     GNUNET_break (0);
-    return NULL;
+    gtk_tree_path_free (path);
+    return;
   }
-  path = gtk_tree_row_reference_get_path (pe->rr);
-  if (TRUE !=
-      gtk_tree_model_get_iter (GTK_TREE_MODEL (pe->tab->ts), &iter, path))
+  if (! gtk_tree_model_get_iter (GTK_TREE_MODEL (de->ts), &iter, path))
   {
     GNUNET_break (0);
     gtk_tree_path_free (path);
-    return pe;
+    return;
   }
   gtk_tree_path_free (path);
-  gtk_tree_store_set (pe->tab->ts, &iter, 2, colour, -1);
-  return pe;
+  gtk_tree_store_set (de->ts, &iter, 8, color, -1);
 }
 
 
+/**
+ * A download operation was stopped.  Remove all state associated with
+ * it and reset the search result's background color to 'white'.
+ *
+ * @param de the download that was stopped
+ */
 static void
-stop_download (struct DownloadEntry *de, int is_suspend)
+stop_download (struct DownloadEntry *de)
 {
   GtkTreeIter iter;
   GtkTreePath *path;
   GtkTreeModel *tm;
   struct SearchResult *search_result;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping download DE=%p, %s\n", de, 
is_suspend ? "temporarily" : "permanently");
   path = gtk_tree_row_reference_get_path (de->rr);
   tm = gtk_tree_row_reference_get_model (de->rr);
   if (path != NULL)
   {
-    if (TRUE != gtk_tree_model_get_iter (tm, &iter, path))
+    if (! gtk_tree_model_get_iter (tm, &iter, path))
+    {
       GNUNET_break (0);
+    }
     else
     {
       gtk_tree_model_get (tm, &iter, 9, &search_result, -1);
-      /*Always fails on downloads started by Download URI */
-      /*GNUNET_assert (search_result->download == de); */
+      GNUNET_assert (search_result->download == de); 
       search_result->download = NULL;
-      if (NULL == search_result->result)
-      {
-        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Removing it from the tree\n");
-        (void) gtk_tree_store_remove (GTK_TREE_STORE (tm), &iter);
-      }
-      else
-         change_download_colour (de, "white");
+      change_download_color (de, "white");
     }
     gtk_tree_path_free (path);
   }
@@ -978,7 +1821,7 @@
 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
       "Marking download error for DE=%p: %s\n", de, emsg);
-  de = change_download_colour (de, "red");
+  change_download_color (de, "red");
   de->is_done = GNUNET_YES;
   path = gtk_tree_row_reference_get_path (de->rr);
   if (TRUE !=
@@ -1015,37 +1858,12 @@
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "It is a directory, scan its 
contents\n");
     GNUNET_FS_GTK_mmap_and_scan (filename, &add_directory_entry, &ade);
   }
-  (void) change_download_colour (de, "green");
+  change_download_color (de, "green");
   return de;
 }
 
 
-static struct PublishEntry *
-mark_publish_progress (struct PublishEntry *pe, uint64_t size,
-                       uint64_t completed)
-{
-  GtkTreeIter iter;
-  GtkTreePath *path;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-      "Marking publicaation progress for PE=%p, %llu/%llu\n",
-      pe, completed, size);
-  path = gtk_tree_row_reference_get_path (pe->rr);
-  if (TRUE !=
-      gtk_tree_model_get_iter (GTK_TREE_MODEL (pe->tab->ts), &iter, path))
-  {
-    GNUNET_break (0);
-    gtk_tree_path_free (path);
-    return pe;
-  }
-  gtk_tree_path_free (path);
-  gtk_tree_store_set (pe->tab->ts, &iter, 3,
-                      (guint) ((size >
-                                0) ? (100 * completed /
-                                      size) : 100) /* progress */ ,
-                      -1);
-  return pe;
-}
 
 
 /**
@@ -1195,13 +2013,13 @@
   if (size > completed)
   {
     if (is_active)
-      change_download_colour (de, "yellow");
+      change_download_color (de, "yellow");
     else
-      change_download_colour (de, "blue");
+      change_download_color (de, "blue");
   }
   else
   {
-    change_download_colour (de, "green");
+    change_download_color (de, "green");
   }
   return de;
 }
@@ -1234,6 +2052,7 @@
       "Setting up download, initially DE=%p, PDE=%p for %p & %p into %llu/%llu 
`%s'\n",
       de, pde, sr, dc, completed, size, filename);
   GNUNET_assert (NULL != uri);
+  srp = NULL;
   if (de == NULL)
   {
     de = GNUNET_malloc (sizeof (struct DownloadEntry));
@@ -1285,14 +2104,18 @@
     return de;
   }
   gtk_tree_path_free (path);
-  gtk_tree_store_set (de->ts, &iter, 4,
-                      (guint) ((size >
+  gtk_tree_store_set (de->ts, &iter, 
+                     4,   (guint) ((size >
                                 0) ? (100 * completed /
                                       size) : 100) /* progress */ ,
                       6, filename /* filename/description */ ,
                       8, "blue" /* status colour: pending */ ,
+                     14, completed,
                       -1);
-  gtk_tree_store_set (de->ts, &iter, 14, completed, -1);
+  if (NULL != srp)
+    gtk_tree_store_set (de->ts, &iter, 
+                       9, srp,
+                       -1);
   return de;
 }
 
@@ -1301,119 +2124,82 @@
 
 
 
+/* ***************** Publish event handling ****************** */
+
+
+
+
 /**
- * Selected row has changed, update preview and metadata
- * areas.
+ * Change the (background) color of the given publish entry.
+ *
+ * @param pe entry to change 
+ * @param color name of the color to use
  */
 static void
-update_meta_data_views (GtkTreeView * tv, gpointer user_data)
+change_publish_color (struct PublishEntry *pe,
+                     const char *color)
 {
-  struct SearchTab *tab = user_data;
-  GtkImage *image;
-  GtkListStore *ms;
-  GtkTreeSelection *sel;
-  GtkTreeModel *model;
   GtkTreeIter iter;
-  struct GNUNET_CONTAINER_MetaData *meta;
-  GdkPixbuf *pixbuf;
+  GtkTreePath *path;
 
-  GNUNET_assert (tab->query_txt != NULL);
-  image =
-      GTK_IMAGE (GNUNET_FS_GTK_get_main_window_object
-                 ("GNUNET_GTK_main_window_preview_image"));
-  ms = GTK_LIST_STORE (GNUNET_FS_GTK_get_main_window_object
-                       ("GNUNET_GTK_meta_data_list_store"));
-
-  sel = gtk_tree_view_get_selection (tv);
-  gtk_list_store_clear (ms);
-  if (TRUE != gtk_tree_selection_get_selected (sel, &model, &iter))
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
+             "Changing publish PE=%p color to %s\n", 
+             pe, color);
+  path = gtk_tree_row_reference_get_path (pe->rr);
+  if (NULL == path)
   {
-    gtk_image_clear (image);
+    GNUNET_break (0);
     return;
   }
-  meta = NULL;
-  pixbuf = NULL;
-  gtk_tree_model_get (model, &iter, 0, &meta, 3, &pixbuf, -1);
-  if (pixbuf != NULL)
+  if (! gtk_tree_model_get_iter (GTK_TREE_MODEL (pe->tab->ts), &iter, path))
   {
-    gtk_image_set_from_pixbuf (image, pixbuf);
-    g_object_unref (G_OBJECT (pixbuf));
+    GNUNET_break (0);
+    gtk_tree_path_free (path);
+    return;
   }
-  if (meta != NULL)
-  {
-    GNUNET_CONTAINER_meta_data_iterate (meta,
-                                        
&GNUNET_FS_GTK_add_meta_data_to_list_store,
-                                        ms);
-  }
+  gtk_tree_path_free (path);
+  gtk_tree_store_set (pe->tab->ts, &iter, 2, color, -1);
+  return;
 }
 
 
-/**
- * Update the label for a search
- */
-static void
-update_search_label (struct SearchTab *tab)
+static struct PublishEntry *
+mark_publish_progress (struct PublishEntry *pe, uint64_t size,
+                       uint64_t completed)
 {
-  char *name;
+  GtkTreeIter iter;
+  GtkTreePath *path;
 
-  while (tab->parent != NULL)
-    tab = tab->parent->tab;
-  if (tab->num_results > 0)
-    GNUNET_asprintf (&name, "%.*s%s (%u)", 20, tab->query_txt,
-                     strlen (tab->query_txt) > 20 ? "..." : "",
-                     tab->num_results);
-  else
-    GNUNET_asprintf (&name, "%.*s%s", 20, tab->query_txt,
-                     strlen (tab->query_txt) > 20 ? "..." : "");
-  gtk_label_set_text (tab->label, name);
-  gtk_widget_set_tooltip_text (GTK_WIDGET (tab->label), tab->query_txt);
-  GNUNET_free (name);
-}
-
-
-/**
- * Close a search tab and free associated state.
- */
-static void
-close_search_tab (struct SearchTab *tab)
-{
-  GtkNotebook *notebook;
-  int index;
-  int i;
-
-  if (tab->parent != NULL)
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+      "Marking publicaation progress for PE=%p, %llu/%llu\n",
+      pe, completed, size);
+  path = gtk_tree_row_reference_get_path (pe->rr);
+  if (TRUE !=
+      gtk_tree_model_get_iter (GTK_TREE_MODEL (pe->tab->ts), &iter, path))
   {
-    /* not a top-level search, do not close tab here! */
-    GNUNET_free (tab);
-    return;
+    GNUNET_break (0);
+    gtk_tree_path_free (path);
+    return pe;
   }
-
-  notebook =
-      GTK_NOTEBOOK (GNUNET_FS_GTK_get_main_window_object
-                    ("GNUNET_GTK_main_window_notebook"));
-  index = -1;
-  for (i = gtk_notebook_get_n_pages (notebook) - 1; i >= 0; i--)
-    if (tab->frame == gtk_notebook_get_nth_page (notebook, i))
-      index = i;
-  gtk_notebook_remove_page (notebook, index);
-  g_object_unref (tab->builder);
-  GNUNET_free (tab->query_txt);
-  GNUNET_CONTAINER_DLL_remove (search_tab_head, search_tab_tail, tab);
-  if (tab == uri_tab)
-    uri_tab = NULL;
-  GNUNET_free (tab);
+  gtk_tree_path_free (path);
+  gtk_tree_store_set (pe->tab->ts, &iter, 3,
+                      (guint) ((size >
+                                0) ? (100 * completed /
+                                      size) : 100) /* progress */ ,
+                      -1);
+  return pe;
 }
 
 
 /**
  * Close a publish tab and free associated state.
  */
-static struct PublishEntry *
-handle_publish_completed (struct PublishEntry *ent,
+static void
+handle_publish_completed (struct PublishEntry *pe,
                           const struct GNUNET_FS_Uri *uri)
 {
-  ent->uri = GNUNET_FS_uri_dup (uri);
-  return change_publish_colour (ent, "green");
+  pe->uri = GNUNET_FS_uri_dup (uri);
+  change_publish_color (pe, "green");
 }
 
 
@@ -1421,11 +2207,12 @@
 /**
  * Handle error.
  */
-static struct PublishEntry *
-handle_publish_error (struct PublishEntry *ent, const char *emsg)
+static void
+handle_publish_error (struct PublishEntry *ent, 
+                     const char *emsg)
 {
   GNUNET_break (0);
-  return change_publish_colour (ent, "red");
+  change_publish_color (ent, "red");
 }
 
 
@@ -1471,621 +2258,20 @@
 }
 
 
-/**
- * Tell FS to stop a search.
- */
-static void
-stop_search (GtkButton * button, gpointer user_data)
-{
-  struct SearchTab *tab = user_data;
-  struct GNUNET_FS_SearchContext *sc;
 
-  if (NULL != (sc = tab->sc))
-  {
-    tab->sc = NULL;
-    GNUNET_FS_search_stop (sc);
-  }
-}
 
 
-static void
-free_search_result (struct SearchResult *sr)
-{
-  GtkTreePath *tp;
-  GtkTreeModel *tm;
-  GtkTreeIter iter;
-  struct GNUNET_FS_Uri *uri;
-  struct GNUNET_CONTAINER_MetaData *meta;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-      "Freeing a search result SR=%p\n", sr);
 
-  if (sr == NULL)
-  {
-    GNUNET_break (0);
-    return;
-  }
-  GNUNET_assert (sr->rr != NULL);
-  tp = gtk_tree_row_reference_get_path (sr->rr);
-  GNUNET_assert (tp != NULL);
-  tm = gtk_tree_row_reference_get_model (sr->rr);
-  GNUNET_assert (tm != NULL);
-  if (TRUE != gtk_tree_model_get_iter (tm, &iter, tp))
-  {
-    GNUNET_break (0);
-    gtk_tree_path_free (tp);
-    return;
-  }
-  gtk_tree_path_free (tp);
-  gtk_tree_model_get (tm, &iter, 0, &meta, 1, &uri, -1);
-  if (uri != NULL)
-    GNUNET_FS_uri_destroy (uri);
-  if (meta != NULL)
-    GNUNET_CONTAINER_meta_data_destroy (meta);
-  gtk_tree_row_reference_free (sr->rr);
-  (void) gtk_tree_store_remove (GTK_TREE_STORE (tm), &iter);
-  GNUNET_free (sr);
-}
 
 
-/**
- * Stop completed downloads (or those that failed).  Should
- * iterate over the underlying tree store and stop all
- * completed entries.  Furthermore, if the resulting tree
- * store is empty and has no search associated with it,
- * the tab should be closed.
- */
-static void
-clear_downloads (GtkButton * button, gpointer user_data)
-{
-  struct SearchTab *tab = user_data;
-  struct SearchResult *sr;
-  GtkTreeModel *tm;
-  GtkTreeIter iter;
 
-  tm = GTK_TREE_MODEL (tab->ts);
-  if (TRUE != gtk_tree_model_get_iter_first (tm, &iter))
-    return;
-  do
-  {
-    gtk_tree_model_get (tm, &iter, 9, &sr, -1);
-    if (sr->download != NULL)
-    {
-      if (sr->download->is_done == GNUNET_YES)
-        GNUNET_FS_download_stop (sr->download->dc, GNUNET_YES);
-    }
-    else if (sr->result == NULL)
-      free_search_result (sr);
-  }
-  while (TRUE == gtk_tree_model_iter_next (tm, &iter));
-}
 
 
 
-/**
- * Tell FS to pause a search.
- */
-static void
-pause_search (GtkButton * button, gpointer user_data)
-{
-  struct SearchTab *tab = user_data;
 
-  if (tab->sc != NULL)
-  {
-    GNUNET_FS_search_pause (tab->sc);
-    gtk_widget_show (tab->play_button);
-    gtk_widget_hide (tab->pause_button);
-  }
-}
 
-
 /**
- * Tell FS to resume a search.
- */
-static void
-continue_search (GtkButton * button, gpointer user_data)
-{
-  struct SearchTab *tab = user_data;
-
-  if (tab->sc != NULL)
-  {
-    GNUNET_FS_search_continue (tab->sc);
-    gtk_widget_show (tab->pause_button);
-    gtk_widget_hide (tab->play_button);
-  }
-}
-
-
-/**
- * FIXME: what exactly are we freeing here on 'row_activated'?
- */
-static void
-closure_notify_free (gpointer data, GClosure *closure)
-{
-  GNUNET_free (data);
-}
-
-
-/**
- * Setup a new search tab.
- *
- * @param sc context with FS for the search
- * @param query the query
- * @param anonymity anonymity level
- */
-static struct SearchTab *
-setup_search (struct GNUNET_FS_SearchContext *sc,
-              const struct GNUNET_FS_Uri *query)
-{
-  struct SearchTab *tab;
-  GtkTreeView *tv;
-  GtkNotebook *notebook;
-  GtkWindow *sf;
-  gint pages;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-      "Setting up a search for %p\n", sc);
-
-  tab = GNUNET_malloc (sizeof (struct SearchTab));
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-      "Allocated a tab %p\n", tab);
-  GNUNET_CONTAINER_DLL_insert (search_tab_head, search_tab_tail, tab);
-  tab->sc = sc;
-  if (query == NULL)
-  {
-    tab->query_txt = GNUNET_strdup ("*");
-  }
-  else
-  {
-    /* FS_uri functions should produce UTF-8, so let them be */
-    if (GNUNET_FS_uri_test_ksk (query))
-      tab->query_txt = GNUNET_FS_uri_ksk_to_string_fancy (query);
-    else
-      tab->query_txt = GNUNET_FS_uri_to_string (query);
-  }
-  tab->builder = GNUNET_GTK_get_new_builder ("gnunet_fs_gtk_search_tab.glade",
-                                            tab);
-  tab->ts =
-      GTK_TREE_STORE (gtk_builder_get_object
-                      (tab->builder,
-                       "GNUNET_GTK_file_sharing_result_tree_store"));
-  /* load frame */
-  sf = GTK_WINDOW (gtk_builder_get_object
-                   (tab->builder, "_search_result_frame_window"));
-  tab->frame = gtk_bin_get_child (GTK_BIN (sf));
-  g_object_ref (tab->frame);
-  gtk_container_remove (GTK_CONTAINER (sf), tab->frame);
-  gtk_widget_destroy (GTK_WIDGET (sf));
-
-  /* load tab_label */
-  sf = GTK_WINDOW (gtk_builder_get_object
-                   (tab->builder, "_search_result_label_window"));
-  tab->tab_label = gtk_bin_get_child (GTK_BIN (sf));
-  g_object_ref (tab->tab_label);
-  gtk_container_remove (GTK_CONTAINER (sf), tab->tab_label);
-  gtk_widget_destroy (GTK_WIDGET (sf));
-
-  /* get refs to widgets */
-  tab->label =
-      GTK_LABEL (gtk_builder_get_object
-                 (tab->builder, "_search_result_label_window_label"));
-
-  /* FIXME: connect these signals using glade!!! */
-  tab->close_button =
-      GTK_WIDGET (gtk_builder_get_object
-                  (tab->builder, "_search_result_label_close_button"));
-  g_signal_connect (G_OBJECT (tab->close_button), "clicked",
-                    G_CALLBACK (stop_search), tab);
-  tab->clear_button =
-      GTK_WIDGET (gtk_builder_get_object
-                  (tab->builder, "_search_result_label_clear_button"));
-  g_signal_connect (G_OBJECT (tab->clear_button), "clicked",
-                    G_CALLBACK (clear_downloads), tab);
-  tab->play_button =
-      GTK_WIDGET (gtk_builder_get_object
-                  (tab->builder, "_search_result_label_play_button"));
-  g_signal_connect (G_OBJECT (tab->play_button), "clicked",
-                    G_CALLBACK (continue_search), tab);
-  tab->pause_button =
-      GTK_WIDGET (gtk_builder_get_object
-                  (tab->builder, "_search_result_label_pause_button"));
-  g_signal_connect (G_OBJECT (tab->pause_button), "clicked",
-                    G_CALLBACK (pause_search), tab);
-  /* patch text */
-  update_search_label (tab);
-
-  /* add signal handlers; FIXME: again, connect these with glade...  */
-  tv = GTK_TREE_VIEW (gtk_builder_get_object
-                      (tab->builder, "_search_result_frame"));
-  g_signal_connect_data (G_OBJECT (tv), "row-activated", 
-                        G_CALLBACK (start_download_row_activated), tab, 
-                        &closure_notify_free, 0);
-  g_signal_connect (G_OBJECT (tv), "cursor-changed",
-                    G_CALLBACK (update_meta_data_views), tab);
-  g_signal_connect (G_OBJECT (tv), "button_press_event",
-                    G_CALLBACK (search_list_on_menu), tab);
-  g_signal_connect (G_OBJECT (tv), "popup-menu",
-                    G_CALLBACK (search_list_on_popup), tab);
-
-
-  /* make visible */
-  notebook =
-      GTK_NOTEBOOK (GNUNET_FS_GTK_get_main_window_object
-                    ("GNUNET_GTK_main_window_notebook"));
-  pages = gtk_notebook_get_n_pages (notebook);
-  gtk_notebook_insert_page (notebook, tab->frame, tab->tab_label, pages - 1);
-  gtk_notebook_set_current_page (notebook, pages - 1);
-  gtk_widget_show (GTK_WIDGET (notebook));
-  return tab;
-}
-
-
-/**
- * Setup an inner search.  FIXME: explain what an 'inner' search is...
- *
- * @param sc context with FS for the search
- * @param parent parent search tab
- * @param anonymity anonymity level
- */
-static struct SearchTab *
-setup_inner_search (struct GNUNET_FS_SearchContext *sc,
-                    struct SearchResult *parent)
-{
-  struct SearchTab *ret;
-
-  ret = GNUNET_malloc (sizeof (struct SearchTab));
-  ret->parent = parent;
-  ret->sc = sc;
-  ret->query_txt = parent->tab->query_txt;
-  ret->builder = parent->tab->builder;
-  ret->frame = parent->tab->frame;
-  ret->tab_label = parent->tab->tab_label;
-  ret->close_button = parent->tab->close_button;
-  ret->clear_button = parent->tab->clear_button;
-  ret->play_button = parent->tab->play_button;
-  ret->label = parent->tab->label;
-
-  return ret;
-}
-
-
-/**
- * Add a search result to the given search tab.
- *
- * @param tab search tab to extend
- * @param iter set to position where search result is added
- * @param parent_rr reference to parent entry in search tab
- * @param uri uri to add
- * @param meta metadata of the entry
- * @param result associated FS search result (can be NULL)
- * @param applicability_rank how relevant is the result
- * @return entry for the search result
- */
-struct SearchResult *
-GNUNET_GTK_add_search_result (struct SearchTab *tab, GtkTreeIter * iter,
-                              GtkTreeRowReference * parent_rr,
-                              const struct GNUNET_FS_Uri *uri,
-                              const struct GNUNET_CONTAINER_MetaData *meta,
-                              struct GNUNET_FS_SearchResult *result,
-                              uint32_t applicability_rank)
-{
-  struct SearchResult *sr;
-  GtkTreePath *tp;
-  const char *status_colour;
-  char *desc;
-  char *mime;
-  char *uris;
-  GdkPixbuf *pixbuf;
-  GtkTreeIter *pitr;
-  GtkTreeIter pmem;
-  GtkTreePath *path;
-  GtkTreeModel *tm;
-  GtkTreeStore *ts;
-  uint64_t fsize;
-
-  if ((uri != NULL) && (!GNUNET_FS_uri_test_loc (uri)) &&
-      (!GNUNET_FS_uri_test_chk (uri)))
-  {
-    fsize = 0;
-    mime = GNUNET_strdup ("GNUnet namespace");
-    status_colour = "lightgreen";
-  }
-  else if (uri != NULL)
-  {
-    fsize = GNUNET_FS_uri_chk_get_file_size (uri);
-    mime =
-        GNUNET_CONTAINER_meta_data_get_first_by_types (meta,
-                                                       
EXTRACTOR_METATYPE_MIMETYPE,
-                                                       
EXTRACTOR_METATYPE_FORMAT,
-                                                       -1);
-    status_colour = "white";
-  }
-  else
-  {
-    fsize = 0;
-    status_colour = "gray";
-    mime = NULL;
-  }
-  desc =
-      GNUNET_CONTAINER_meta_data_get_first_by_types (meta,
-                                                     
EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME,
-                                                     
EXTRACTOR_METATYPE_PACKAGE_NAME,
-                                                     EXTRACTOR_METATYPE_TITLE,
-                                                     
EXTRACTOR_METATYPE_BOOK_TITLE,
-                                                     
EXTRACTOR_METATYPE_FILENAME,
-                                                     
EXTRACTOR_METATYPE_DESCRIPTION,
-                                                     
EXTRACTOR_METATYPE_SUMMARY,
-                                                     EXTRACTOR_METATYPE_ALBUM,
-                                                     
EXTRACTOR_METATYPE_COMMENT,
-                                                     
EXTRACTOR_METATYPE_SUBJECT,
-                                                     
EXTRACTOR_METATYPE_KEYWORDS,
-                                                     -1);
-  if (desc == NULL)
-    desc = GNUNET_strdup (_("no description supplied"));
-  else
-  {
-    char *utf8_desc = NULL;
-
-    utf8_desc =
-        GNUNET_FS_GTK_dubious_meta_to_utf8 (EXTRACTOR_METAFORMAT_UTF8, desc,
-                                            strlen (desc) + 1);
-    GNUNET_free (desc);
-    if (utf8_desc != NULL)
-      desc = utf8_desc;
-    else
-      desc = NULL;
-  }
-  if (uri == NULL)
-    uris = GNUNET_strdup (_("no URI"));
-  else
-    uris = GNUNET_FS_uri_to_string (uri);
-
-  pixbuf = GNUNET_FS_GTK_get_thumbnail_from_meta_data (meta);
-  sr = GNUNET_malloc (sizeof (struct SearchResult));
-  sr->result = result;
-  sr->tab = tab;
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-      "Allocated a search result SR=%p\n", sr);
-  if (parent_rr != NULL)
-  {
-    /* get piter from parent */
-    path = gtk_tree_row_reference_get_path (parent_rr);
-    tm = gtk_tree_row_reference_get_model (parent_rr);
-    if (TRUE != gtk_tree_model_get_iter (GTK_TREE_MODEL (tm), &pmem, path))
-    {
-      GNUNET_break (0);
-      gtk_tree_path_free (path);
-      /* desperate measure: make top-level entry */
-      pitr = NULL;
-    }
-    else
-    {
-      pitr = &pmem;
-    }
-    ts = GTK_TREE_STORE (tm);
-  }
-  else
-  {
-    /* top-level result */
-    pitr = NULL;
-    ts = tab->ts;
-  }
-  gtk_tree_store_insert_with_values (ts, iter, pitr, G_MAXINT, 0,
-                                     GNUNET_CONTAINER_meta_data_duplicate
-                                     (meta), 1,
-                                     (uri ==
-                                      NULL) ? NULL : GNUNET_FS_uri_dup (uri), 
2,
-                                     (uri == NULL) ? 0 : fsize, 3,
-                                     pixbuf /* preview */ ,
-                                     4, 0 /* percent progress */ ,
-                                     5, 0 /* percent availability */ ,
-                                     6, desc /* filename/description */ ,
-                                     7, uris, 8, status_colour, 9, sr, 10, 
mime,
-                                     11, applicability_rank, 12,
-                                     0 /* avail-cert */ ,
-                                     13, 0, /* avail-rank */
-                                     14, (guint64) 0, /* completed */
-                                     15, NULL, /* downloaded_filename */
-                                     16, -1, /* downloaded_anonymity */
-                                     -1);
-  if (tab != NULL)
-  {
-    while (tab->parent != NULL)
-      tab = tab->parent->tab;
-    tab->num_results++;
-  }
-  if (pixbuf != NULL)
-    g_object_unref (pixbuf);
-  GNUNET_free (uris);
-  GNUNET_free_non_null (desc);
-  GNUNET_free_non_null (mime);
-  tp = gtk_tree_model_get_path (GTK_TREE_MODEL (ts), iter);
-  sr->rr = gtk_tree_row_reference_new (GTK_TREE_MODEL (ts), tp);
-  gtk_tree_path_free (tp);
-  return sr;
-}
-
-
-static struct SearchResult *
-process_search_result (void *cls, struct SearchResult *parent,
-                       const struct GNUNET_FS_Uri *uri,
-                       const struct GNUNET_CONTAINER_MetaData *meta,
-                       struct GNUNET_FS_SearchResult *result,
-                       uint32_t applicability_rank)
-{
-  struct SearchTab *tab = cls;
-  struct SearchResult *sr;
-  GtkTreeIter iter;
-
-  sr = GNUNET_GTK_add_search_result (tab, &iter,
-                                     (parent != NULL) ? parent->rr : NULL, uri,
-                                     meta, result, applicability_rank);
-  update_search_label (tab);
-  return sr;
-}
-
-
-/**
- * Setup a new top-level entry in the URI tab.  If necessary, create
- * the URI tab first.
- *
- * @param iter set to the new entry
- * @param srp set to search result
- * @param meta metadata for the new entry
- * @param uri URI for the new entry
- * @return NULL on error, otherwise tree store matching iter
- */
-struct SearchTab *
-GNUNET_GTK_add_to_uri_tab (GtkTreeIter * iter, struct SearchResult **srp,
-                           const struct GNUNET_CONTAINER_MetaData *meta,
-                           const struct GNUNET_FS_Uri *uri)
-{
-  struct SearchResult *sr;
-  GtkNotebook *notebook;
-  gint page;
-
-  if (uri_tab == NULL)
-  {
-    uri_tab = setup_search (NULL, NULL);
-    gtk_widget_set_visible (uri_tab->close_button, FALSE);
-    gtk_widget_set_visible (uri_tab->pause_button, FALSE);
-  }
-  else
-  {
-    /* make 'utab' the current page */
-    notebook =
-        GTK_NOTEBOOK (GNUNET_FS_GTK_get_main_window_object
-                      ("GNUNET_GTK_main_window_notebook"));
-    for (page = 0; page < gtk_notebook_get_n_pages (notebook); page++)
-      if (uri_tab->frame == gtk_notebook_get_nth_page (notebook, page))
-      {
-        gtk_notebook_set_current_page (notebook, page);
-        break;
-      }
-  }
-  sr = GNUNET_GTK_add_search_result (uri_tab, iter, NULL, uri, meta, NULL, 0);
-
-  if (NULL != srp)
-    *srp = sr;
-  return uri_tab;
-}
-
-
-static struct SearchTab *
-handle_search_error (struct SearchTab *sr, const char *emsg)
-{
-  /* FIXME: implement error handler */
-  GNUNET_break (0);
-  return sr;
-}
-
-
-static struct SearchResult *
-update_search_result (struct SearchResult *sr,
-                      const struct GNUNET_CONTAINER_MetaData *meta,
-                      int32_t availability_rank,
-                      uint32_t availability_certainty,
-                      uint32_t applicability_rank)
-{
-  GtkTreeIter iter;
-  struct GNUNET_CONTAINER_MetaData *ometa;
-  GtkTreeView *tv;
-  GtkTreePath *tp;
-  GtkTreeStore *ts;
-  GtkTreeModel *tm;
-  char *desc;
-  char *mime;
-  GdkPixbuf *pixbuf;
-  guint percent_avail;
-  GtkNotebook *notebook;
-  gint page;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-      "Updating search result SR=%p with %d, %u, %u\n",
-      sr, availability_rank, availability_certainty, applicability_rank);
-
-  if (sr == NULL)
-    return NULL;
-  desc =
-      GNUNET_CONTAINER_meta_data_get_first_by_types (meta,
-                                                     
EXTRACTOR_METATYPE_PACKAGE_NAME,
-                                                     EXTRACTOR_METATYPE_TITLE,
-                                                     
EXTRACTOR_METATYPE_BOOK_TITLE,
-                                                     
EXTRACTOR_METATYPE_FILENAME,
-                                                     
EXTRACTOR_METATYPE_DESCRIPTION,
-                                                     
EXTRACTOR_METATYPE_SUMMARY,
-                                                     EXTRACTOR_METATYPE_ALBUM,
-                                                     
EXTRACTOR_METATYPE_COMMENT,
-                                                     
EXTRACTOR_METATYPE_SUBJECT,
-                                                     
EXTRACTOR_METATYPE_KEYWORDS,
-                                                     -1);
-  if (desc == NULL)
-    desc = GNUNET_strdup (_("no description supplied"));
-  else
-  {
-    char *utf8_desc = NULL;
-
-    utf8_desc =
-        GNUNET_FS_GTK_dubious_meta_to_utf8 (EXTRACTOR_METAFORMAT_UTF8, desc,
-                                            strlen (desc) + 1);
-    GNUNET_free (desc);
-    if (utf8_desc != NULL)
-      desc = utf8_desc;
-    else
-      desc = NULL;
-  }
-  mime =
-      GNUNET_CONTAINER_meta_data_get_first_by_types (meta,
-                                                     
EXTRACTOR_METATYPE_MIMETYPE,
-                                                     EXTRACTOR_METATYPE_FORMAT,
-                                                     -1);
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-      "mime=`%s', desc=`%s'\n", mime, desc);
-  pixbuf = GNUNET_FS_GTK_get_thumbnail_from_meta_data (meta);
-  tp = gtk_tree_row_reference_get_path (sr->rr);
-  tm = gtk_tree_row_reference_get_model (sr->rr);
-  ts = GTK_TREE_STORE (tm);
-  gtk_tree_model_get_iter (tm, &iter, tp);
-  gtk_tree_path_free (tp);
-  gtk_tree_model_get (tm, &iter, 0, &ometa, -1);
-  if (meta != NULL)
-    GNUNET_CONTAINER_meta_data_destroy (ometa);
-  if (availability_certainty > 0)
-    percent_avail =
-        (availability_certainty +
-         availability_rank) * 50 / availability_certainty;
-  else
-    percent_avail = 0;
-  gtk_tree_store_set (ts, &iter, 0, GNUNET_CONTAINER_meta_data_duplicate 
(meta),
-                      3, pixbuf /* preview */ ,
-                      5, (guint) percent_avail /* percent availability */ ,
-                      6, desc /* filename/description */ ,
-                      10, mime, 11, (guint) applicability_rank, 12,
-                      (guint) availability_certainty, 13,
-                      (gint) availability_rank, -1);
-  if (pixbuf != NULL)
-    g_object_unref (pixbuf);
-  GNUNET_free_non_null (desc);
-  GNUNET_free_non_null (mime);
-
-  notebook =
-      GTK_NOTEBOOK (GNUNET_FS_GTK_get_main_window_object
-                    ("GNUNET_GTK_main_window_notebook"));
-  page = gtk_notebook_get_current_page (notebook);
-  if (gtk_notebook_get_nth_page (notebook, page) == sr->tab->frame)
-  {
-    tv = GTK_TREE_VIEW (gtk_builder_get_object
-                        (sr->tab->builder, "_search_result_frame"));
-
-    update_meta_data_views (tv, sr->tab);
-  }
-  return sr;
-}
-
-
-
-
-/**
  * Tell FS to stop all active publish operations.  Then close the tab.
  */
 static void
@@ -2226,6 +2412,10 @@
 }
 
 
+
+
+/* ***************** Master event handler ****************** */
+
 /**
  * Notification of FS to a client about the progress of an
  * operation.  Callbacks of this type will be used for uploads,
@@ -2260,16 +2450,13 @@
       return ret;
     if (info->value.publish.specifics.resume.message != NULL)
     {
-      ret =
-          handle_publish_error (ret,
-                                info->value.publish.specifics.resume.message);
+      handle_publish_error (ret,
+                           info->value.publish.specifics.resume.message);
     }
     else if (info->value.publish.specifics.resume.chk_uri != NULL)
     {
-      ret =
-          handle_publish_completed (ret,
-                                    info->value.publish.specifics.resume.
-                                    chk_uri);
+      handle_publish_completed (ret,
+                               info->value.publish.specifics.resume.chk_uri);
     }
     return ret;
   case GNUNET_FS_STATUS_PUBLISH_SUSPEND:
@@ -2280,12 +2467,13 @@
                                   info->value.publish.size,
                                   info->value.publish.completed);
   case GNUNET_FS_STATUS_PUBLISH_ERROR:
-    return handle_publish_error (info->value.publish.cctx,
-                                 info->value.publish.specifics.error.message);
+    handle_publish_error (info->value.publish.cctx,
+                         info->value.publish.specifics.error.message);
+    return info->value.publish.cctx;
   case GNUNET_FS_STATUS_PUBLISH_COMPLETED:
-    return handle_publish_completed (info->value.publish.cctx,
-                                     info->value.publish.specifics.completed.
-                                     chk_uri);
+    handle_publish_completed (info->value.publish.cctx,
+                             info->value.publish.specifics.completed.chk_uri);
+    return info->value.publish.cctx;
   case GNUNET_FS_STATUS_PUBLISH_STOPPED:
     handle_publish_stop (info->value.publish.cctx);
     return NULL;
@@ -2313,7 +2501,7 @@
     }
     return ret;
   case GNUNET_FS_STATUS_DOWNLOAD_SUSPEND:
-    stop_download (info->value.download.cctx, GNUNET_YES);
+    stop_download (info->value.download.cctx);
     return NULL;
   case GNUNET_FS_STATUS_DOWNLOAD_PROGRESS:
     return mark_download_progress (info->value.download.cctx,
@@ -2334,12 +2522,14 @@
                                     info->value.download.size,
                                     info->value.download.filename);
   case GNUNET_FS_STATUS_DOWNLOAD_STOPPED:
-    stop_download (info->value.download.cctx, GNUNET_NO);
+    stop_download (info->value.download.cctx);
     return NULL;
   case GNUNET_FS_STATUS_DOWNLOAD_ACTIVE:
-    return change_download_colour (info->value.download.cctx, "yellow");
+    change_download_color (info->value.download.cctx, "yellow");
+    return info->value.download.cctx;
   case GNUNET_FS_STATUS_DOWNLOAD_INACTIVE:
-    return change_download_colour (info->value.download.cctx, "blue");
+    change_download_color (info->value.download.cctx, "blue");
+    return info->value.download.cctx;
   case GNUNET_FS_STATUS_DOWNLOAD_LOST_PARENT:
     return download_lost_parent (info->value.download.cctx,
                                  info->value.download.size,
@@ -2353,9 +2543,8 @@
   case GNUNET_FS_STATUS_SEARCH_RESUME:
     ret = setup_search (info->value.search.sc, info->value.search.query);
     if (info->value.search.specifics.resume.message)
-      ret =
-          handle_search_error (ret,
-                               info->value.search.specifics.resume.message);
+      handle_search_error (ret,
+                          info->value.search.specifics.resume.message);
     return ret;
   case GNUNET_FS_STATUS_SEARCH_RESUME_RESULT:
     ret =
@@ -2366,15 +2555,16 @@
                                result,
                                info->value.search.specifics.resume_result.
                                applicability_rank);
-    return update_search_result (ret,
-                                 info->value.search.specifics.resume_result.
-                                 meta,
-                                 info->value.search.specifics.resume_result.
-                                 applicability_rank,
-                                 info->value.search.specifics.resume_result.
-                                 availability_certainty,
-                                 info->value.search.specifics.resume_result.
-                                 availability_rank);
+    update_search_result (ret,
+                         info->value.search.specifics.resume_result.
+                         meta,
+                         info->value.search.specifics.resume_result.
+                         applicability_rank,
+                         info->value.search.specifics.resume_result.
+                         availability_certainty,
+                         info->value.search.specifics.resume_result.
+                         availability_rank);
+    return ret;
   case GNUNET_FS_STATUS_SEARCH_SUSPEND:
     close_search_tab (info->value.search.cctx);
     return NULL;
@@ -2390,17 +2580,19 @@
     GNUNET_break (0);
     break;
   case GNUNET_FS_STATUS_SEARCH_UPDATE:
-    return update_search_result (info->value.search.specifics.update.cctx,
-                                 info->value.search.specifics.update.meta,
-                                 info->value.search.specifics.update.
-                                 applicability_rank,
-                                 info->value.search.specifics.update.
-                                 availability_certainty,
-                                 info->value.search.specifics.update.
-                                 availability_rank);
+    update_search_result (info->value.search.specifics.update.cctx,
+                         info->value.search.specifics.update.meta,
+                         info->value.search.specifics.update.
+                         applicability_rank,
+                         info->value.search.specifics.update.
+                         availability_certainty,
+                         info->value.search.specifics.update.
+                         availability_rank);
+    return info->value.search.specifics.update.cctx;
   case GNUNET_FS_STATUS_SEARCH_ERROR:
-    return handle_search_error (info->value.search.cctx,
-                                info->value.search.specifics.error.message);
+    handle_search_error (info->value.search.cctx,
+                        info->value.search.specifics.error.message);
+    return info->value.search.cctx;
   case GNUNET_FS_STATUS_SEARCH_PAUSED:
     return info->value.search.cctx;
   case GNUNET_FS_STATUS_SEARCH_CONTINUED:
@@ -2443,48 +2635,4 @@
 }
 
 
-/**
- * Page switched in main notebook, update thumbnail and
- * metadata views.
- */
-void
-GNUNET_GTK_main_window_notebook_switch_page_cb (GtkWidget * dummy,
-                                                gpointer data)
-{
-  GtkNotebook *notebook;
-  gint page;
-  GtkWidget *w;
-  struct SearchTab *tab;
-  GtkImage *image;
-  GtkListStore *ms;
-  GtkTreeView *tv;
-
-  notebook =
-      GTK_NOTEBOOK (GNUNET_FS_GTK_get_main_window_object
-                    ("GNUNET_GTK_main_window_notebook"));
-  page = gtk_notebook_get_current_page (notebook);
-  w = gtk_notebook_get_nth_page (notebook, page);
-  tab = search_tab_head;
-  while (tab != NULL)
-  {
-    if (tab->frame == w)
-    {
-      tv = GTK_TREE_VIEW (gtk_builder_get_object
-                          (tab->builder, "_search_result_frame"));
-      update_meta_data_views (tv, tab);
-      return;
-    }
-    tab = tab->next;
-  }
-  image =
-      GTK_IMAGE (GNUNET_FS_GTK_get_main_window_object
-                 ("GNUNET_GTK_main_window_preview_image"));
-  gtk_image_clear (image);
-  ms = GTK_LIST_STORE (GNUNET_FS_GTK_get_main_window_object
-                       ("GNUNET_GTK_meta_data_list_store"));
-  gtk_list_store_clear (ms);
-}
-
-
-
 /* end of gnunet-fs-gtk-event_handler.c */

Modified: gnunet-gtk/src/fs/gnunet-fs-gtk-event_handler.h
===================================================================
--- gnunet-gtk/src/fs/gnunet-fs-gtk-event_handler.h     2012-02-01 09:53:50 UTC 
(rev 19593)
+++ gnunet-gtk/src/fs/gnunet-fs-gtk-event_handler.h     2012-02-01 11:50:19 UTC 
(rev 19594)
@@ -26,6 +26,10 @@
 #include "gnunet-fs-gtk-common.h"
 
 
+/**
+ * State we keep for each (search) result entry in the
+ * tree view of a search tab.
+ */
 struct SearchResult;
 
 
@@ -54,31 +58,68 @@
    */
   struct GNUNET_FS_SearchContext *sc;
 
+  /**
+   * Text of the search query.
+   */
   char *query_txt;
 
+  /**
+   * GtkBuilder object for the search tab.
+   */ 
   GtkBuilder *builder;
 
+  /**
+   * Frame instance of the search tab.
+   */
   GtkWidget *frame;
 
+  /**
+   * The widget representing this search in the tab bar (not
+   * a GtkLabel, contains the actual label and the buttons).
+   */
   GtkWidget *tab_label;
 
+  /**
+   * Button to stop and close the search.
+   */
   GtkWidget *close_button;
 
+  /**
+   * Button to clear all entries for downloads that have completed.
+   */
   GtkWidget *clear_button;
 
+  /**
+   * Button to resume the search.
+   */
   GtkWidget *play_button;
 
+  /**
+   * Button to pause the search.
+   */
   GtkWidget *pause_button;
 
+  /**
+   * Textual label in the 'tab_label'
+   */
   GtkLabel *label;
 
+  /**
+   * Tree store with the search results.
+   */
   GtkTreeStore *ts;
 
+  /**
+   * Number of results we got for this search.
+   */
   unsigned int num_results;
 
 };
 
 
+/**
+ * Information we keep for each download.
+ */
 struct DownloadEntry
 {
 
@@ -156,14 +197,19 @@
 /**
  * Add a search result to the given search tab.
  *
- * @param tab search tab to extend
- * @param iter set to position where search result is added
- * @param parent_rr reference to parent entry in search tab
- * @param uri uri to add
+ * @param tab search tab to extend, never NULL
+ * @param iter set to position where search result is added (OUT only)
+ * @param parent_rr reference to parent entry in search tab, NULL for normal
+ *                  search results, 
+ * @param uri uri to add, can be NULL for top-level entry of a directory 
opened from disk
+ *                        (in this case, we don't know the URI and should 
probably not
+ *                         bother to calculate it)
  * @param meta metadata of the entry
- * @param result associated FS search result (can be NULL)
+ * @param result associated FS search result (can be NULL if this result
+ *                        was part of a directory)
  * @param applicability_rank how relevant is the result
- * @return entry for the search result
+ * @return struct representing the search result (also stored in the tree
+ *                model at 'iter')
  */
 struct SearchResult *
 GNUNET_GTK_add_search_result (struct SearchTab *tab, GtkTreeIter * iter,




reply via email to

[Prev in Thread] Current Thread [Next in Thread]