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