6b608a2aca56033581a867e8dfd0c9a16bfe7bee
[geeqie.git] / src / slideshow.c
1 /*
2  * GQview
3  * (C) 2004 John Ellis
4  *
5  * Author: John Ellis
6  *
7  * This software is released under the GNU General Public License (GNU GPL).
8  * Please read the included file COPYING for more information.
9  * This software comes with no warranty of any kind, use at your own risk!
10  */
11
12
13 #include "gqview.h"
14 #include "collect.h"
15 #include "image.h"
16 #include "slideshow.h"
17
18 #include "layout.h"
19 #include "layout_image.h"
20 #include "ui_fileops.h"
21
22
23 static void slideshow_timer_reset(SlideShowData *ss, gint reset);
24
25
26 void slideshow_free(SlideShowData *ss)
27 {
28         slideshow_timer_reset(ss, FALSE);
29
30         if (ss->stop_func) ss->stop_func(ss, ss->stop_data);
31
32         if (ss->path_list) path_list_free(ss->path_list);
33         if (ss->cd) collection_unref(ss->cd);
34         g_free(ss->layout_path);
35
36         g_list_free(ss->list);
37         g_list_free(ss->list_done);
38
39         g_free(ss->slide_path);
40
41         g_free(ss);
42 }
43
44 static GList *generate_list(SlideShowData *ss)
45 {
46         GList *list = NULL;
47
48         if (ss->from_selection)
49                 {
50                 list = layout_selection_list_by_index(ss->layout);
51                 }
52         else
53                 {
54                 gint i;
55                 for(i = 0; i < ss->slide_count; i++)
56                         {
57                         list = g_list_prepend(list, GINT_TO_POINTER(i));
58                         }
59                 list = g_list_reverse(list);
60                 }
61
62         return list;
63 }
64
65 static GList *generate_random_list(SlideShowData *ss)
66 {
67         GList *src_list = NULL;
68         GList *list = NULL;
69         GList *work;
70
71         src_list = generate_list(ss);
72
73         while(src_list)
74                 {
75                 gint p = (double)rand() / ((double)RAND_MAX + 1.0) * g_list_length(src_list);
76                 work = g_list_nth(src_list, p);
77                 list = g_list_prepend(list, work->data);
78                 src_list = g_list_remove(src_list, work->data);
79                 }
80
81         return list;
82 }
83
84 static void slideshow_list_init(SlideShowData *ss, gint start_index)
85 {
86         if (ss->list_done)
87                 {
88                 g_list_free(ss->list_done);
89                 ss->list_done = NULL;
90                 }
91
92         if (ss->list) g_list_free(ss->list);
93
94         if (slideshow_random)
95                 {
96                 ss->list = generate_random_list(ss);
97                 }
98         else
99                 {
100                 ss->list = generate_list(ss);
101                 if (start_index >= 0)
102                         {
103                         /* start with specified image by skipping to it */
104                         gint i = 0;
105
106                         while(ss->list && i < start_index)
107                                 {
108                                 ss->list_done = g_list_prepend (ss->list_done, ss->list->data);
109                                 ss->list = g_list_remove(ss->list, ss->list->data);
110                                 i++;
111                                 }
112                         }
113                 }
114 }
115
116 gint slideshow_should_continue(SlideShowData *ss)
117 {
118         const gchar *imd_path;
119         const gchar *path;
120
121         imd_path = image_get_path(ss->imd);
122
123         if ( ((imd_path == NULL) != (ss->slide_path == NULL)) ||
124             (imd_path && ss->slide_path && strcmp(imd_path, ss->slide_path) != 0) ) return FALSE;
125
126         if (ss->path_list) return TRUE;
127
128         if (ss->cd)
129                 {
130                 if (g_list_length(ss->cd->list) == ss->slide_count)
131                         return TRUE;
132                 else
133                         return FALSE;
134                 }
135
136         if (!ss->layout) return FALSE;
137         path = layout_get_path(ss->layout);
138
139         if (path && ss->layout_path &&
140             strcmp(path, ss->layout_path) == 0)
141                 {
142                 if (ss->from_selection && ss->slide_count == layout_selection_count(ss->layout, NULL)) return TRUE;
143                 if (!ss->from_selection && ss->slide_count == layout_list_count(ss->layout, NULL)) return TRUE;
144                 }
145
146         return FALSE;
147 }
148
149 static gint slideshow_step(SlideShowData *ss, gint forward)
150 {
151         gint row;
152
153         if (!slideshow_should_continue(ss))
154                 {
155                 return FALSE;
156                 }
157
158         if (forward)
159                 {
160                 if (!ss->list) return TRUE;
161
162                 row = GPOINTER_TO_INT(ss->list->data);
163                 ss->list_done = g_list_prepend (ss->list_done, ss->list->data);
164                 ss->list = g_list_remove(ss->list, ss->list->data);
165                 }
166         else
167                 {
168                 if (!ss->list_done || !ss->list_done->next) return TRUE;
169
170                 ss->list = g_list_prepend(ss->list, ss->list_done->data);
171                 ss->list_done = g_list_remove(ss->list_done, ss->list_done->data);
172                 row = GPOINTER_TO_INT(ss->list_done->data);
173                 }
174
175         g_free(ss->slide_path);
176         ss->slide_path = NULL;
177
178         if (ss->path_list)
179                 {
180                 ss->slide_path = g_strdup(g_list_nth_data(ss->path_list, row));
181                 image_change_path(ss->imd, ss->slide_path, image_zoom_get_default(ss->imd, zoom_mode));
182                 }
183         else if (ss->cd)
184                 {
185                 CollectInfo *info;
186
187                 info = g_list_nth_data(ss->cd->list, row);
188                 ss->slide_path = g_strdup(info->path);
189
190                 image_change_from_collection(ss->imd, ss->cd, info, image_zoom_get_default(ss->imd, zoom_mode));
191                 }
192         else
193                 {
194                 ss->slide_path = g_strdup(layout_list_get_path(ss->layout, row));
195
196                 if (ss->from_selection)
197                         {
198                         image_change_path(ss->imd, ss->slide_path, image_zoom_get_default(ss->imd, zoom_mode));
199                         layout_status_update_info(ss->layout, NULL);
200                         }
201                 else
202                         {
203                         layout_image_set_index(ss->layout, row);
204                         }
205                 }
206
207         if (!ss->list && slideshow_repeat)
208                 {
209                 slideshow_list_init(ss, -1);
210                 }
211
212         if (!ss->list)
213                 {
214                 return FALSE;
215                 }
216
217         /* read ahead */
218
219         if (enable_read_ahead)
220                 {
221                 gint r;
222                 if (forward)
223                         {
224                         if (!ss->list) return TRUE;
225                         r = GPOINTER_TO_INT(ss->list->data);
226                         }
227                 else
228                         {
229                         if (!ss->list_done || !ss->list_done->next) return TRUE;
230                         r = GPOINTER_TO_INT(ss->list_done->next->data);
231                         }
232
233                 if (ss->path_list)
234                         {
235                         image_prebuffer_set(ss->imd, g_list_nth_data(ss->path_list, r));
236                         }
237                 else if (ss->cd)
238                         {
239                         CollectInfo *info;
240                         info = g_list_nth_data(ss->cd->list, r);
241                         if (info) image_prebuffer_set(ss->imd, info->path);
242                         }
243                 else if (ss->from_selection)
244                         {
245                         image_prebuffer_set(ss->imd, layout_list_get_path(ss->layout, r));
246                         }
247                 }
248
249         return TRUE;
250 }
251
252 static gint slideshow_loop_cb(gpointer data)
253 {
254         SlideShowData *ss = data;
255
256         if (ss->paused) return TRUE;
257
258         if (!slideshow_step(ss, TRUE))
259                 {
260                 ss->timeout_id = -1;
261                 slideshow_free(ss);
262                 return FALSE;
263                 }
264
265         return TRUE;
266 }
267
268 static void slideshow_timer_reset(SlideShowData *ss, gint reset)
269 {
270         if (reset)
271                 {
272                 if (slideshow_delay < 1) slideshow_delay = 1;
273
274                 if (ss->timeout_id != -1) g_source_remove(ss->timeout_id);
275                 ss->timeout_id = g_timeout_add(slideshow_delay * 1000 / SLIDESHOW_SUBSECOND_PRECISION,
276                                                slideshow_loop_cb, ss);
277                 }
278         else if (ss->timeout_id != -1)
279                 {
280                 g_source_remove(ss->timeout_id);
281                 ss->timeout_id = -1;
282                 }
283 }
284
285 void slideshow_next(SlideShowData *ss)
286 {
287         if (!slideshow_step(ss, TRUE))
288                 {
289                 slideshow_free(ss);
290                 return;
291                 }
292
293         slideshow_timer_reset(ss, TRUE);
294 }
295
296 void slideshow_prev(SlideShowData *ss)
297 {
298         if (!slideshow_step(ss, FALSE))
299                 {
300                 slideshow_free(ss);
301                 return;
302                 }
303
304         slideshow_timer_reset(ss, TRUE);
305 }
306
307 static SlideShowData *real_slideshow_start(ImageWindow *imd, LayoutWindow *lw,
308                                            GList *path_list, gint start_point,
309                                            CollectionData *cd, CollectInfo *start_info,
310                                            void (*stop_func)(SlideShowData *, gpointer), gpointer stop_data)
311 {
312         SlideShowData *ss;
313         gint start_index = -1;
314
315         if (!path_list && !cd && layout_list_count(lw, NULL) < 1) return NULL;
316
317         ss = g_new0(SlideShowData, 1);
318
319         ss->imd = imd;
320
321         ss->path_list = path_list;
322         ss->cd = cd;
323         ss->layout = lw;
324         ss->layout_path = NULL;
325
326         ss->list = NULL;
327         ss->list_done = NULL;
328
329         ss->from_selection = FALSE;
330
331         ss->stop_func = stop_func;
332         ss->stop_data = stop_data;
333
334         ss->timeout_id = -1;
335
336         ss->paused = FALSE;
337
338         if (ss->path_list)
339                 {
340                 ss->slide_count = g_list_length(ss->path_list);
341                 }
342         else if (ss->cd)
343                 {
344                 collection_ref(ss->cd);
345                 ss->slide_count = g_list_length(ss->cd->list);
346                 if (!slideshow_random && start_info)
347                         {
348                         start_index = g_list_index(ss->cd->list, start_info);
349                         }
350                 }
351         else
352                 {
353                 /* layout method */
354
355                 ss->slide_count = layout_selection_count(ss->layout, NULL);
356                 ss->layout_path = g_strdup(layout_get_path(ss->layout));
357                 if (ss->slide_count < 2)
358                         {
359                         ss->slide_count = layout_list_count(ss->layout, NULL);
360                         if (!slideshow_random && start_point >= 0 && start_point < ss->slide_count)
361                                 {
362                                 start_index = start_point;
363                                 }
364                         }
365                 else
366                         {
367                         ss->from_selection = TRUE;
368                         }
369                 }
370
371         slideshow_list_init(ss, start_index);
372
373         ss->slide_path = g_strdup(image_get_path(ss->imd));
374         if (slideshow_step(ss, TRUE))
375                 {
376                 slideshow_timer_reset(ss, TRUE);
377                 }
378         else
379                 {
380                 ss = NULL;
381                 }
382
383         return ss;
384 }
385
386 SlideShowData *slideshow_start_from_path_list(ImageWindow *imd, GList *list,
387                                               void (*stop_func)(SlideShowData *, gpointer), gpointer stop_data)
388 {
389         return real_slideshow_start(imd, NULL, list, -1, NULL, NULL, stop_func, stop_data);
390 }
391
392 SlideShowData *slideshow_start_from_collection(ImageWindow *imd, CollectionData *cd,
393                                                void (*stop_func)(SlideShowData *, gpointer), gpointer stop_data,
394                                                CollectInfo *start_info)
395 {
396         return real_slideshow_start(imd, NULL, NULL, -1, cd, start_info, stop_func, stop_data);
397 }
398
399 SlideShowData *slideshow_start(ImageWindow *imd, LayoutWindow *lw, gint start_point,
400                                void (*stop_func)(SlideShowData *, gpointer), gpointer stop_data)
401 {
402         return real_slideshow_start(imd, lw, NULL, start_point, NULL, NULL, stop_func, stop_data);
403 }
404
405 gint slideshow_paused(SlideShowData *ss)
406 {
407         if (!ss) return FALSE;
408
409         return ss->paused;
410 }
411
412 void slideshow_pause_set(SlideShowData *ss, gint paused)
413 {
414         if (!ss) return;
415
416         ss->paused = paused;
417 }
418
419 gint slideshow_pause_toggle(SlideShowData *ss)
420 {
421         slideshow_pause_set(ss, !slideshow_paused(ss));
422         return slideshow_paused(ss);
423 }
424
425