Sync to GQview 1.5.9 release.
[geeqie.git] / src / img-view.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 "img-view.h"
15
16 #include "collect.h"
17 #include "collect-io.h"
18 #include "dnd.h"
19 #include "editors.h"
20 #include "filelist.h"
21 #include "fullscreen.h"
22 #include "image.h"
23 #include "image-overlay.h"
24 #include "info.h"
25 #include "menu.h"
26 #include "slideshow.h"
27 #include "utilops.h"
28 #include "ui_bookmark.h"
29 #include "ui_fileops.h"
30 #include "ui_menu.h"
31
32 #include <gdk/gdkkeysyms.h> /* for keyboard values */
33
34 #include "icons/view.xpm"
35
36
37 typedef struct _ViewWindow ViewWindow;
38 struct _ViewWindow
39 {
40         GtkWidget *window;
41         ImageWindow *imd;
42         FullScreenData *fs;
43         SlideShowData *ss;
44
45         GList *list;
46         GList *list_pointer;
47
48         gint overlay_id;
49 };
50
51
52 static GList *view_window_list = NULL;
53
54
55 static GtkWidget *view_popup_menu(ViewWindow *vw);
56 static void view_fullscreen_toggle(ViewWindow *vw, gint force_off);
57 static void view_overlay_toggle(ViewWindow *vw);
58
59 static void view_slideshow_next(ViewWindow *vw);
60 static void view_slideshow_prev(ViewWindow *vw);
61 static void view_slideshow_start(ViewWindow *vw);
62 static void view_slideshow_stop(ViewWindow *vw);
63
64 static void view_window_close(ViewWindow *vw);
65
66 static void view_window_dnd_init(ViewWindow *vw);
67
68
69 /*
70  *-----------------------------------------------------------------------------
71  * misc
72  *-----------------------------------------------------------------------------
73  */ 
74
75 static ImageWindow *view_window_active_image(ViewWindow *vw)
76 {
77         if (vw->fs) return vw->fs->imd;
78
79         return vw->imd;
80 }
81
82 static void view_window_set_list(ViewWindow *vw, GList *list)
83 {
84
85         path_list_free(vw->list);
86         vw->list = NULL;
87         vw->list_pointer = NULL;
88
89         vw->list = path_list_copy(list);
90 }
91
92 static gint view_window_contains_collection(ViewWindow *vw)
93 {
94         CollectionData *cd;
95         CollectInfo *info;
96
97         cd = image_get_collection(view_window_active_image(vw), &info);
98
99         return (cd && info);
100 }
101
102 static void view_collection_step(ViewWindow *vw, gint next)
103 {
104         ImageWindow *imd = view_window_active_image(vw);
105         CollectionData *cd;
106         CollectInfo *info;
107         CollectInfo *read_ahead_info = NULL;
108
109         cd = image_get_collection(imd, &info);
110
111         if (!cd || !info) return;
112
113         if (next)
114                 {
115                 info = collection_next_by_info(cd, info);
116                 if (enable_read_ahead)
117                         {
118                         read_ahead_info = collection_next_by_info(cd, info);
119                         if (!read_ahead_info) read_ahead_info = collection_prev_by_info(cd, info);
120                         }
121                 }
122         else
123                 {
124                 info = collection_prev_by_info(cd, info);
125                 if (enable_read_ahead)
126                         {
127                         read_ahead_info = collection_prev_by_info(cd, info);
128                         if (!read_ahead_info) read_ahead_info = collection_next_by_info(cd, info);
129                         }
130                 }
131
132         if (info)
133                 {
134                 image_change_from_collection(imd, cd, info, image_zoom_get_default(imd, zoom_mode));
135
136                 if (read_ahead_info) image_prebuffer_set(imd, read_ahead_info->path);
137                 }
138         
139 }
140
141 static void view_collection_step_to_end(ViewWindow *vw, gint last)
142 {
143         ImageWindow *imd = view_window_active_image(vw);
144         CollectionData *cd;
145         CollectInfo *info;
146         CollectInfo *read_ahead_info = NULL;
147
148         cd = image_get_collection(imd, &info);
149
150         if (!cd || !info) return;
151
152         if (last)
153                 {
154                 info = collection_get_last(cd);
155                 if (enable_read_ahead) read_ahead_info = collection_prev_by_info(cd, info);
156                 }
157         else
158                 {
159                 info = collection_get_first(cd);
160                 if (enable_read_ahead) read_ahead_info = collection_next_by_info(cd, info);
161                 }
162
163         if (info)
164                 {
165                 image_change_from_collection(imd, cd, info, image_zoom_get_default(imd, zoom_mode));
166                 if (read_ahead_info) image_prebuffer_set(imd, read_ahead_info->path);
167                 }
168 }
169
170 static void view_list_step(ViewWindow *vw, gint next)
171 {
172         ImageWindow *imd = view_window_active_image(vw);
173         const gchar *path;
174         GList *work;
175         GList *work_ahead;
176
177         if (!vw->list) return;
178
179         path = image_get_path(imd);
180         if (!path) return;
181
182         if (g_list_position(vw->list, vw->list_pointer) >= 0)
183                 {
184                 work = vw->list_pointer;
185                 }
186         else
187                 {
188                 gint found = FALSE;
189
190                 work = vw->list;
191                 while (work && !found)
192                         {
193                         gchar *temp;
194
195                         temp = work->data;
196
197                         if (strcmp(path, temp) == 0)
198                                 {
199                                 found = TRUE;
200                                 }
201                         else
202                                 {
203                                 work = work->next;
204                                 }
205                         }
206                 }
207         if (!work) return;
208
209         work_ahead = NULL;
210         if (next)
211                 {
212                 work = work->next;
213                 if (work) work_ahead = work->next;
214                 }
215         else
216                 {
217                 work = work->prev;
218                 if (work) work_ahead = work->prev;
219                 }
220         if (!work) return;
221
222         vw->list_pointer = work;
223         path = work->data;
224         image_change_path(imd, path, image_zoom_get_default(imd, zoom_mode));
225
226         if (enable_read_ahead && work_ahead)
227                 {
228                 const gchar *next_path = work_ahead->data;
229                 image_prebuffer_set(imd, next_path);
230                 }
231 }
232
233 static void view_list_step_to_end(ViewWindow *vw, gint last)
234 {
235         ImageWindow *imd = view_window_active_image(vw);
236         const gchar *path;
237         GList *work;
238         GList *work_ahead;
239
240         if (!vw->list) return;
241
242         if (last)
243                 {
244                 work = g_list_last(vw->list);
245                 work_ahead = work->prev;
246                 }
247         else
248                 {
249                 work = vw->list;
250                 work_ahead = work->next;
251                 }
252
253         vw->list_pointer = work;
254         path = work->data;
255         image_change_path(imd, path, image_zoom_get_default(imd, zoom_mode));
256
257         if (enable_read_ahead && work_ahead)
258                 {
259                 const gchar *next_path = work_ahead->data;
260                 image_prebuffer_set(imd, next_path);
261                 }
262 }
263
264 static void view_step_next(ViewWindow *vw)
265 {
266         if (vw->ss)
267                 {
268                 view_slideshow_next(vw);
269                 }
270         else if (vw->list)
271                 {
272                 view_list_step(vw, TRUE);
273                 }
274         else
275                 {
276                 view_collection_step(vw, TRUE);
277                 }
278 }
279
280 static void view_step_prev(ViewWindow *vw)
281 {
282         if (vw->ss)
283                 {
284                 view_slideshow_prev(vw);
285                 }
286         else if (vw->list)
287                 {
288                 view_list_step(vw, FALSE);
289                 }
290         else
291                 {
292                 view_collection_step(vw, FALSE);
293                 }
294 }
295
296 static void view_step_to_end(ViewWindow *vw, gint last)
297 {
298         if (vw->list)
299                 {
300                 view_list_step_to_end(vw, last);
301                 }
302         else
303                 {
304                 view_collection_step_to_end(vw, last);
305                 }
306 }
307
308 /*
309  *-----------------------------------------------------------------------------
310  * view window keyboard
311  *-----------------------------------------------------------------------------
312  */
313
314 static void view_window_menu_pos_cb(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer data)
315 {
316         ViewWindow *vw = data;
317         ImageWindow *imd;
318
319         imd = view_window_active_image(vw);
320         gdk_window_get_origin(imd->image->window, x, y);
321         popup_menu_position_clamp(menu, x, y, 0);
322 }
323
324 static gint view_window_key_press_cb(GtkWidget *widget, GdkEventKey *event, gpointer data)
325 {
326         ViewWindow *vw = data;
327         ImageWindow *imd;
328         gint stop_signal = FALSE;
329         GtkWidget *menu;
330         gint x = 0;
331         gint y = 0;
332
333         imd = view_window_active_image(vw);
334
335         switch (event->keyval)
336                 {
337                 case GDK_Left: case GDK_KP_Left:
338                         x -= 1;
339                         stop_signal = TRUE;
340                         break;
341                 case GDK_Right: case GDK_KP_Right:
342                         x += 1;
343                         stop_signal = TRUE;
344                         break;
345                 case GDK_Up: case GDK_KP_Up:
346                         y -= 1;
347                         stop_signal = TRUE;
348                         break;
349                 case GDK_Down: case GDK_KP_Down:
350                         y += 1;
351                         stop_signal = TRUE;
352                         break;
353                 }
354
355         if ( !(event->state & GDK_CONTROL_MASK) )
356             switch (event->keyval)
357                 {
358                 case GDK_Page_Up: case GDK_KP_Page_Up:
359                 case GDK_BackSpace:
360                 case 'B': case 'b':
361                         view_step_prev(vw);
362                         stop_signal = TRUE;
363                         break;
364                 case GDK_Page_Down: case GDK_KP_Page_Down:
365                 case GDK_space:
366                 case 'N': case 'n':
367                         view_step_next(vw);
368                         stop_signal = TRUE;
369                         break;
370                 case GDK_Home: case GDK_KP_Home:
371                         view_step_to_end(vw, FALSE);
372                         stop_signal = TRUE;
373                         break;
374                 case GDK_End: case GDK_KP_End:
375                         view_step_to_end(vw, TRUE);
376                         stop_signal = TRUE;
377                         break;
378                 case '+': case '=': case GDK_KP_Add:
379                         image_zoom_adjust(imd, get_zoom_increment());
380                         break;
381                 case '-': case GDK_KP_Subtract:
382                         image_zoom_adjust(imd, -get_zoom_increment());
383                         break;
384                 case 'X': case 'x': case GDK_KP_Multiply:
385                         image_zoom_set(imd, 0.0);
386                         break;
387                 case 'Z': case 'z': case GDK_KP_Divide: case '1':
388                         image_zoom_set(imd, 1.0);
389                         break;
390                 case '2':
391                         image_zoom_set(imd, 2.0);
392                         break;
393                 case '3':
394                         image_zoom_set(imd, 3.0);
395                         break;
396                 case '4':
397                         image_zoom_set(imd, 4.0);
398                         break;
399                 case '7':
400                         image_zoom_set(imd, -4.0);
401                         break;
402                 case '8':
403                         image_zoom_set(imd, -3.0);
404                         break;
405                 case '9':
406                         image_zoom_set(imd, -2.0);
407                         break;
408                 case 'W': case 'w':
409                         image_zoom_set_fill_geometry(imd, FALSE);
410                         break;
411                 case 'H': case 'h':
412                         image_zoom_set_fill_geometry(imd, TRUE);
413                         break;
414                 case 'R': case 'r':
415                         image_reload(imd);
416                         break;
417                 case 'S': case 's':
418                         if (vw->ss)
419                                 view_slideshow_stop(vw);
420                         else
421                                 view_slideshow_start(vw);
422                         stop_signal = TRUE;
423                         break;
424                 case 'P': case 'p':
425                         slideshow_pause_toggle(vw->ss);
426                         break;
427                 case 'F': case 'f':
428                 case 'V': case 'v':
429                         view_fullscreen_toggle(vw, FALSE);
430                         stop_signal = TRUE;
431                         break;
432                 case 'I': case 'i':
433                         view_overlay_toggle(vw);
434                         break;
435                 case ']':
436                         image_alter(imd, ALTER_ROTATE_90);
437                         stop_signal = TRUE;
438                         break;
439                 case '[':
440                         image_alter(imd, ALTER_ROTATE_90_CC);
441                         stop_signal = TRUE;
442                         break;
443                 case GDK_Delete: case GDK_KP_Delete:
444                         if (enable_delete_key)
445                                 {
446                                 file_util_delete(image_get_path(imd), NULL, imd->widget);
447                                 stop_signal = TRUE;
448                                 }
449                         break;
450                 case GDK_Escape:
451                         if (vw->fs)
452                                 {
453                                 view_fullscreen_toggle(vw, TRUE);
454                                 }
455                         else
456                                 {
457                                 gtk_widget_destroy(vw->window);
458                                 }
459                         stop_signal = TRUE;
460                         break;
461                 case GDK_Menu:
462                 case GDK_F10:
463                         menu = view_popup_menu(vw);
464                         gtk_menu_popup(GTK_MENU(menu), NULL, NULL, view_window_menu_pos_cb, vw, 0, GDK_CURRENT_TIME);
465                         stop_signal = TRUE;
466                         break;
467                 }
468
469         if (event->state & GDK_CONTROL_MASK)
470                 {
471                 gint n = -1;
472                 switch (event->keyval)
473                         {
474                         case '1':
475                                 n = 0;
476                                 break;
477                         case '2':
478                                 n = 1;
479                                 break;
480                         case '3':
481                                 n = 2;
482                                 break;
483                         case '4':
484                                 n = 3;
485                                 break;
486                         case '5':
487                                 n = 4;
488                                 break;
489                         case '6':
490                                 n = 5;
491                                 break;
492                         case '7':
493                                 n = 6;
494                                 break;
495                         case '8':
496                                 n = 7;
497                                 break;
498                         case '9':
499                                 n = 8;
500                                 break;
501                         case '0':
502                                 n = 9;
503                                 break;
504                         case 'C': case 'c':
505                                 file_util_copy(image_get_path(imd), NULL, NULL, imd->widget);
506                                 stop_signal = TRUE;
507                                 break;
508                         case 'M': case 'm':
509                                 file_util_move(image_get_path(imd), NULL, NULL, imd->widget);
510                                 stop_signal = TRUE;
511                                 break;
512                         case 'R': case 'r':
513                                 file_util_rename(image_get_path(imd), NULL, imd->widget);
514                                 stop_signal = TRUE;
515                                 break;
516                         case 'D': case 'd':
517                                 file_util_delete(image_get_path(imd), NULL, imd->widget);
518                                 stop_signal = TRUE;
519                                 break;
520                         case 'P': case 'p':
521                                 info_window_new(image_get_path(imd), NULL);
522                                 stop_signal = TRUE;
523                                 break;
524                         case 'W': case 'w':
525                                 view_window_close(vw);
526                                 break;
527                         }
528                 if (n != -1)
529                         {
530                         view_fullscreen_toggle(vw, TRUE);
531                         start_editor_from_file(n, image_get_path(imd));
532                         }
533                 }
534         else if (event->state & GDK_SHIFT_MASK)
535                 {
536                 switch (event->keyval)
537                         {
538                         case 'R': case 'r':
539                                 image_alter(imd, ALTER_ROTATE_180);
540                                 stop_signal = TRUE;
541                                 break;
542                         case 'M': case 'm':
543                                 image_alter(imd, ALTER_MIRROR);
544                                 stop_signal = TRUE;
545                                 break;
546                         case 'F': case 'f':
547                                 image_alter(imd, ALTER_FLIP);
548                                 stop_signal = TRUE;
549                                 break;
550                         default:
551                                 break;
552                         }
553                 x *= 3;
554                 y *= 3;
555                 }
556
557         if (x != 0 || y!= 0)
558                 {
559                 keyboard_scroll_calc(&x, &y, event);
560                 image_scroll(imd, x, y);
561                 }
562
563         return stop_signal;
564 }
565
566 /*
567  *-----------------------------------------------------------------------------
568  * view window main routines
569  *-----------------------------------------------------------------------------
570  */ 
571
572 static void button_cb(ImageWindow *imd, gint button, guint32 time,
573                       gdouble x, gdouble y, guint state, gpointer data)
574 {
575         ViewWindow *vw = data;
576         GtkWidget *menu;
577
578         switch (button)
579                 {
580                 case 1:
581                         view_step_next(vw);
582                         break;
583                 case 2:
584                         view_step_prev(vw);
585                         break;
586                 case 3:
587                         menu = view_popup_menu(vw);
588                         gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL, 3, time);
589                         break;
590                 default:
591                         break;
592                 }
593 }
594
595 static void scroll_cb(ImageWindow *imd, GdkScrollDirection direction, guint32 time,
596                       gdouble x, gdouble y, guint state, gpointer data)
597 {
598         ViewWindow *vw = data;
599
600         if (state & GDK_CONTROL_MASK)
601                 {
602                 switch (direction)
603                         {
604                         case GDK_SCROLL_UP:
605                                 image_zoom_adjust_at_point(imd, get_zoom_increment(), x, y);
606                                 break;
607                         case GDK_SCROLL_DOWN:
608                                 image_zoom_adjust_at_point(imd, -get_zoom_increment(), x, y);
609                                 break;
610                         default:
611                                 break;
612                         }
613                 }
614         else if ( (state & GDK_SHIFT_MASK) != (mousewheel_scrolls))
615                 {
616                 switch (direction)
617                         {
618                         case GDK_SCROLL_UP:
619                                 image_scroll(imd, 0, -MOUSEWHEEL_SCROLL_SIZE);
620                                 break;
621                         case GDK_SCROLL_DOWN:
622                                 image_scroll(imd, 0, MOUSEWHEEL_SCROLL_SIZE);
623                                 break;
624                         case GDK_SCROLL_LEFT:
625                                 image_scroll(imd, -MOUSEWHEEL_SCROLL_SIZE, 0);
626                                 break;
627                         case GDK_SCROLL_RIGHT:
628                                 image_scroll(imd, MOUSEWHEEL_SCROLL_SIZE, 0);
629                                 break;
630                         default:
631                                 break;
632                         }
633                 }
634         else
635                 {
636                 switch (direction)
637                         {
638                         case GDK_SCROLL_UP:
639                                 view_step_prev(vw);
640                                 break;
641                         case GDK_SCROLL_DOWN:
642                                 view_step_next(vw);
643                                 break;
644                         default:
645                                 break;
646                         }
647                 }
648 }
649
650 static void view_image_set_buttons(ViewWindow *vw, ImageWindow *imd)
651 {
652         image_set_button_func(imd, button_cb, vw);
653         image_set_scroll_func(imd, scroll_cb, vw);
654 }
655
656 static void view_fullscreen_stop_func(FullScreenData *fs, gpointer data)
657 {
658         ViewWindow *vw = data;
659
660         vw->fs = NULL;
661
662         if (vw->ss) vw->ss->imd = vw->imd;
663 }
664
665 static void view_fullscreen_toggle(ViewWindow *vw, gint force_off)
666 {
667         if (force_off && !vw->fs) return;
668
669         if (vw->fs)
670                 {
671                 fullscreen_stop(vw->fs);
672
673                 if (vw->overlay_id != -1) vw->overlay_id = image_overlay_info_enable(vw->imd);
674                 }
675         else
676                 {
677                 vw->fs = fullscreen_start(vw->window, vw->imd, view_fullscreen_stop_func, vw);
678
679                 view_image_set_buttons(vw, vw->fs->imd);
680                 g_signal_connect(G_OBJECT(vw->fs->window), "key_press_event",
681                                  G_CALLBACK(view_window_key_press_cb), vw);
682
683                 if (vw->ss) vw->ss->imd = vw->fs->imd;
684
685                 if (vw->overlay_id != -1)
686                         {
687                         image_overlay_info_disable(vw->imd, vw->overlay_id);
688                         vw->overlay_id = image_overlay_info_enable(vw->fs->imd);
689                         }
690                 }
691 }
692
693 static void view_overlay_toggle(ViewWindow *vw)
694 {
695         ImageWindow *imd;
696
697         imd = view_window_active_image(vw);
698
699         if (vw->overlay_id == -1)
700                 {
701                 vw->overlay_id = image_overlay_info_enable(imd);
702                 }
703         else
704                 {
705                 image_overlay_info_disable(imd, vw->overlay_id);
706                 vw->overlay_id = -1;
707                 }
708 }
709
710 static void view_slideshow_next(ViewWindow *vw)
711 {
712         if (vw->ss) slideshow_next(vw->ss);
713 }
714
715 static void view_slideshow_prev(ViewWindow *vw)
716 {
717         if (vw->ss) slideshow_prev(vw->ss);
718 }
719
720 static void view_slideshow_stop_func(SlideShowData *fs, gpointer data)
721 {
722         ViewWindow *vw = data;
723
724         vw->ss = NULL;
725 }
726
727 static void view_slideshow_start(ViewWindow *vw)
728 {
729         if (!vw->ss)
730                 {
731                 CollectionData *cd;
732                 CollectInfo *info;
733
734                 if (vw->list)
735                         {
736                         vw->ss = slideshow_start_from_path_list(view_window_active_image(vw),
737                                                                 path_list_copy(vw->list),
738                                                                 view_slideshow_stop_func, vw);
739                         vw->list_pointer = NULL;
740                         return;
741                         }
742
743                 cd = image_get_collection(view_window_active_image(vw), &info);
744                 if (cd && info)
745                         {
746                         vw->ss = slideshow_start_from_collection(view_window_active_image(vw), cd,
747                                                                  view_slideshow_stop_func, vw, info);
748                         }
749                 }
750 }
751
752 static void view_slideshow_stop(ViewWindow *vw)
753 {
754         if (vw->ss) slideshow_free(vw->ss);
755 }
756
757 static void view_window_close(ViewWindow *vw)
758 {
759         view_window_list = g_list_remove(view_window_list, vw);
760
761         view_slideshow_stop(vw);
762         view_fullscreen_toggle(vw, TRUE);
763         gtk_widget_destroy(vw->window);
764         path_list_free(vw->list);
765         g_free(vw);
766 }
767
768 static gint view_window_delete_cb(GtkWidget *w, GdkEventAny *event, gpointer data)
769 {
770         ViewWindow *vw = data;
771
772         view_window_close(vw);
773         return TRUE;
774 }
775
776 static ViewWindow *real_view_window_new(const gchar *path, GList *list, CollectionData *cd, CollectInfo *info)
777 {
778         ViewWindow *vw;
779         GtkAllocation req_size;
780         GdkGeometry geometry;
781         gint w, h;
782
783         if (!path && !list && (!cd || !info)) return NULL;
784
785         vw = g_new0(ViewWindow, 1);
786         vw->fs = NULL;
787         vw->ss = NULL;
788         vw->list = NULL;
789         vw->list_pointer = NULL;
790
791         vw->overlay_id = -1;
792
793         vw->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
794
795         geometry.min_width = 8;
796         geometry.min_height = 8;
797         gtk_window_set_geometry_hints(GTK_WINDOW(vw->window), NULL, &geometry, GDK_HINT_MIN_SIZE);
798
799         gtk_window_set_resizable(GTK_WINDOW(vw->window), TRUE);
800         gtk_window_set_title (GTK_WINDOW(vw->window), "GQview");
801         gtk_window_set_wmclass(GTK_WINDOW(vw->window), "view", "GQview");
802         gtk_container_set_border_width(GTK_CONTAINER(vw->window), 0);
803
804         window_set_icon(vw->window, (const gchar **)view_xpm, NULL);
805
806         vw->imd = image_new(FALSE);
807
808         if (black_window_background) image_background_set_black(vw->imd, TRUE);
809
810         image_attach_window(vw->imd, vw->window, NULL, "GQview", TRUE);
811
812         image_auto_refresh(vw->imd, 0);
813         image_top_window_set_sync(vw->imd, TRUE);
814
815         gtk_container_add(GTK_CONTAINER(vw->window), vw->imd->widget);
816         gtk_widget_show(vw->imd->widget);
817
818         view_window_dnd_init(vw);
819
820         view_image_set_buttons(vw, vw->imd);
821
822         g_signal_connect(G_OBJECT(vw->window), "delete_event",
823                          G_CALLBACK(view_window_delete_cb), vw);
824         g_signal_connect(G_OBJECT(vw->window), "key_press_event",
825                          G_CALLBACK(view_window_key_press_cb), vw);
826         if (cd && info)
827                 {
828                 image_change_from_collection(vw->imd, cd, info, image_zoom_get_default(NULL, zoom_mode));
829                 if (enable_read_ahead)
830                         {
831                         CollectInfo * r_info = collection_next_by_info(cd, info);
832                         if (!r_info) r_info = collection_prev_by_info(cd, info);
833                         if (r_info) image_prebuffer_set(vw->imd, r_info->path);
834                         }
835                 }
836         else if (list)
837                 {
838                 view_window_set_list(vw, list);
839                 vw->list_pointer = vw->list;
840                 image_change_path(vw->imd, (gchar *)vw->list->data, image_zoom_get_default(NULL, zoom_mode));
841
842                 if (enable_read_ahead)
843                         {
844                         GList *work = vw->list->next;
845                         if (work) image_prebuffer_set(vw->imd, (gchar *)work->data);
846                         }
847                 }
848         else
849                 {
850                 image_change_path(vw->imd, path, image_zoom_get_default(NULL, zoom_mode));
851                 }
852
853         if (image_zoom_get(vw->imd) == 0.0)
854                 {
855                 w = vw->imd->image_width;
856                 h = vw->imd->image_height;
857                 }
858         else
859                 {
860                 w = vw->imd->width;
861                 h = vw->imd->height;
862                 }
863         if (limit_window_size)
864                 {
865                 gint mw = gdk_screen_width() * max_window_size / 100;
866                 gint mh = gdk_screen_height() * max_window_size / 100;
867
868                 if (w > mw) w = mw;
869                 if (h > mh) h = mh;
870                 }
871
872         gtk_window_set_default_size(GTK_WINDOW(vw->window), w, h);
873         req_size.x = req_size.y = 0;
874         req_size.width = w;
875         req_size.height = h;
876         gtk_widget_size_allocate(GTK_WIDGET(vw->window), &req_size);
877
878         gtk_widget_set_size_request(vw->imd->image, w, h);
879
880         gtk_widget_show(vw->window);
881
882         view_window_list = g_list_append(view_window_list, vw);
883
884         return vw;
885 }
886
887 static void view_window_collection_unref_cb(GtkWidget *widget, gpointer data)
888 {
889         CollectionData *cd = data;
890
891         collection_unref(cd);
892 }
893
894 void view_window_new(const gchar *path)
895 {
896         if (file_extension_match(path, ".gqv"))
897                 {
898                 ViewWindow *vw;
899                 CollectionData *cd;
900                 CollectInfo *info;
901
902                 cd = collection_new(path);
903                 if (collection_load(cd, path, FALSE))
904                         {
905                         info = collection_get_first(cd);
906                         }
907                 else
908                         {
909                         collection_unref(cd);
910                         cd = NULL;
911                         info = NULL;
912                         }
913                 vw = real_view_window_new(NULL, NULL, cd, info);
914                 if (vw && cd)
915                         {
916                         g_signal_connect(G_OBJECT(vw->window), "destroy",
917                                          G_CALLBACK(view_window_collection_unref_cb), cd);
918                         }
919                 }
920         else if (isdir(path))
921                 {
922                 GList *list = NULL;
923
924                 if (path_list(path, &list, NULL))
925                         {
926                         list = path_list_sort(list);
927                         list = path_list_filter(list, FALSE);
928                         }
929                 real_view_window_new(NULL, list, NULL, NULL);
930                 path_list_free(list);
931                 }
932         else
933                 {
934                 real_view_window_new(path, NULL, NULL, NULL);
935                 }
936 }
937
938 void view_window_new_from_list(GList *list)
939 {
940         real_view_window_new(NULL, list, NULL, NULL);
941 }
942
943 void view_window_new_from_collection(CollectionData *cd, CollectInfo *info)
944 {
945         real_view_window_new(NULL, NULL, cd, info);
946 }
947
948 /*
949  *-----------------------------------------------------------------------------
950  * public
951  *-----------------------------------------------------------------------------
952  */
953
954 void view_window_colors_update(void)
955 {
956         GList *work;
957
958         work = view_window_list;
959         while (work)
960                 {
961                 ViewWindow *vw = work->data;
962                 work = work->next;
963
964                 image_background_set_black(vw->imd, black_window_background);
965                 }
966 }
967
968 gint view_window_find_image(ImageWindow *imd, gint *index, gint *total)
969 {
970         GList *work;
971
972         work = view_window_list;
973         while (work)
974                 {
975                 ViewWindow *vw = work->data;
976                 work = work->next;
977
978                 if (vw->imd == imd ||
979                     (vw->fs && vw->fs->imd == imd))
980                         {
981                         if (vw->ss)
982                                 {
983                                 gint n;
984                                 n = g_list_length(vw->ss->list_done);
985                                 if (index) *index = n - 1;
986                                 if (total) *total = n + g_list_length(vw->ss->list);
987                                 }
988                         else
989                                 {
990                                 if (index) *index = g_list_position(vw->list, vw->list_pointer);
991                                 if (total) *total = g_list_length(vw->list);
992                                 }
993                         return TRUE;
994                         }
995                 }
996
997         return FALSE;
998 }
999
1000 /*
1001  *-----------------------------------------------------------------------------
1002  * view window menu routines and callbacks
1003  *-----------------------------------------------------------------------------
1004  */ 
1005
1006 static void view_new_window_cb(GtkWidget *widget, gpointer data)
1007 {
1008         ViewWindow *vw = data;
1009         CollectionData *cd;
1010         CollectInfo *info;
1011
1012         cd = image_get_collection(vw->imd, &info);
1013
1014         if (cd && info)
1015                 {
1016                 view_window_new_from_collection(cd, info);
1017                 }
1018         else
1019                 {
1020                 view_window_new(image_get_path(vw->imd));
1021                 }
1022 }
1023
1024 static void view_edit_cb(GtkWidget *widget, gpointer data)
1025 {
1026         ViewWindow *vw;
1027         gint n;
1028
1029         vw = submenu_item_get_data(widget);
1030         n = GPOINTER_TO_INT(data);
1031         if (!vw) return;
1032
1033         view_fullscreen_toggle(vw, TRUE);
1034         start_editor_from_file(n, image_get_path(vw->imd));
1035 }
1036
1037 static void view_alter_cb(GtkWidget *widget, gpointer data)
1038 {
1039         ViewWindow *vw;
1040         AlterType type;
1041
1042         vw = submenu_item_get_data(widget);
1043         type = GPOINTER_TO_INT(data);
1044
1045         if (!vw) return;
1046         image_alter(vw->imd, type);
1047 }
1048
1049 static void view_info_cb(GtkWidget *widget, gpointer data)
1050 {
1051         ViewWindow *vw = data;
1052         ImageWindow *imd;
1053
1054         imd = view_window_active_image(vw);
1055         info_window_new(image_get_path(imd), NULL);
1056 }
1057
1058 static void view_wallpaper_cb(GtkWidget *widget, gpointer data)
1059 {
1060         ViewWindow *vw = data;
1061         ImageWindow *imd;
1062
1063         imd = view_window_active_image(vw);
1064         image_to_root_window(imd, (image_zoom_get(imd) == 0.0));
1065 }
1066
1067 static void view_zoom_in_cb(GtkWidget *widget, gpointer data)
1068 {
1069         ViewWindow *vw = data;
1070
1071         image_zoom_adjust(view_window_active_image(vw), get_zoom_increment());
1072 }
1073
1074 static void view_zoom_out_cb(GtkWidget *widget, gpointer data)
1075 {
1076         ViewWindow *vw = data;
1077
1078         image_zoom_adjust(view_window_active_image(vw), -get_zoom_increment());
1079 }
1080
1081 static void view_zoom_1_1_cb(GtkWidget *widget, gpointer data)
1082 {
1083         ViewWindow *vw = data;
1084
1085         image_zoom_set(view_window_active_image(vw), 1.0);
1086 }
1087
1088 static void view_zoom_fit_cb(GtkWidget *widget, gpointer data)
1089 {
1090         ViewWindow *vw = data;
1091
1092         image_zoom_set(view_window_active_image(vw), 0.0);
1093 }
1094
1095 static void view_copy_cb(GtkWidget *widget, gpointer data)
1096 {
1097         ViewWindow *vw = data;
1098         ImageWindow *imd;
1099
1100         imd = view_window_active_image(vw);
1101         file_util_copy(image_get_path(imd), NULL, NULL, imd->widget);
1102 }
1103
1104 static void view_move_cb(GtkWidget *widget, gpointer data)
1105 {
1106         ViewWindow *vw = data;
1107         ImageWindow *imd;
1108
1109         imd = view_window_active_image(vw);
1110         file_util_move(image_get_path(imd), NULL, NULL, imd->widget);
1111 }
1112
1113 static void view_rename_cb(GtkWidget *widget, gpointer data)
1114 {
1115         ViewWindow *vw = data;
1116         ImageWindow *imd;
1117
1118         imd = view_window_active_image(vw);
1119         file_util_rename(image_get_path(imd), NULL, imd->widget);
1120 }
1121
1122 static void view_delete_cb(GtkWidget *widget, gpointer data)
1123 {
1124         ViewWindow *vw = data;
1125         ImageWindow *imd;
1126
1127         imd = view_window_active_image(vw);
1128         file_util_delete(image_get_path(imd), NULL, imd->widget);
1129 }
1130
1131 static void view_fullscreen_cb(GtkWidget *widget, gpointer data)
1132 {
1133         ViewWindow *vw = data;
1134
1135         view_fullscreen_toggle(vw, FALSE);
1136 }
1137
1138 static void view_slideshow_start_cb(GtkWidget *widget, gpointer data)
1139 {
1140         ViewWindow *vw = data;
1141
1142         view_slideshow_start(vw);
1143 }
1144
1145 static void view_slideshow_stop_cb(GtkWidget *widget, gpointer data)
1146 {
1147         ViewWindow *vw = data;
1148
1149         view_slideshow_stop(vw);
1150 }
1151
1152 static void view_slideshow_pause_cb(GtkWidget *widget, gpointer data)
1153 {
1154         ViewWindow *vw = data;
1155
1156         slideshow_pause_toggle(vw->ss);
1157 }
1158
1159 static void view_close_cb(GtkWidget *widget, gpointer data)
1160 {
1161         ViewWindow *vw = data;
1162
1163         view_window_close(vw);
1164 }
1165
1166 static GtkWidget *view_popup_menu(ViewWindow *vw)
1167 {
1168         GtkWidget *menu;
1169         GtkWidget *item;
1170
1171         menu = popup_menu_short_lived();
1172
1173         menu_item_add_stock(menu, _("Zoom _in"), GTK_STOCK_ZOOM_IN, G_CALLBACK(view_zoom_in_cb), vw);
1174         menu_item_add_stock(menu, _("Zoom _out"), GTK_STOCK_ZOOM_OUT, G_CALLBACK(view_zoom_out_cb), vw);
1175         menu_item_add_stock(menu, _("Zoom _1:1"), GTK_STOCK_ZOOM_100, G_CALLBACK(view_zoom_1_1_cb), vw);
1176         menu_item_add_stock(menu, _("Fit image to _window"), GTK_STOCK_ZOOM_FIT, G_CALLBACK(view_zoom_fit_cb), vw);
1177         menu_item_add_divider(menu);
1178
1179         item = submenu_add_edit(menu, NULL, G_CALLBACK(view_edit_cb), vw);
1180         menu_item_add_divider(item);
1181         menu_item_add(item, _("Set as _wallpaper"), G_CALLBACK(view_wallpaper_cb), vw);
1182
1183         submenu_add_alter(menu, G_CALLBACK(view_alter_cb), vw);
1184
1185         menu_item_add_stock(menu, _("_Properties"), GTK_STOCK_PROPERTIES, G_CALLBACK(view_info_cb), vw);
1186
1187         menu_item_add_stock(menu, _("View in _new window"), GTK_STOCK_NEW, G_CALLBACK(view_new_window_cb), vw);
1188
1189         menu_item_add_divider(menu);
1190         menu_item_add_stock(menu, _("_Copy..."), GTK_STOCK_COPY, G_CALLBACK(view_copy_cb), vw);
1191         menu_item_add(menu, _("_Move..."), G_CALLBACK(view_move_cb), vw);
1192         menu_item_add(menu, _("_Rename..."), G_CALLBACK(view_rename_cb), vw);
1193         menu_item_add_stock(menu, _("_Delete..."), GTK_STOCK_DELETE, G_CALLBACK(view_delete_cb), vw);
1194
1195         menu_item_add_divider(menu);
1196
1197         if (vw->ss)
1198                 {
1199                 menu_item_add(menu, _("_Stop slideshow"), G_CALLBACK(view_slideshow_stop_cb), vw);
1200                 if (slideshow_paused(vw->ss))
1201                         {
1202                         item = menu_item_add(menu, _("Continue slides_how"),
1203                                              G_CALLBACK(view_slideshow_pause_cb), vw);
1204                         }
1205                 else
1206                         {
1207                         item = menu_item_add(menu, _("Pause slides_how"),
1208                                              G_CALLBACK(view_slideshow_pause_cb), vw);
1209                         }
1210                 }
1211         else
1212                 {
1213                 item = menu_item_add(menu, _("_Start slideshow"), G_CALLBACK(view_slideshow_start_cb), vw);
1214                 gtk_widget_set_sensitive(item, (vw->list != NULL) || view_window_contains_collection(vw));
1215                 item = menu_item_add(menu, _("Pause slides_how"), G_CALLBACK(view_slideshow_pause_cb), vw);
1216                 gtk_widget_set_sensitive(item, FALSE);
1217                 }
1218
1219         if (vw->fs)
1220                 {
1221                 menu_item_add(menu, _("Exit _full screen"), G_CALLBACK(view_fullscreen_cb), vw);
1222                 }
1223         else
1224                 {
1225                 menu_item_add(menu, _("_Full screen"), G_CALLBACK(view_fullscreen_cb), vw);
1226                 }
1227
1228         menu_item_add_divider(menu);
1229         menu_item_add_stock(menu, _("C_lose window"), GTK_STOCK_CLOSE, G_CALLBACK(view_close_cb), vw);
1230
1231         return menu;
1232 }
1233
1234 /*
1235  *-------------------------------------------------------------------
1236  * dnd confirm dir
1237  *-------------------------------------------------------------------
1238  */
1239
1240 typedef struct {
1241         ViewWindow *vw;
1242         GList *list;
1243 } CViewConfirmD;
1244
1245 static void view_dir_list_cancel(GtkWidget *widget, gpointer data)
1246 {
1247         /* do nothing */
1248 }
1249
1250 static void view_dir_list_do(ViewWindow *vw, GList *list, gint skip, gint recurse)
1251 {
1252         GList *work;
1253
1254         view_window_set_list(vw, NULL);
1255
1256         work = list;
1257         while (work)
1258                 {
1259                 gchar *path = work->data;
1260                 work = work->next;
1261
1262                 if (isdir(path))
1263                         {
1264                         if (!skip)
1265                                 {
1266                                 GList *list = NULL;
1267
1268                                 if (recurse)
1269                                         {
1270                                         list = path_list_recursive(path);
1271                                         }
1272                                 else
1273                                         {
1274                                         path_list(path, &list, NULL);
1275                                         list = path_list_sort(list);
1276                                         list = path_list_filter(list, FALSE);
1277                                         }
1278                                 if (list) vw->list = g_list_concat(vw->list, list);
1279                                 }
1280                         }
1281                 else
1282                         {
1283                         /* FIXME: no filtering here */
1284                         vw->list = g_list_append(vw->list, g_strdup(path));
1285                         }
1286                 }
1287
1288         if (vw->list)
1289                 {
1290                 gchar *path;
1291
1292                 vw->list_pointer = vw->list;
1293                 path = vw->list->data;
1294                 image_change_path(vw->imd, path, image_zoom_get_default(vw->imd, zoom_mode));
1295
1296                 work = vw->list->next;
1297                 if (enable_read_ahead && work)
1298                         {
1299                         path = work->data;
1300                         image_prebuffer_set(vw->imd, path);
1301                         }
1302                 }
1303         else
1304                 {
1305                 image_change_path(vw->imd, NULL, image_zoom_get_default(vw->imd, zoom_mode));
1306                 }
1307 }
1308
1309 static void view_dir_list_add(GtkWidget *widget, gpointer data)
1310 {
1311         CViewConfirmD *d = data;
1312         view_dir_list_do(d->vw, d->list, FALSE, FALSE);
1313 }
1314
1315 static void view_dir_list_recurse(GtkWidget *widget, gpointer data)
1316 {
1317         CViewConfirmD *d = data;
1318         view_dir_list_do(d->vw, d->list, FALSE, TRUE);
1319 }
1320
1321 static void view_dir_list_skip(GtkWidget *widget, gpointer data)
1322 {
1323         CViewConfirmD *d = data;
1324         view_dir_list_do(d->vw, d->list, TRUE, FALSE);
1325 }
1326
1327 static void view_dir_list_destroy(GtkWidget *widget, gpointer data)
1328 {
1329         CViewConfirmD *d = data;
1330         path_list_free(d->list);
1331         g_free(d);
1332 }
1333
1334 static GtkWidget *view_confirm_dir_list(ViewWindow *vw, GList *list)
1335 {
1336         GtkWidget *menu;
1337         CViewConfirmD *d;
1338
1339         d = g_new(CViewConfirmD, 1);
1340         d->vw = vw;
1341         d->list = list;
1342
1343         menu = popup_menu_short_lived();
1344         g_signal_connect(G_OBJECT(menu), "destroy",
1345                          G_CALLBACK(view_dir_list_destroy), d);
1346
1347         menu_item_add_stock(menu, _("Dropped list includes folders."), GTK_STOCK_DND_MULTIPLE, NULL, NULL);
1348         menu_item_add_divider(menu);
1349         menu_item_add_stock(menu, _("_Add contents"), GTK_STOCK_OK, G_CALLBACK(view_dir_list_add), d);
1350         menu_item_add_stock(menu, _("Add contents _recursive"), GTK_STOCK_ADD, G_CALLBACK(view_dir_list_recurse), d);
1351         menu_item_add_stock(menu, _("_Skip folders"), GTK_STOCK_REMOVE, G_CALLBACK(view_dir_list_skip), d);
1352         menu_item_add_divider(menu);
1353         menu_item_add_stock(menu, _("Cancel"), GTK_STOCK_CANCEL, G_CALLBACK(view_dir_list_cancel), d);
1354
1355         return menu;
1356 }
1357
1358 /*
1359  *-----------------------------------------------------------------------------
1360  * image drag and drop routines
1361  *-----------------------------------------------------------------------------
1362  */
1363
1364 static void view_window_get_dnd_data(GtkWidget *widget, GdkDragContext *context,
1365                                      gint x, gint y,
1366                                      GtkSelectionData *selection_data, guint info,
1367                                      guint time, gpointer data)
1368 {
1369         ViewWindow *vw = data;
1370         ImageWindow *imd;
1371
1372         if (gtk_drag_get_source_widget(context) == vw->imd->image) return;
1373
1374         imd = vw->imd;
1375
1376         if (info == TARGET_URI_LIST || info == TARGET_APP_COLLECTION_MEMBER)
1377                 {
1378                 CollectionData *source;
1379                 GList *list;
1380                 GList *info_list;
1381
1382                 if (info == TARGET_URI_LIST)
1383                         {
1384                         GList *work;
1385
1386                         list = uri_list_from_text(selection_data->data, TRUE);
1387
1388                         work = list;
1389                         while (work)
1390                                 {
1391                                 if (isdir((gchar *)work->data))
1392                                         {
1393                                         GtkWidget *menu;
1394                                         menu = view_confirm_dir_list(vw, list);
1395                                         gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 0, time);
1396                                         return;
1397                                         }
1398                                 work = work->next;
1399                                 }
1400
1401                         list = path_list_filter(list, FALSE);
1402
1403                         source = NULL;
1404                         info_list = NULL;
1405                         }
1406                 else
1407                         {
1408                         source = collection_from_dnd_data((gchar *)selection_data->data, &list, &info_list);
1409                         }
1410
1411                 if (list)
1412                         {
1413                         gchar *path;
1414
1415                         path = list->data;
1416                         if (isfile(path))
1417                                 {
1418                                 view_slideshow_stop(vw);
1419                                 view_window_set_list(vw, NULL);
1420
1421                                 if (source && info_list)
1422                                         {
1423                                         image_change_from_collection(imd, source, info_list->data, image_zoom_get_default(imd, zoom_mode));
1424                                         }
1425                                 else
1426                                         {
1427                                         if (list->next)
1428                                                 {
1429                                                 vw->list = list;
1430                                                 list = NULL;
1431
1432                                                 vw->list_pointer = vw->list;
1433                                                 }
1434                                         image_change_path(imd, path, image_zoom_get_default(imd, zoom_mode));
1435                                         }
1436                                 }
1437                         }
1438                 path_list_free(list);
1439                 g_list_free(info_list);
1440                 }
1441 }
1442
1443 static void view_window_set_dnd_data(GtkWidget *widget, GdkDragContext *context,
1444                                      GtkSelectionData *selection_data, guint info,
1445                                      guint time, gpointer data)
1446 {
1447         ViewWindow *vw = data;
1448         const gchar *path;
1449
1450         path = image_get_path(vw->imd);
1451
1452         if (path)
1453                 {
1454                 gchar *text = NULL;
1455                 gint len;
1456                 gint plain_text;
1457                 GList *list;
1458
1459                 switch (info)
1460                         {
1461                         case TARGET_URI_LIST:
1462                                 plain_text = FALSE;
1463                                 break;
1464                         case TARGET_TEXT_PLAIN:
1465                         default:
1466                                 plain_text = TRUE;
1467                                 break;
1468                         }
1469                 list = g_list_append(NULL, (gchar *)path);
1470                 text = uri_text_from_list(list, &len, plain_text);
1471                 g_list_free(list);
1472                 if (text)
1473                         {
1474                         gtk_selection_data_set (selection_data, selection_data->target,
1475                                                 8, text, len);
1476                         g_free(text);
1477                         }
1478                 }
1479         else
1480                 {
1481                 gtk_selection_data_set (selection_data, selection_data->target,
1482                                         8, NULL, 0);
1483                 }
1484 }
1485
1486 static void view_window_dnd_init(ViewWindow *vw)
1487 {
1488         ImageWindow *imd;
1489
1490         imd = vw->imd;
1491
1492         gtk_drag_source_set(imd->image, GDK_BUTTON2_MASK,
1493                             dnd_file_drag_types, dnd_file_drag_types_count,
1494                             GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
1495         g_signal_connect(G_OBJECT(imd->image), "drag_data_get",
1496                          G_CALLBACK(view_window_set_dnd_data), vw);
1497
1498         gtk_drag_dest_set(imd->image,
1499                           GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP,
1500                           dnd_file_drop_types, dnd_file_drop_types_count,
1501                           GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
1502         g_signal_connect(G_OBJECT(imd->image), "drag_data_received",
1503                          G_CALLBACK(view_window_get_dnd_data), vw);
1504 }
1505
1506 /*
1507  *-----------------------------------------------------------------------------
1508  * maintenance (for rename, move, remove)
1509  *-----------------------------------------------------------------------------
1510  */
1511
1512 static void view_real_removed(ViewWindow *vw, const gchar *path, GList *ignore_list)
1513 {
1514         ImageWindow *imd;
1515         const gchar *image_path;
1516
1517         imd = view_window_active_image(vw);
1518         image_path = image_get_path(imd);
1519
1520         if (image_path && strcmp(image_path, path) == 0)
1521                 {
1522                 if (vw->list)
1523                         {
1524                         view_list_step(vw, TRUE);
1525                         if (image_get_path(imd) == image_path)
1526                                 {
1527                                 view_list_step(vw, FALSE);
1528                                 }
1529                         }
1530                 else if (view_window_contains_collection(vw))
1531                         {
1532                         view_collection_step(vw, TRUE);
1533                         if (image_get_path(imd) == image_path)
1534                                 {
1535                                 view_collection_step(vw, FALSE);
1536                                 }
1537                         }
1538                 if (image_get_path(imd) == image_path)
1539                         {
1540                         image_change_path(imd, NULL, image_zoom_get_default(imd, zoom_mode));
1541                         }
1542                 }
1543
1544         if (vw->list)
1545                 {
1546                 GList *work;
1547                 GList *old;
1548
1549                 old = vw->list_pointer;
1550
1551                 work = vw->list;
1552                 while (work)
1553                         {
1554                         gchar *chk_path;
1555                         GList *chk_link;
1556
1557                         chk_path = work->data;
1558                         chk_link = work;
1559                         work = work->next;
1560
1561                         if (strcmp(chk_path, path) == 0)
1562                                 {
1563                                 if (vw->list_pointer == chk_link)
1564                                         {
1565                                         vw->list_pointer = (chk_link->next) ? chk_link->next : chk_link->prev;
1566                                         }
1567                                 vw->list = g_list_remove(vw->list, chk_path);
1568                                 g_free(chk_path);
1569                                 }
1570                         }
1571
1572                 /* handles stepping correctly when same image is in the list more than once */
1573                 if (old && old != vw->list_pointer)
1574                         {
1575                         gchar *path;
1576
1577                         if (vw->list_pointer)
1578                                 {
1579                                 path = vw->list_pointer->data;
1580                                 }
1581                         else
1582                                 {
1583                                 path = NULL;
1584                                 }
1585
1586                         image_change_path(imd, path, image_zoom_get_default(imd, zoom_mode));
1587                         }
1588                 }
1589
1590         if (vw->overlay_id != -1) image_overlay_update(imd, vw->overlay_id);
1591 }
1592
1593 static void view_real_moved(ViewWindow *vw, const gchar *source, const gchar *dest)
1594 {
1595         ImageWindow *imd;
1596         const gchar *image_path;
1597
1598         imd = view_window_active_image(vw);
1599         image_path = image_get_path(imd);
1600
1601         if (image_path && strcmp(image_path, source) == 0)
1602                 {
1603                 image_set_path(imd, dest);
1604                 }
1605
1606         if (vw->list)
1607                 {
1608                 GList *work;
1609                 work = vw->list;
1610                 while (work)
1611                         {
1612                         gchar *chk_path;
1613
1614                         chk_path = work->data;
1615
1616                         if (strcmp(chk_path, source) == 0)
1617                                 {
1618                                 work->data = g_strdup(dest);
1619                                 g_free(chk_path);
1620                                 }
1621
1622                         work = work->next;
1623                         }
1624                 }
1625 }
1626
1627 void view_window_maint_removed(const gchar *path, GList *ignore_list)
1628 {
1629         GList *work = view_window_list;
1630         while (work)
1631                 {
1632                 ViewWindow *vw = work->data;
1633                 work = work->next;
1634
1635                 view_real_removed(vw, path, ignore_list);
1636                 }
1637 }
1638
1639 void view_window_maint_moved(const gchar *source, const gchar *dest)
1640 {
1641         GList *work = view_window_list;
1642         while (work)
1643                 {
1644                 ViewWindow *vw = work->data;
1645                 work = work->next;
1646
1647                 view_real_moved(vw, source, dest);
1648                 }
1649 }
1650