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_tracker_search_controller_search_match_active_changed (PhotosTrackerSearchController *self)
{
  const gchar *str;

  str = photos_search_controller_get_string (self->priv->srch_cntrlr);
  if (str == NULL || str[0] == '\0')
    return;

  photos_tracker_controller_refresh_for_object (PHOTOS_TRACKER_CONTROLLER (self));
}
static void
photos_tracker_search_controller_col_active_changed (PhotosTrackerSearchController *self)
{
  PhotosWindowMode mode;

  mode = photos_mode_controller_get_window_mode (self->priv->mode_cntrlr);
  if (mode != PHOTOS_WINDOW_MODE_SEARCH)
    return;

  photos_tracker_controller_refresh_for_object (PHOTOS_TRACKER_CONTROLLER (self));
}
static void
photos_tracker_controller_dispose (GObject *object)
{
  PhotosTrackerController *self = PHOTOS_TRACKER_CONTROLLER (object);
  PhotosTrackerControllerPrivate *priv = self->priv;

  g_clear_object (&priv->src_mngr);
  g_clear_object (&priv->offset_cntrlr);
  g_clear_object (&priv->queue);

  G_OBJECT_CLASS (photos_tracker_controller_parent_class)->dispose (object);
}
static void
photos_tracker_controller_finalize (GObject *object)
{
  PhotosTrackerController *self = PHOTOS_TRACKER_CONTROLLER (object);
  PhotosTrackerControllerPrivate *priv = self->priv;

  g_clear_error (&priv->queue_error);

  if (priv->current_query != NULL)
    photos_query_free (priv->current_query);

  G_OBJECT_CLASS (photos_tracker_controller_parent_class)->finalize (object);
}
static void
photos_tracker_controller_constructed (GObject *object)
{
  PhotosTrackerController *self = PHOTOS_TRACKER_CONTROLLER (object);
  PhotosTrackerControllerPrivate *priv = self->priv;

  G_OBJECT_CLASS (photos_tracker_controller_parent_class)->constructed (object);

  priv->offset_cntrlr = PHOTOS_TRACKER_CONTROLLER_GET_CLASS (self)->get_offset_controller (self);
  g_signal_connect_swapped (priv->offset_cntrlr,
                            "offset-changed",
                            G_CALLBACK (photos_tracker_controller_offset_changed),
                            self);
}
static void
photos_tracker_controller_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
{
  PhotosTrackerController *self = PHOTOS_TRACKER_CONTROLLER (object);

  switch (prop_id)
    {
    case PROP_MODE:
      self->priv->mode = (PhotosWindowMode) g_value_get_enum (value);
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}
static void
photos_tracker_controller_finalize (GObject *object)
{
  PhotosTrackerController *self = PHOTOS_TRACKER_CONTROLLER (object);
  PhotosTrackerControllerPrivate *priv = self->priv;

  if (priv->item_mngr != NULL)
    g_object_remove_weak_pointer (G_OBJECT (priv->item_mngr), (gpointer *) &priv->item_mngr);

  if (priv->mode_cntrlr != NULL)
    g_object_remove_weak_pointer (G_OBJECT (priv->mode_cntrlr), (gpointer *) &priv->mode_cntrlr);

  g_clear_error (&priv->queue_error);

  if (priv->current_query != NULL)
    photos_query_free (priv->current_query);

  G_OBJECT_CLASS (photos_tracker_controller_parent_class)->finalize (object);
}
static void
photos_tracker_controller_query_executed (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
  PhotosTrackerController *self = PHOTOS_TRACKER_CONTROLLER (user_data);
  TrackerSparqlConnection *connection = TRACKER_SPARQL_CONNECTION (source_object);
  GError *error;
  TrackerSparqlCursor *cursor;

  error = NULL;
  cursor = tracker_sparql_connection_query_finish (connection, res, &error);
  if (error != NULL)
    {
      photos_tracker_controller_query_finished (self, error);
      g_error_free (error);
      return;
    }

  tracker_sparql_cursor_next_async (cursor,
                                    self->priv->cancellable,
                                    photos_tracker_controller_cursor_next,
                                    g_object_ref (self));
  g_object_unref (cursor);
}