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