GList *
_filter_out_unshowable_recent_items (PengeEverythingPane *pane,
                                     ZeitgeistResultSet  *set)
{
  PengeEverythingPanePrivate *priv = GET_PRIVATE (pane);
  GList *ret = NULL;
  guint i; /* loop index */

  /* probably an error (or an actual empty set, obv), we need to return empty
   * list anyway */
  if (set == NULL)
    return NULL;

  while (zeitgeist_result_set_has_next (set))
  {
    ZeitgeistEvent *event = NULL;
    gchar *thumbnail_path = NULL;

    /* We have to do this because we edit the list */
    event = zeitgeist_result_set_next (set);

    /* FIXME, so far this is the assumption, then we can use a better data
     * structure for managing events with multiple subjects */
    g_assert (zeitgeist_event_num_subjects (event) == 1);

    for (i = 0; i < zeitgeist_event_num_subjects (event); ++i)
      {
        ZeitgeistSubject *s;
        GFile *file;
        const gchar *uri = NULL;

        s = zeitgeist_event_get_subject (event, i);
        g_assert (s != NULL);
        uri = zeitgeist_subject_get_uri (s);
        g_assert (uri != NULL);

        /* Just a small debug help :)
        g_warning ("%s: subj(%d): i=%s m=%s",
            zeitgeist_subject_get_uri (s),
            i,
            zeitgeist_subject_get_interpretation (s),
            zeitgeist_subject_get_manifestation (s));
        */


        /* Current detault template look for local files only, if it's not local,
         * it's probably a template error, log it and move on */
        if (!g_str_has_prefix (uri, "file:"))
          {
            g_warning ("uri %s for recent event is not local", uri);
            continue;
          }

        file = g_file_new_for_uri (uri);

        /* if the file does not exist anymore we ignore it and move on */
        if (!g_file_query_exists (file, NULL))
          break; /* consider the next event */

        thumbnail_path = mpl_utils_get_thumbnail_path (uri);

        /* add to the return list only if it has a valid thumbnail */
        if (thumbnail_path && g_file_test (thumbnail_path, G_FILE_TEST_EXISTS))
          ret = g_list_prepend (ret, g_object_ref (event));

        g_free (thumbnail_path);
        g_object_unref (file);
      }
  }

  return ret;
}
static void
_zeitgeist_log_find_received (GObject *source_object,
                              GAsyncResult *res,
                              gpointer user_data)
{
  ZeitgeistLog *log = ZEITGEIST_LOG (source_object);
  PengeEverythingPane *pane = user_data;
  PengeEverythingPanePrivate *priv;
  GList *sw_items, *recent_file_items, *l;
  ZeitgeistResultSet *set = NULL;
  GList *old_actors = NULL;
  ClutterActor *actor;
  gboolean show_welcome_tile = TRUE;
  gint recent_files_count, sw_items_count;
  GError *error = NULL;

  g_return_if_fail (PENGE_IS_EVERYTHING_PANE (user_data));

  priv = GET_PRIVATE (pane);

  set = zeitgeist_log_find_events_finish (log, res, &error);
  if (error != NULL)
    {
      g_warning (G_STRLOC ": Error obtaining recent files: %s",
          error->message);
      g_clear_error (&error);
    }

  /* It actually moves the interesting events into a list */
  recent_file_items = _filter_out_unshowable_recent_items (pane, set);
  recent_file_items = g_list_sort (recent_file_items,
                                   (GCompareFunc)_recent_files_sort_func);

  /* Get Sw items */
  sw_items = g_hash_table_get_values (priv->uuid_to_sw_items);
  sw_items = g_list_sort (sw_items,
                          (GCompareFunc)_sw_item_sort_compare_func);

  recent_files_count = priv->block_count * priv->ratio;

  if (recent_files_count > g_list_length (recent_file_items))
    recent_files_count = g_list_length (recent_file_items);

  sw_items_count = priv->block_count - recent_files_count;

  old_actors = g_hash_table_get_values (priv->pointer_to_actor);

  if (sw_items != NULL || recent_file_items != NULL)
  {
    if (priv->welcome_tile)
    {
      clutter_container_remove_actor (CLUTTER_CONTAINER (pane),
                                      priv->welcome_tile);
      priv->welcome_tile = NULL;
    }
  }

  while ((sw_items_count && sw_items) ||
         (recent_files_count && recent_file_items))
  {
    SwItem *sw_item = NULL;
    ZeitgeistEvent *recent_file_event = NULL;

    /* If no sw items -> force compare to favour recent file */
    if (sw_items_count && sw_items)
      sw_item = (SwItem *)sw_items->data;
    else
      sw_item = NULL;

    /* If no recent files -> force compare to favour sw stuff */
    if (recent_files_count && recent_file_items)
      recent_file_event = recent_file_items->data;
    else
      recent_file_event = NULL;

    if (_compare_item_and_event (sw_item, recent_file_event) < 1)
    {
      /* Sw item is newer */

      actor = g_hash_table_lookup (priv->pointer_to_actor,
                                   sw_item);
      if (!actor)
      {
        actor = _add_from_sw_item (pane, sw_item);
        g_hash_table_insert (priv->pointer_to_actor,
                             sw_item,
                             actor);

        /* Needed to remove from hash when we kill the actor */
        g_object_set_data (G_OBJECT (actor), "data-pointer", sw_item);
      }

      sw_items_count -= _sw_item_weight (sw_item);

      clutter_container_child_set (CLUTTER_CONTAINER (pane),
                                   actor,
                                   "col-span", _sw_item_weight (sw_item),
                                   NULL);

      sw_items = g_list_remove (sw_items, sw_item);

      show_welcome_tile = FALSE;
    } else {
      /* Recent file item is newer */

      actor = g_hash_table_lookup (priv->pointer_to_actor,
                                   recent_file_event);

      if (!actor)
      {
        const gchar *uri = NULL;
        gchar *thumbnail_path = NULL;
        ZeitgeistSubject *subj;

        /* FIXME we assume there is only one subject */
        subj = zeitgeist_event_get_subject (recent_file_event, 0);
        uri = zeitgeist_subject_get_uri (subj);

        thumbnail_path = mpl_utils_get_thumbnail_path (uri);

        actor = _add_from_recent_file_event (pane,
                                            recent_file_event,
                                            thumbnail_path);
        g_free (thumbnail_path);
        g_hash_table_insert (priv->pointer_to_actor,
                             recent_file_event,
                             actor);

        /* Needed to remove from hash when we kill the actor */
        g_object_set_data (G_OBJECT (actor), "data-pointer", recent_file_event);

        show_welcome_tile = FALSE;
      }

      recent_files_count--;

      g_object_unref (recent_file_event);
      recent_file_items = g_list_remove (recent_file_items,
                                         recent_file_event);
    }

    clutter_container_lower_child (CLUTTER_CONTAINER (pane),
                                   actor,
                                   NULL);

    old_actors = g_list_remove (old_actors, actor);
  }

  for (l = old_actors; l; l = l->next)
  {
    gpointer p;
    p = g_object_get_data (G_OBJECT (l->data), "data-pointer");

    if (p)
    {
      clutter_container_remove_actor (CLUTTER_CONTAINER (pane),
                                      CLUTTER_ACTOR (l->data));
      g_hash_table_remove (priv->pointer_to_actor, p);
    }
  }

  g_list_free (old_actors);

  if (show_welcome_tile && !priv->welcome_tile)
  {
    priv->welcome_tile = penge_welcome_tile_new ();
    clutter_container_add_actor (CLUTTER_CONTAINER (pane),
                                 priv->welcome_tile);
    clutter_container_child_set (CLUTTER_CONTAINER (pane),
                                 priv->welcome_tile,
                                 "col-span", 3,
                                 NULL);
  }

  g_list_free (sw_items);

  for (l = recent_file_items; l; l = l->next)
  {
    ZeitgeistEvent *recent_file_event = l->data;
    g_object_unref (recent_file_event);
  }
  g_list_free (recent_file_items);

}
static void _on_got_events (ZeitgeistResultSet *pEvents, GtkListStore *pModel)
{
	int i, n;
	ZeitgeistEvent *event;
	ZeitgeistSubject *subject;
	gint64 iTimeStamp;
	const gchar *cEventURI;
	guint id;
	gchar *cName = NULL, *cURI = NULL, *cIconName = NULL, *cIconPath, *cPath = NULL;
	double fOrder;
	int iVolumeID;
	gboolean bIsDirectory;
	GdkPixbuf *pixbuf;
	GtkTreeIter iter;
	GHashTable *pHashTable = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL);  // used to prevent doubles
	
	//\_____________ parse all the events.
	while (zeitgeist_result_set_has_next (pEvents))
	{
		#ifdef ZEITGEIST_1_0
		event = zeitgeist_result_set_next (pEvents);
		#else
		event = zeitgeist_result_set_next_value (pEvents);
		#endif
		iTimeStamp = zeitgeist_event_get_timestamp (event) / 1e3;
		id = zeitgeist_event_get_id (event);
		n = zeitgeist_event_num_subjects (event);
		if (n > 1)
			cd_debug (" +++ %s, %s, %d", zeitgeist_event_get_interpretation (event), zeitgeist_event_get_manifestation (event), n);
		for (i = 0; i < n; i++)
		{
			subject = zeitgeist_event_get_subject (event, i);
			
			//\_____________ prevent doubles.
			cEventURI = zeitgeist_subject_get_uri (subject);
			if (g_hash_table_lookup_extended  (pHashTable, cEventURI, NULL, NULL))
				continue;
			//g_print ("  %s:\n    %s, %s\n", cEventURI, zeitgeist_subject_get_interpretation (subject), zeitgeist_subject_get_manifestation (subject));
			
			//\_____________ ignore files that have been deleted
			cPath = g_filename_from_uri (cEventURI, NULL, NULL);  // NULL for anything else than file://*
			if (strncmp (cEventURI, "file://", 7) == 0 && ! g_file_test (cPath, G_FILE_TEST_EXISTS))
			{
				g_hash_table_insert (pHashTable, (gchar*)cEventURI, NULL);  // since we've checked it, insert it, even if we don't display it.
				g_free (cPath);
				continue;
			}
			//\_____________ get the text to display.
			const gchar *cText = zeitgeist_subject_get_text (subject);
			if (cText == NULL)  // skip empty texts (they are most of the times web page that redirect to another page, which is probably in the next event anyway).
				continue;
			
			//\_____________ find the icon.
			if (strncmp (cEventURI, "http", 4) == 0)  // gvfs is deadly slow to get info on distant URI...
			{
				cIconName = cairo_dock_search_icon_s_path ("text-html", myData.iDesiredIconSize);
			}
			else if (strncmp (cEventURI, "application://", 14) == 0)  // application URL
			{
				gchar *cClass = cairo_dock_register_class (cEventURI+14);
				cIconName = g_strdup (cairo_dock_get_class_icon (cClass));
				cText = cairo_dock_get_class_name (cClass);  // use the translated name
				g_free (cClass);
			}
			else
			{
				cairo_dock_fm_get_file_info (cEventURI, &cName, &cURI, &cIconName, &bIsDirectory, &iVolumeID, &fOrder, CAIRO_DOCK_FM_SORT_BY_DATE);
			}
			if (cIconName != NULL)
			{
				cIconPath = cairo_dock_search_icon_s_path (cIconName, myData.iDesiredIconSize);
				pixbuf = gdk_pixbuf_new_from_file_at_size (cIconPath, myData.iDesiredIconSize, myData.iDesiredIconSize, NULL);
				g_free (cIconPath);
			}
			else
				pixbuf = NULL;
			
			//\_____________ build the path to display.
			const gchar *cDisplayedPath = (cPath ? cPath : cEventURI);

			// need to escape the '&' (and ', etc.) because gtk-tooltips use markups by default.
			gchar *cEscapedPath = g_markup_escape_text (cDisplayedPath, -1);
			
			//\_____________ store in the model.
			memset (&iter, 0, sizeof (GtkTreeIter));
			gtk_list_store_append (GTK_LIST_STORE (pModel), &iter);
			gtk_list_store_set (GTK_LIST_STORE (pModel), &iter,
				CD_MODEL_NAME, cText,
				CD_MODEL_URI, cEventURI,
				CD_MODEL_PATH, cEscapedPath,
				CD_MODEL_ICON, pixbuf,
				CD_MODEL_DATE, iTimeStamp,
				CD_MODEL_ID, id, -1);
			
			g_free (cIconName);
			cIconName = NULL;
			g_free (cName);
			cName = NULL;
			g_free (cURI);
			cURI = NULL;
			if (pixbuf)
				g_object_unref (pixbuf);
			g_free (cPath);
			g_free (cEscapedPath);
			
			g_hash_table_insert (pHashTable, (gchar*)cEventURI, NULL);  // cEventURI stays valid in this function.
		}
	}
	g_hash_table_destroy (pHashTable);
}