static void
photos_tracker_controller_cursor_next (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
  PhotosTrackerController *self = PHOTOS_TRACKER_CONTROLLER (user_data);
  PhotosTrackerControllerPrivate *priv = self->priv;
  TrackerSparqlCursor *cursor = TRACKER_SPARQL_CURSOR (source_object);
  gboolean valid;
  gint64 now;

  valid = tracker_sparql_cursor_next_finish (cursor, res, NULL); /* TODO: use GError */
  if (!valid)
    {
      tracker_sparql_cursor_close (cursor);
      photos_tracker_controller_query_finished (self, NULL);
      g_object_unref (self);
      return;
    }

  now = g_get_monotonic_time ();
  photos_debug (PHOTOS_DEBUG_TRACKER, "Query Cursor: %" G_GINT64_FORMAT, (now - priv->last_query_time) / 1000000);

  photos_item_manager_add_item (PHOTOS_ITEM_MANAGER (priv->item_mngr), cursor);
  tracker_sparql_cursor_next_async (cursor,
                                    priv->cancellable,
                                    photos_tracker_controller_cursor_next,
                                    self);
}
static void
photos_fetch_collections_job_cursor_next (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
  PhotosFetchCollectionsJob *self = PHOTOS_FETCH_COLLECTIONS_JOB (user_data);
  TrackerSparqlCursor *cursor = TRACKER_SPARQL_CURSOR (source_object);
  GError *error;
  gboolean valid;
  gchar *urn;

  error = NULL;
  valid = tracker_sparql_cursor_next_finish (cursor, res, &error);
  if (error != NULL)
    {
      g_warning ("Unable to fetch collections: %s", error->message);
      g_error_free (error);
      goto end;
    }
  if (!valid)
    goto end;

  urn = g_strdup (tracker_sparql_cursor_get_string (cursor, 0, NULL));
  self->collections = g_list_prepend (self->collections, urn);

  tracker_sparql_cursor_next_async (cursor,
                                    NULL,
                                    photos_fetch_collections_job_cursor_next,
                                    self);
  return;

 end:
  self->collections = g_list_reverse (self->collections);
  photos_fetch_collections_job_emit_callback (self);
  tracker_sparql_cursor_close (cursor);
  g_object_unref (self);
}
static void
photos_camera_cache_cursor_next (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
  GTask *task = G_TASK (user_data);
  PhotosCameraCache *self;
  PhotosCameraCachePrivate *priv;
  TrackerSparqlCursor *cursor = TRACKER_SPARQL_CURSOR (source_object);
  GError *error;
  const gchar *manufacturer;
  const gchar *model;
  gchar *camera;
  gpointer key;

  self = PHOTOS_CAMERA_CACHE (g_task_get_source_object (task));
  priv = self->priv;

  error = NULL;
  tracker_sparql_cursor_next_finish (cursor, res, &error);
  if (error != NULL)
    {
      g_task_return_error (task, error);
      goto out;
    }

  manufacturer = tracker_sparql_cursor_get_string (cursor, 0, NULL);
  model = tracker_sparql_cursor_get_string (cursor, 1, NULL);

  if (manufacturer == NULL && model == NULL)
    camera = NULL;
  else if (manufacturer == NULL || g_str_has_prefix (model, manufacturer))
    camera = g_strdup (model);
  else if (model == NULL)
    camera = g_strdup (manufacturer);
  else
    camera = g_strconcat (manufacturer, " ", model, NULL);

  key = g_task_get_task_data (task);
  g_hash_table_insert (priv->cache, key, camera);

  g_task_return_pointer (task, g_strdup (camera), g_free);

 out:
  tracker_sparql_cursor_close (cursor);
  g_object_unref (task);
}
static void
photos_offset_controller_cursor_next (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
  PhotosOffsetController *self = PHOTOS_OFFSET_CONTROLLER (user_data);
  PhotosOffsetControllerPrivate *priv = self->priv;
  TrackerSparqlCursor *cursor = TRACKER_SPARQL_CURSOR (source_object);
  gboolean valid;

  valid = tracker_sparql_cursor_next_finish (cursor, res, NULL);
  if (valid)
    {
      priv->count = (gint) tracker_sparql_cursor_get_integer (cursor, 0);
      g_signal_emit (self, signals[COUNT_CHANGED], 0, priv->count);
    }

  tracker_sparql_cursor_close (cursor);
  g_object_unref (self);
}