1 /*
2  * Photos - access, organize and share your photos on GNOME
3  * Copyright © 2012 – 2019 Red Hat, Inc.
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 /* Based on code from:
20  *   + Documents
21  */
22 
23 
24 #include "config.h"
25 
26 #include <dazzle.h>
27 #include <glib.h>
28 #include <glib/gi18n.h>
29 
30 #include <gio/gio.h>
31 
32 #include "photos-base-manager.h"
33 #include "photos-debug.h"
34 #include "photos-enums.h"
35 #include "photos-filterable.h"
36 #include "photos-item-manager.h"
37 #include "photos-marshalers.h"
38 #include "photos-query-builder.h"
39 #include "photos-search-context.h"
40 #include "photos-tracker-controller.h"
41 #include "photos-tracker-queue.h"
42 
43 
44 struct _PhotosTrackerControllerPrivate
45 {
46   GCancellable *cancellable;
47   GError *queue_error;
48   PhotosBaseManager *item_mngr;
49   PhotosBaseManager *src_mngr;
50   PhotosModeController *mode_cntrlr;
51   PhotosOffsetController *offset_cntrlr;
52   PhotosQuery *current_query;
53   PhotosTrackerQueue *queue;
54   PhotosWindowMode mode;
55   gboolean delay_start;
56   gboolean is_frozen;
57   gboolean is_started;
58   gboolean query_queued;
59   gboolean querying;
60   gboolean refresh_pending;
61   gint query_queued_flags;
62   gint64 last_query_time;
63   guint reset_count_id;
64 };
65 
66 enum
67 {
68   PROP_0,
69   PROP_DELAY_START,
70   PROP_MODE
71 };
72 
73 enum
74 {
75   QUERY_ERROR,
76   QUERY_STATUS_CHANGED,
77   LAST_SIGNAL
78 };
79 
80 static guint signals[LAST_SIGNAL] = { 0 };
81 
82 
83 G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (PhotosTrackerController, photos_tracker_controller, G_TYPE_OBJECT);
84 DZL_DEFINE_COUNTER (instances,
85                     "PhotosTrackerController",
86                     "Instances",
87                     "Number of PhotosTrackerController instances")
88 
89 
90 enum
91 {
92   RESET_COUNT_TIMEOUT = 500 /* ms */
93 };
94 
95 typedef enum
96 {
97   PHOTOS_TRACKER_REFRESH_FLAGS_NONE = 0,
98   PHOTOS_TRACKER_REFRESH_FLAGS_DONT_SET_QUERY_STATUS = 1 << 0,
99   PHOTOS_TRACKER_REFRESH_FLAGS_RESET_OFFSET = 1 << 1,
100 } PhotosTrackerRefreshFlags;
101 
102 static void photos_tracker_controller_refresh_internal (PhotosTrackerController *self, gint flags);
103 static void photos_tracker_controller_set_query_status (PhotosTrackerController *self, gboolean query_status);
104 
105 
106 static gboolean
photos_tracker_controller_reset_count_timeout(gpointer user_data)107 photos_tracker_controller_reset_count_timeout (gpointer user_data)
108 {
109   PhotosTrackerController *self = PHOTOS_TRACKER_CONTROLLER (user_data);
110   PhotosTrackerControllerPrivate *priv;
111 
112   priv = photos_tracker_controller_get_instance_private (self);
113 
114   priv->reset_count_id = 0;
115   photos_offset_controller_reset_count (priv->offset_cntrlr);
116   return G_SOURCE_REMOVE;
117 }
118 
119 
120 static void
photos_tracker_controller_reset_constraint(PhotosTrackerController * self)121 photos_tracker_controller_reset_constraint (PhotosTrackerController *self)
122 {
123   PhotosTrackerControllerPrivate *priv;
124   PhotosBaseManager *item_mngr_chld;
125   gboolean constrain;
126   gint count;
127   gint offset;
128   gint step;
129 
130   priv = photos_tracker_controller_get_instance_private (self);
131 
132   item_mngr_chld = photos_item_manager_get_for_mode (PHOTOS_ITEM_MANAGER (priv->item_mngr), priv->mode);
133   count = (gint) photos_base_manager_get_objects_count (item_mngr_chld);
134 
135   offset = photos_offset_controller_get_offset (priv->offset_cntrlr);
136   step = photos_offset_controller_get_step (priv->offset_cntrlr);
137 
138   constrain = (count >= offset + step) ? TRUE : FALSE;
139   photos_item_manager_set_constraints_for_mode (PHOTOS_ITEM_MANAGER (priv->item_mngr), constrain, priv->mode);
140 }
141 
142 static void
photos_tracker_controller_item_added_removed(PhotosTrackerController * self)143 photos_tracker_controller_item_added_removed (PhotosTrackerController *self)
144 {
145   PhotosTrackerControllerPrivate *priv;
146 
147   priv = photos_tracker_controller_get_instance_private (self);
148 
149   /* Update the count so that PhotosOffsetController has the correct
150    * values. Otherwise things like loading more items and "No
151    * Results" page will not work correctly.
152    */
153 
154   if (priv->reset_count_id == 0)
155     {
156       priv->reset_count_id = g_timeout_add (RESET_COUNT_TIMEOUT,
157                                             photos_tracker_controller_reset_count_timeout,
158                                             self);
159     }
160 
161   photos_tracker_controller_reset_constraint (self);
162 }
163 
164 
165 static void
photos_tracker_controller_query_error(PhotosTrackerController * self,GError * error)166 photos_tracker_controller_query_error (PhotosTrackerController *self, GError *error)
167 {
168   const gchar *primary;
169 
170   if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
171     return;
172 
173   if (g_error_matches (error, TRACKER_SPARQL_ERROR, TRACKER_SPARQL_ERROR_INTERNAL))
174     primary = _("Unable to find Tracker on your operating system");
175   else
176     primary = _("Unable to fetch the list of photos");
177 
178   g_signal_emit (self, signals[QUERY_ERROR], 0, primary, error->message);
179 }
180 
181 
182 static void
photos_tracker_controller_query_finished(PhotosTrackerController * self,GError * error)183 photos_tracker_controller_query_finished (PhotosTrackerController *self, GError *error)
184 {
185   PhotosTrackerControllerPrivate *priv;
186 
187   priv = photos_tracker_controller_get_instance_private (self);
188 
189   photos_tracker_controller_set_query_status (self, FALSE);
190 
191   if (error != NULL)
192     photos_tracker_controller_query_error (self, error);
193   else
194     photos_offset_controller_reset_count (priv->offset_cntrlr);
195 
196   if (priv->query_queued)
197     {
198       priv->query_queued = FALSE;
199       photos_tracker_controller_refresh_internal (self, priv->query_queued_flags);
200     }
201 }
202 
203 
204 static void
photos_tracker_controller_cursor_next(GObject * source_object,GAsyncResult * res,gpointer user_data)205 photos_tracker_controller_cursor_next (GObject *source_object, GAsyncResult *res, gpointer user_data)
206 {
207   g_autoptr (PhotosTrackerController) self = PHOTOS_TRACKER_CONTROLLER (user_data);
208   PhotosTrackerControllerPrivate *priv;
209   TrackerSparqlCursor *cursor = TRACKER_SPARQL_CURSOR (source_object);
210   gboolean success;
211   gint64 now;
212 
213   priv = photos_tracker_controller_get_instance_private (self);
214 
215   if (priv->item_mngr == NULL)
216     goto out;
217 
218   {
219     g_autoptr (GError) error = NULL;
220 
221     /* Note that tracker_sparql_cursor_next_finish can return FALSE even
222      * without an error.
223      */
224     success = tracker_sparql_cursor_next_finish (cursor, res, &error);
225     if (error != NULL)
226       {
227         photos_tracker_controller_query_finished (self, error);
228         goto out;
229       }
230   }
231 
232   if (!success)
233     {
234       tracker_sparql_cursor_close (cursor);
235       photos_tracker_controller_query_finished (self, NULL);
236       goto out;
237     }
238 
239   now = g_get_monotonic_time ();
240   photos_debug (PHOTOS_DEBUG_TRACKER,
241                 "Query Cursor: %" G_GINT64_FORMAT " seconds",
242                 (now - priv->last_query_time) / 1000000);
243 
244   photos_item_manager_add_item_for_mode (PHOTOS_ITEM_MANAGER (priv->item_mngr),
245                                          PHOTOS_TRACKER_CONTROLLER_GET_CLASS (self)->base_item_type,
246                                          priv->mode,
247                                          cursor);
248 
249   tracker_sparql_cursor_next_async (cursor,
250                                     priv->cancellable,
251                                     photos_tracker_controller_cursor_next,
252                                     g_object_ref (self));
253 
254  out:
255   return;
256 }
257 
258 
259 static void
photos_tracker_controller_query_executed(GObject * source_object,GAsyncResult * res,gpointer user_data)260 photos_tracker_controller_query_executed (GObject *source_object, GAsyncResult *res, gpointer user_data)
261 {
262   PhotosTrackerController *self = PHOTOS_TRACKER_CONTROLLER (user_data);
263   PhotosTrackerControllerPrivate *priv;
264   TrackerSparqlConnection *connection = TRACKER_SPARQL_CONNECTION (source_object);
265   TrackerSparqlCursor *cursor; /* Use g_autoptr */
266 
267   priv = photos_tracker_controller_get_instance_private (self);
268 
269   {
270     g_autoptr (GError) error = NULL;
271 
272     cursor = tracker_sparql_connection_query_finish (connection, res, &error);
273     if (error != NULL)
274       {
275         photos_tracker_controller_query_finished (self, error);
276         return;
277       }
278   }
279 
280   tracker_sparql_cursor_next_async (cursor,
281                                     priv->cancellable,
282                                     photos_tracker_controller_cursor_next,
283                                     g_object_ref (self));
284   g_object_unref (cursor);
285 }
286 
287 
288 static void
photos_tracker_controller_perform_current_query(PhotosTrackerController * self)289 photos_tracker_controller_perform_current_query (PhotosTrackerController *self)
290 {
291   PhotosTrackerControllerPrivate *priv;
292   const gchar *type_name;
293   g_autofree gchar *tag = NULL;
294 
295   priv = photos_tracker_controller_get_instance_private (self);
296 
297   g_clear_object (&priv->current_query);
298   priv->current_query = PHOTOS_TRACKER_CONTROLLER_GET_CLASS (self)->get_query (self);
299   g_return_if_fail (priv->current_query != NULL);
300 
301   type_name = G_OBJECT_TYPE_NAME (self);
302   tag = g_strdup_printf ("%s: %s", type_name, G_STRFUNC);
303   photos_query_set_tag (priv->current_query, tag);
304 
305   g_object_unref (priv->cancellable);
306   priv->cancellable = g_cancellable_new ();
307 
308   if (G_UNLIKELY (priv->queue == NULL))
309     {
310       photos_tracker_controller_query_error (self, priv->queue_error);
311       goto out;
312     }
313 
314   photos_tracker_queue_select (priv->queue,
315                                priv->current_query,
316                                priv->cancellable,
317                                photos_tracker_controller_query_executed,
318                                g_object_ref (self),
319                                g_object_unref);
320 
321  out:
322   return;
323 }
324 
325 
326 static void
photos_tracker_controller_offset_changed(PhotosTrackerController * self)327 photos_tracker_controller_offset_changed (PhotosTrackerController *self)
328 {
329   photos_tracker_controller_reset_constraint (self);
330   photos_tracker_controller_refresh_internal (self, PHOTOS_TRACKER_REFRESH_FLAGS_DONT_SET_QUERY_STATUS);
331 }
332 
333 
334 static void
photos_tracker_controller_set_query_status(PhotosTrackerController * self,gboolean query_status)335 photos_tracker_controller_set_query_status (PhotosTrackerController *self, gboolean query_status)
336 {
337   PhotosTrackerControllerPrivate *priv;
338   gint64 now;
339 
340   priv = photos_tracker_controller_get_instance_private (self);
341 
342   if (priv->querying == query_status)
343     return;
344 
345   now = g_get_monotonic_time ();
346   if (query_status)
347     priv->last_query_time = now;
348   else
349     {
350       photos_debug (PHOTOS_DEBUG_TRACKER,
351                     "Query Elapsed: %" G_GINT64_FORMAT " seconds",
352                     (now - priv->last_query_time) / 1000000);
353       priv->last_query_time = 0;
354     }
355 
356   priv->querying = query_status;
357   g_signal_emit (self, signals[QUERY_STATUS_CHANGED], 0, priv->querying);
358 }
359 
360 
361 static void
photos_tracker_controller_refresh_internal(PhotosTrackerController * self,gint flags)362 photos_tracker_controller_refresh_internal (PhotosTrackerController *self, gint flags)
363 {
364   PhotosTrackerControllerPrivate *priv;
365 
366   priv = photos_tracker_controller_get_instance_private (self);
367 
368   priv->is_started = TRUE;
369 
370   if (priv->is_frozen)
371     return;
372 
373   if (flags & PHOTOS_TRACKER_REFRESH_FLAGS_RESET_OFFSET)
374     photos_offset_controller_reset_offset (priv->offset_cntrlr);
375 
376   if (photos_tracker_controller_get_query_status (self))
377     {
378       g_cancellable_cancel (priv->cancellable);
379       priv->query_queued = TRUE;
380       priv->query_queued_flags = flags;
381       return;
382     }
383 
384   if (!(flags & PHOTOS_TRACKER_REFRESH_FLAGS_DONT_SET_QUERY_STATUS))
385     {
386       photos_tracker_controller_set_query_status (self, TRUE);
387       photos_item_manager_clear (PHOTOS_ITEM_MANAGER (priv->item_mngr), priv->mode);
388     }
389 
390   photos_tracker_controller_perform_current_query (self);
391 }
392 
393 
394 static void
photos_tracker_controller_refresh_for_source(PhotosTrackerController * self)395 photos_tracker_controller_refresh_for_source (PhotosTrackerController *self)
396 {
397   PhotosTrackerControllerPrivate *priv;
398 
399   priv = photos_tracker_controller_get_instance_private (self);
400 
401   if (priv->current_query != NULL)
402     {
403       PhotosSource *source;
404 
405       source = photos_query_get_source (priv->current_query);
406       if (source != NULL)
407         {
408           const gchar *id;
409 
410           id = photos_filterable_get_id (PHOTOS_FILTERABLE (source));
411           if (g_strcmp0 (id, PHOTOS_SOURCE_STOCK_ALL) == 0)
412             photos_tracker_controller_refresh_internal (self, PHOTOS_TRACKER_REFRESH_FLAGS_NONE);
413         }
414     }
415 
416   priv->refresh_pending = FALSE;
417 }
418 
419 
420 static void
photos_tracker_controller_source_object_added_removed(PhotosTrackerController * self,GObject * source)421 photos_tracker_controller_source_object_added_removed (PhotosTrackerController *self, GObject *source)
422 {
423   PhotosTrackerControllerPrivate *priv;
424   PhotosWindowMode mode;
425 
426   priv = photos_tracker_controller_get_instance_private (self);
427 
428   g_return_if_fail (priv->mode_cntrlr != NULL);
429 
430   if (!photos_filterable_is_search_criterion (PHOTOS_FILTERABLE (source)))
431     goto out;
432 
433   mode = photos_mode_controller_get_window_mode (priv->mode_cntrlr);
434   if (mode == priv->mode)
435     photos_tracker_controller_refresh_for_source (self);
436   else
437     priv->refresh_pending = TRUE;
438 
439  out:
440   return;
441 }
442 
443 
444 static void
photos_tracker_controller_window_mode_changed(PhotosTrackerController * self,PhotosWindowMode mode,PhotosWindowMode old_mode)445 photos_tracker_controller_window_mode_changed (PhotosTrackerController *self,
446                                                PhotosWindowMode mode,
447                                                PhotosWindowMode old_mode)
448 {
449   PhotosTrackerControllerPrivate *priv;
450 
451   priv = photos_tracker_controller_get_instance_private (self);
452 
453   if (priv->refresh_pending && mode == priv->mode)
454     photos_tracker_controller_refresh_for_source (self);
455 }
456 
457 
458 static void
photos_tracker_controller_constructed(GObject * object)459 photos_tracker_controller_constructed (GObject *object)
460 {
461   PhotosTrackerController *self = PHOTOS_TRACKER_CONTROLLER (object);
462   PhotosTrackerControllerPrivate *priv;
463   PhotosBaseManager *item_mngr_chld;
464 
465   priv = photos_tracker_controller_get_instance_private (self);
466 
467   G_OBJECT_CLASS (photos_tracker_controller_parent_class)->constructed (object);
468 
469   item_mngr_chld = photos_item_manager_get_for_mode (PHOTOS_ITEM_MANAGER (priv->item_mngr), priv->mode);
470   g_signal_connect_object (item_mngr_chld,
471                            "object-added",
472                            G_CALLBACK (photos_tracker_controller_item_added_removed),
473                            self,
474                            G_CONNECT_SWAPPED);
475   g_signal_connect_object (item_mngr_chld,
476                            "object-removed",
477                            G_CALLBACK (photos_tracker_controller_item_added_removed),
478                            self,
479                            G_CONNECT_SWAPPED);
480 
481   priv->offset_cntrlr = PHOTOS_TRACKER_CONTROLLER_GET_CLASS (self)->get_offset_controller (self);
482   g_signal_connect_swapped (priv->offset_cntrlr,
483                             "offset-changed",
484                             G_CALLBACK (photos_tracker_controller_offset_changed),
485                             self);
486 }
487 
488 
489 static void
photos_tracker_controller_dispose(GObject * object)490 photos_tracker_controller_dispose (GObject *object)
491 {
492   PhotosTrackerController *self = PHOTOS_TRACKER_CONTROLLER (object);
493   PhotosTrackerControllerPrivate *priv;
494 
495   priv = photos_tracker_controller_get_instance_private (self);
496 
497   if (priv->reset_count_id != 0)
498     {
499       g_source_remove (priv->reset_count_id);
500       priv->reset_count_id = 0;
501     }
502 
503   g_clear_object (&priv->src_mngr);
504   g_clear_object (&priv->offset_cntrlr);
505   g_clear_object (&priv->current_query);
506   g_clear_object (&priv->queue);
507 
508   G_OBJECT_CLASS (photos_tracker_controller_parent_class)->dispose (object);
509 }
510 
511 
512 static void
photos_tracker_controller_finalize(GObject * object)513 photos_tracker_controller_finalize (GObject *object)
514 {
515   PhotosTrackerController *self = PHOTOS_TRACKER_CONTROLLER (object);
516   PhotosTrackerControllerPrivate *priv;
517 
518   priv = photos_tracker_controller_get_instance_private (self);
519 
520   if (priv->item_mngr != NULL)
521     g_object_remove_weak_pointer (G_OBJECT (priv->item_mngr), (gpointer *) &priv->item_mngr);
522 
523   if (priv->mode_cntrlr != NULL)
524     g_object_remove_weak_pointer (G_OBJECT (priv->mode_cntrlr), (gpointer *) &priv->mode_cntrlr);
525 
526   g_clear_error (&priv->queue_error);
527 
528   G_OBJECT_CLASS (photos_tracker_controller_parent_class)->finalize (object);
529 
530   DZL_COUNTER_DEC (instances);
531 }
532 
533 
534 static void
photos_tracker_controller_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)535 photos_tracker_controller_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
536 {
537   PhotosTrackerController *self = PHOTOS_TRACKER_CONTROLLER (object);
538   PhotosTrackerControllerPrivate *priv;
539 
540   priv = photos_tracker_controller_get_instance_private (self);
541 
542   switch (prop_id)
543     {
544     case PROP_DELAY_START:
545       priv->delay_start = g_value_get_boolean (value);
546       break;
547 
548     case PROP_MODE:
549       priv->mode = (PhotosWindowMode) g_value_get_enum (value);
550       break;
551 
552     default:
553       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
554       break;
555     }
556 }
557 
558 
559 static void
photos_tracker_controller_init(PhotosTrackerController * self)560 photos_tracker_controller_init (PhotosTrackerController *self)
561 {
562   PhotosTrackerControllerPrivate *priv;
563   GApplication *app;
564   PhotosSearchContextState *state;
565 
566   DZL_COUNTER_INC (instances);
567 
568   priv = photos_tracker_controller_get_instance_private (self);
569 
570   app = g_application_get_default ();
571   state = photos_search_context_get_state (PHOTOS_SEARCH_CONTEXT (app));
572 
573   priv->cancellable = g_cancellable_new ();
574 
575   priv->item_mngr = state->item_mngr;
576   g_object_add_weak_pointer (G_OBJECT (priv->item_mngr), (gpointer *) &priv->item_mngr);
577 
578   priv->src_mngr = g_object_ref (state->src_mngr);
579   g_signal_connect_swapped (priv->src_mngr,
580                             "object-added",
581                             G_CALLBACK (photos_tracker_controller_source_object_added_removed),
582                             self);
583   g_signal_connect_swapped (priv->src_mngr,
584                             "object-removed",
585                             G_CALLBACK (photos_tracker_controller_source_object_added_removed),
586                             self);
587 
588   priv->mode_cntrlr = state->mode_cntrlr;
589   g_object_add_weak_pointer (G_OBJECT (priv->mode_cntrlr), (gpointer *) &priv->mode_cntrlr);
590   g_signal_connect_swapped (priv->mode_cntrlr,
591                             "window-mode-changed",
592                             G_CALLBACK (photos_tracker_controller_window_mode_changed),
593                             self);
594 
595   priv->queue = photos_tracker_queue_dup_singleton (NULL, &priv->queue_error);
596 }
597 
598 
599 static void
photos_tracker_controller_class_init(PhotosTrackerControllerClass * class)600 photos_tracker_controller_class_init (PhotosTrackerControllerClass *class)
601 {
602   GObjectClass *object_class = G_OBJECT_CLASS (class);
603 
604   class->base_item_type = G_TYPE_NONE;
605 
606   object_class->constructed = photos_tracker_controller_constructed;
607   object_class->dispose = photos_tracker_controller_dispose;
608   object_class->set_property = photos_tracker_controller_set_property;
609   object_class->finalize = photos_tracker_controller_finalize;
610 
611   g_object_class_install_property (object_class,
612                                    PROP_DELAY_START,
613                                    g_param_spec_boolean ("delay-start",
614                                                          "Delay start",
615                                                          "Don't start issuing queries immediately on startup",
616                                                          FALSE,
617                                                          G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE));
618 
619   g_object_class_install_property (object_class,
620                                    PROP_MODE,
621                                    g_param_spec_enum ("mode",
622                                                       "PhotosWindowMode enum",
623                                                       "The mode handled by this controller",
624                                                       PHOTOS_TYPE_WINDOW_MODE,
625                                                       PHOTOS_WINDOW_MODE_NONE,
626                                                       G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE));
627 
628   signals[QUERY_ERROR] = g_signal_new ("query-error",
629                                        G_TYPE_FROM_CLASS (class),
630                                        G_SIGNAL_RUN_LAST,
631                                        G_STRUCT_OFFSET (PhotosTrackerControllerClass,
632                                                         query_error),
633                                        NULL, /*accumulator */
634                                        NULL, /*accu_data */
635                                        _photos_marshal_VOID__STRING_STRING,
636                                        G_TYPE_NONE,
637                                        2,
638                                        G_TYPE_STRING,
639                                        G_TYPE_STRING);
640 
641   signals[QUERY_STATUS_CHANGED] = g_signal_new ("query-status-changed",
642                                                 G_TYPE_FROM_CLASS (class),
643                                                 G_SIGNAL_RUN_LAST,
644                                                 G_STRUCT_OFFSET (PhotosTrackerControllerClass,
645                                                                  query_status_changed),
646                                                 NULL, /*accumulator */
647                                                 NULL, /*accu_data */
648                                                 g_cclosure_marshal_VOID__BOOLEAN,
649                                                 G_TYPE_NONE,
650                                                 1,
651                                                 G_TYPE_BOOLEAN);
652 }
653 
654 
655 void
photos_tracker_controller_refresh_for_object(PhotosTrackerController * self)656 photos_tracker_controller_refresh_for_object (PhotosTrackerController *self)
657 {
658   photos_tracker_controller_refresh_internal (self, PHOTOS_TRACKER_REFRESH_FLAGS_RESET_OFFSET);
659 }
660 
661 
662 void
photos_tracker_controller_set_frozen(PhotosTrackerController * self,gboolean frozen)663 photos_tracker_controller_set_frozen (PhotosTrackerController *self, gboolean frozen)
664 {
665   PhotosTrackerControllerPrivate *priv;
666 
667   priv = photos_tracker_controller_get_instance_private (self);
668   priv->is_frozen = frozen;
669 }
670 
671 
672 void
photos_tracker_controller_start(PhotosTrackerController * self)673 photos_tracker_controller_start (PhotosTrackerController *self)
674 {
675   PhotosTrackerControllerPrivate *priv;
676 
677   priv = photos_tracker_controller_get_instance_private (self);
678 
679   if (priv->delay_start)
680     return;
681 
682   if (priv->is_started)
683     return;
684 
685   photos_tracker_controller_refresh_internal (self, PHOTOS_TRACKER_REFRESH_FLAGS_NONE);
686 }
687 
688 
689 gboolean
photos_tracker_controller_get_query_status(PhotosTrackerController * self)690 photos_tracker_controller_get_query_status (PhotosTrackerController *self)
691 {
692   PhotosTrackerControllerPrivate *priv;
693 
694   priv = photos_tracker_controller_get_instance_private (self);
695   return priv->querying;
696 }
697