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