rename GQview -> Geeqie over the code
[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 "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 "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 (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 (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, 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 (enable_read_ahead) read_ahead_info = collection_prev_by_info(cd, info);
155                 }
156         else
157                 {
158                 info = collection_get_first(cd);
159                 if (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, 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, zoom_mode));
225
226         if (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, zoom_mode));
256
257         if (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 (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) != (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 = gtk_window_new(GTK_WINDOW_TOPLEVEL);
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_window_set_title (GTK_WINDOW(vw->window), "Geeqie");
855         gtk_window_set_wmclass(GTK_WINDOW(vw->window), "view", "Geeqie");
856         gtk_container_set_border_width(GTK_CONTAINER(vw->window), 0);
857
858         window_set_icon(vw->window, PIXBUF_INLINE_ICON_VIEW, NULL);
859
860         vw->imd = image_new(FALSE);
861
862         if (black_window_background) image_background_set_black(vw->imd, TRUE);
863
864         image_attach_window(vw->imd, vw->window, NULL, "Geeqie", TRUE);
865
866         image_auto_refresh(vw->imd, 0);
867         image_top_window_set_sync(vw->imd, TRUE);
868
869         gtk_container_add(GTK_CONTAINER(vw->window), vw->imd->widget);
870         gtk_widget_show(vw->imd->widget);
871
872         view_window_dnd_init(vw);
873
874         view_image_set_buttons(vw, vw->imd);
875
876         g_signal_connect(G_OBJECT(vw->window), "destroy",
877                          G_CALLBACK(view_window_destroy_cb), vw);
878         g_signal_connect(G_OBJECT(vw->window), "delete_event",
879                          G_CALLBACK(view_window_delete_cb), vw);
880         g_signal_connect(G_OBJECT(vw->window), "key_press_event",
881                          G_CALLBACK(view_window_key_press_cb), vw);
882         if (cd && info)
883                 {
884                 image_change_from_collection(vw->imd, cd, info, image_zoom_get_default(NULL, zoom_mode));
885                 if (enable_read_ahead)
886                         {
887                         CollectInfo * r_info = collection_next_by_info(cd, info);
888                         if (!r_info) r_info = collection_prev_by_info(cd, info);
889                         if (r_info) image_prebuffer_set(vw->imd, r_info->fd);
890                         }
891                 }
892         else if (list)
893                 {
894                 view_window_set_list(vw, list);
895                 vw->list_pointer = vw->list;
896                 image_change_fd(vw->imd, (FileData *)vw->list->data, image_zoom_get_default(NULL, zoom_mode));
897
898                 if (enable_read_ahead)
899                         {
900                         GList *work = vw->list->next;
901                         if (work) image_prebuffer_set(vw->imd, (FileData *)work->data);
902                         }
903                 }
904         else
905                 {
906                 image_change_fd(vw->imd, fd, image_zoom_get_default(NULL, zoom_mode));
907                 }
908
909         if (image_zoom_get(vw->imd) == 0.0)
910                 {
911                 pixbuf_renderer_get_image_size(PIXBUF_RENDERER(vw->imd->pr), &w, &h);
912                 }
913         else
914                 {
915                 pixbuf_renderer_get_scaled_size(PIXBUF_RENDERER(vw->imd->pr), &w, &h);
916                 }
917         if (limit_window_size)
918                 {
919                 gint mw = gdk_screen_width() * max_window_size / 100;
920                 gint mh = gdk_screen_height() * max_window_size / 100;
921
922                 if (w > mw) w = mw;
923                 if (h > mh) h = mh;
924                 }
925
926         gtk_window_set_default_size(GTK_WINDOW(vw->window), w, h);
927         req_size.x = req_size.y = 0;
928         req_size.width = w;
929         req_size.height = h;
930         gtk_widget_size_allocate(GTK_WIDGET(vw->window), &req_size);
931
932         gtk_widget_set_size_request(vw->imd->pr, w, h);
933
934         gtk_widget_show(vw->window);
935
936         view_window_list = g_list_append(view_window_list, vw);
937
938         return vw;
939 }
940
941 static void view_window_collection_unref_cb(GtkWidget *widget, gpointer data)
942 {
943         CollectionData *cd = data;
944
945         collection_unref(cd);
946 }
947
948 void view_window_new(FileData *fd)
949 {
950         if (file_extension_match(fd->path, ".gqv"))
951                 {
952                 ViewWindow *vw;
953                 CollectionData *cd;
954                 CollectInfo *info;
955
956                 cd = collection_new(fd->path);
957                 if (collection_load(cd, fd->path, FALSE))
958                         {
959                         info = collection_get_first(cd);
960                         }
961                 else
962                         {
963                         collection_unref(cd);
964                         cd = NULL;
965                         info = NULL;
966                         }
967                 vw = real_view_window_new(NULL, NULL, cd, info);
968                 if (vw && cd)
969                         {
970                         g_signal_connect(G_OBJECT(vw->window), "destroy",
971                                          G_CALLBACK(view_window_collection_unref_cb), cd);
972                         }
973                 }
974         else if (isdir(fd->path)) 
975                 {
976                 GList *list = NULL;
977
978                 if (filelist_read(fd->path, &list, NULL))
979                         {
980                         list = filelist_sort_path(list);
981                         list = filelist_filter(list, FALSE);
982                         }
983                 real_view_window_new(NULL, list, NULL, NULL);
984                 filelist_free(list);
985                 }
986         else
987                 {
988                 real_view_window_new(fd, NULL, NULL, NULL);
989                 }
990 }
991
992 void view_window_new_from_list(GList *list)
993 {
994         real_view_window_new(NULL, list, NULL, NULL);
995 }
996
997 void view_window_new_from_collection(CollectionData *cd, CollectInfo *info)
998 {
999         real_view_window_new(NULL, NULL, cd, info);
1000 }
1001
1002 /*
1003  *-----------------------------------------------------------------------------
1004  * public
1005  *-----------------------------------------------------------------------------
1006  */
1007
1008 void view_window_colors_update(void)
1009 {
1010         GList *work;
1011
1012         work = view_window_list;
1013         while (work)
1014                 {
1015                 ViewWindow *vw = work->data;
1016                 work = work->next;
1017
1018                 image_background_set_black(vw->imd, black_window_background);
1019                 }
1020 }
1021
1022 gint view_window_find_image(ImageWindow *imd, gint *index, gint *total)
1023 {
1024         GList *work;
1025
1026         work = view_window_list;
1027         while (work)
1028                 {
1029                 ViewWindow *vw = work->data;
1030                 work = work->next;
1031
1032                 if (vw->imd == imd ||
1033                     (vw->fs && vw->fs->imd == imd))
1034                         {
1035                         if (vw->ss)
1036                                 {
1037                                 gint n;
1038                                 gint t;
1039
1040                                 n = g_list_length(vw->ss->list_done);
1041                                 t = n + g_list_length(vw->ss->list);
1042                                 if (n == 0) n = t;
1043                                 if (index) *index = n - 1;
1044                                 if (total) *total = t;
1045                                 }
1046                         else
1047                                 {
1048                                 if (index) *index = g_list_position(vw->list, vw->list_pointer);
1049                                 if (total) *total = g_list_length(vw->list);
1050                                 }
1051                         return TRUE;
1052                         }
1053                 }
1054
1055         return FALSE;
1056 }
1057
1058 /*
1059  *-----------------------------------------------------------------------------
1060  * view window menu routines and callbacks
1061  *-----------------------------------------------------------------------------
1062  */ 
1063
1064 static void view_new_window_cb(GtkWidget *widget, gpointer data)
1065 {
1066         ViewWindow *vw = data;
1067         CollectionData *cd;
1068         CollectInfo *info;
1069
1070         cd = image_get_collection(vw->imd, &info);
1071
1072         if (cd && info)
1073                 {
1074                 view_window_new_from_collection(cd, info);
1075                 }
1076         else
1077                 {
1078                 view_window_new(image_get_fd(vw->imd));
1079                 }
1080 }
1081
1082 static void view_edit_cb(GtkWidget *widget, gpointer data)
1083 {
1084         ViewWindow *vw;
1085         ImageWindow *imd;
1086         gint n;
1087
1088         vw = submenu_item_get_data(widget);
1089         n = GPOINTER_TO_INT(data);
1090         if (!vw) return;
1091
1092         if (!editor_window_flag_set(n))
1093                 {
1094                 view_fullscreen_toggle(vw, TRUE);
1095                 }
1096
1097         imd = view_window_active_image(vw);
1098         start_editor_from_file(n, image_get_fd(imd));
1099 }
1100
1101 static void view_alter_cb(GtkWidget *widget, gpointer data)
1102 {
1103         ViewWindow *vw;
1104         AlterType type;
1105
1106         vw = submenu_item_get_data(widget);
1107         type = GPOINTER_TO_INT(data);
1108
1109         if (!vw) return;
1110         image_alter(vw->imd, type);
1111 }
1112
1113 static void view_info_cb(GtkWidget *widget, gpointer data)
1114 {
1115         ViewWindow *vw = data;
1116         ImageWindow *imd;
1117
1118         imd = view_window_active_image(vw);
1119         info_window_new(image_get_fd(imd), NULL);
1120 }
1121
1122 static void view_wallpaper_cb(GtkWidget *widget, gpointer data)
1123 {
1124         ViewWindow *vw = data;
1125         ImageWindow *imd;
1126
1127         imd = view_window_active_image(vw);
1128         image_to_root_window(imd, (image_zoom_get(imd) == 0.0));
1129 }
1130
1131 static void view_zoom_in_cb(GtkWidget *widget, gpointer data)
1132 {
1133         ViewWindow *vw = data;
1134
1135         image_zoom_adjust(view_window_active_image(vw), get_zoom_increment());
1136 }
1137
1138 static void view_zoom_out_cb(GtkWidget *widget, gpointer data)
1139 {
1140         ViewWindow *vw = data;
1141
1142         image_zoom_adjust(view_window_active_image(vw), -get_zoom_increment());
1143 }
1144
1145 static void view_zoom_1_1_cb(GtkWidget *widget, gpointer data)
1146 {
1147         ViewWindow *vw = data;
1148
1149         image_zoom_set(view_window_active_image(vw), 1.0);
1150 }
1151
1152 static void view_zoom_fit_cb(GtkWidget *widget, gpointer data)
1153 {
1154         ViewWindow *vw = data;
1155
1156         image_zoom_set(view_window_active_image(vw), 0.0);
1157 }
1158
1159 static void view_copy_cb(GtkWidget *widget, gpointer data)
1160 {
1161         ViewWindow *vw = data;
1162         ImageWindow *imd;
1163
1164         imd = view_window_active_image(vw);
1165         file_util_copy(image_get_fd(imd), NULL, NULL, imd->widget);
1166 }
1167
1168 static void view_move_cb(GtkWidget *widget, gpointer data)
1169 {
1170         ViewWindow *vw = data;
1171         ImageWindow *imd;
1172
1173         imd = view_window_active_image(vw);
1174         file_util_move(image_get_fd(imd), NULL, NULL, imd->widget);
1175 }
1176
1177 static void view_rename_cb(GtkWidget *widget, gpointer data)
1178 {
1179         ViewWindow *vw = data;
1180         ImageWindow *imd;
1181
1182         imd = view_window_active_image(vw);
1183         file_util_rename(image_get_fd(imd), NULL, imd->widget);
1184 }
1185
1186 static void view_delete_cb(GtkWidget *widget, gpointer data)
1187 {
1188         ViewWindow *vw = data;
1189         ImageWindow *imd;
1190
1191         imd = view_window_active_image(vw);
1192         file_util_delete(image_get_fd(imd), NULL, imd->widget);
1193 }
1194
1195 static void view_fullscreen_cb(GtkWidget *widget, gpointer data)
1196 {
1197         ViewWindow *vw = data;
1198
1199         view_fullscreen_toggle(vw, FALSE);
1200 }
1201
1202 static void view_slideshow_start_cb(GtkWidget *widget, gpointer data)
1203 {
1204         ViewWindow *vw = data;
1205
1206         view_slideshow_start(vw);
1207 }
1208
1209 static void view_slideshow_stop_cb(GtkWidget *widget, gpointer data)
1210 {
1211         ViewWindow *vw = data;
1212
1213         view_slideshow_stop(vw);
1214 }
1215
1216 static void view_slideshow_pause_cb(GtkWidget *widget, gpointer data)
1217 {
1218         ViewWindow *vw = data;
1219
1220         slideshow_pause_toggle(vw->ss);
1221 }
1222
1223 static void view_close_cb(GtkWidget *widget, gpointer data)
1224 {
1225         ViewWindow *vw = data;
1226
1227         view_window_close(vw);
1228 }
1229
1230 static GtkWidget *view_popup_menu(ViewWindow *vw)
1231 {
1232         GtkWidget *menu;
1233         GtkWidget *item;
1234
1235         menu = popup_menu_short_lived();
1236
1237         menu_item_add_stock(menu, _("Zoom _in"), GTK_STOCK_ZOOM_IN, G_CALLBACK(view_zoom_in_cb), vw);
1238         menu_item_add_stock(menu, _("Zoom _out"), GTK_STOCK_ZOOM_OUT, G_CALLBACK(view_zoom_out_cb), vw);
1239         menu_item_add_stock(menu, _("Zoom _1:1"), GTK_STOCK_ZOOM_100, G_CALLBACK(view_zoom_1_1_cb), vw);
1240         menu_item_add_stock(menu, _("Fit image to _window"), GTK_STOCK_ZOOM_FIT, G_CALLBACK(view_zoom_fit_cb), vw);
1241         menu_item_add_divider(menu);
1242
1243         item = submenu_add_edit(menu, NULL, G_CALLBACK(view_edit_cb), vw);
1244         menu_item_add_divider(item);
1245         menu_item_add(item, _("Set as _wallpaper"), G_CALLBACK(view_wallpaper_cb), vw);
1246
1247         submenu_add_alter(menu, G_CALLBACK(view_alter_cb), vw);
1248
1249         menu_item_add_stock(menu, _("_Properties"), GTK_STOCK_PROPERTIES, G_CALLBACK(view_info_cb), vw);
1250
1251         menu_item_add_stock(menu, _("View in _new window"), GTK_STOCK_NEW, G_CALLBACK(view_new_window_cb), vw);
1252
1253         menu_item_add_divider(menu);
1254         menu_item_add_stock(menu, _("_Copy..."), GTK_STOCK_COPY, G_CALLBACK(view_copy_cb), vw);
1255         menu_item_add(menu, _("_Move..."), G_CALLBACK(view_move_cb), vw);
1256         menu_item_add(menu, _("_Rename..."), G_CALLBACK(view_rename_cb), vw);
1257         menu_item_add_stock(menu, _("_Delete..."), GTK_STOCK_DELETE, G_CALLBACK(view_delete_cb), vw);
1258
1259         menu_item_add_divider(menu);
1260
1261         if (vw->ss)
1262                 {
1263                 menu_item_add(menu, _("_Stop slideshow"), G_CALLBACK(view_slideshow_stop_cb), vw);
1264                 if (slideshow_paused(vw->ss))
1265                         {
1266                         item = menu_item_add(menu, _("Continue slides_how"),
1267                                              G_CALLBACK(view_slideshow_pause_cb), vw);
1268                         }
1269                 else
1270                         {
1271                         item = menu_item_add(menu, _("Pause slides_how"),
1272                                              G_CALLBACK(view_slideshow_pause_cb), vw);
1273                         }
1274                 }
1275         else
1276                 {
1277                 item = menu_item_add(menu, _("_Start slideshow"), G_CALLBACK(view_slideshow_start_cb), vw);
1278                 gtk_widget_set_sensitive(item, (vw->list != NULL) || view_window_contains_collection(vw));
1279                 item = menu_item_add(menu, _("Pause slides_how"), G_CALLBACK(view_slideshow_pause_cb), vw);
1280                 gtk_widget_set_sensitive(item, FALSE);
1281                 }
1282
1283         if (vw->fs)
1284                 {
1285                 menu_item_add(menu, _("Exit _full screen"), G_CALLBACK(view_fullscreen_cb), vw);
1286                 }
1287         else
1288                 {
1289                 menu_item_add(menu, _("_Full screen"), G_CALLBACK(view_fullscreen_cb), vw);
1290                 }
1291
1292         menu_item_add_divider(menu);
1293         menu_item_add_stock(menu, _("C_lose window"), GTK_STOCK_CLOSE, G_CALLBACK(view_close_cb), vw);
1294
1295         return menu;
1296 }
1297
1298 /*
1299  *-------------------------------------------------------------------
1300  * dnd confirm dir
1301  *-------------------------------------------------------------------
1302  */
1303
1304 typedef struct {
1305         ViewWindow *vw;
1306         GList *list;
1307 } CViewConfirmD;
1308
1309 static void view_dir_list_cancel(GtkWidget *widget, gpointer data)
1310 {
1311         /* do nothing */
1312 }
1313
1314 static void view_dir_list_do(ViewWindow *vw, GList *list, gint skip, gint recurse)
1315 {
1316         GList *work;
1317
1318         view_window_set_list(vw, NULL);
1319
1320         work = list;
1321         while (work)
1322                 {
1323                 FileData *fd = work->data;
1324                 work = work->next;
1325
1326                 if (isdir(fd->path))
1327                         {
1328                         if (!skip)
1329                                 {
1330                                 GList *list = NULL;
1331
1332                                 if (recurse)
1333                                         {
1334                                         list = filelist_recursive(fd->path);
1335                                         }
1336                                 else
1337                                         { /*FIXME */
1338                                         filelist_read(fd->path, &list, NULL);
1339                                         list = filelist_sort_path(list);
1340                                         list = filelist_filter(list, FALSE);
1341                                         }
1342                                 if (list) vw->list = g_list_concat(vw->list, list);
1343                                 }
1344                         }
1345                 else
1346                         {
1347                         /* FIXME: no filtering here */
1348                         vw->list = g_list_append(vw->list, file_data_ref(fd));
1349                         }
1350                 }
1351
1352         if (vw->list)
1353                 {
1354                 FileData *fd;
1355
1356                 vw->list_pointer = vw->list;
1357                 fd = vw->list->data;
1358                 image_change_fd(vw->imd, fd, image_zoom_get_default(vw->imd, zoom_mode));
1359
1360                 work = vw->list->next;
1361                 if (enable_read_ahead && work)
1362                         {
1363                         fd = work->data;
1364                         image_prebuffer_set(vw->imd, fd);
1365                         }
1366                 }
1367         else
1368                 {
1369                 image_change_fd(vw->imd, NULL, image_zoom_get_default(vw->imd, zoom_mode));
1370                 }
1371 }
1372
1373 static void view_dir_list_add(GtkWidget *widget, gpointer data)
1374 {
1375         CViewConfirmD *d = data;
1376         view_dir_list_do(d->vw, d->list, FALSE, FALSE);
1377 }
1378
1379 static void view_dir_list_recurse(GtkWidget *widget, gpointer data)
1380 {
1381         CViewConfirmD *d = data;
1382         view_dir_list_do(d->vw, d->list, FALSE, TRUE);
1383 }
1384
1385 static void view_dir_list_skip(GtkWidget *widget, gpointer data)
1386 {
1387         CViewConfirmD *d = data;
1388         view_dir_list_do(d->vw, d->list, TRUE, FALSE);
1389 }
1390
1391 static void view_dir_list_destroy(GtkWidget *widget, gpointer data)
1392 {
1393         CViewConfirmD *d = data;
1394         filelist_free(d->list);
1395         g_free(d);
1396 }
1397
1398 static GtkWidget *view_confirm_dir_list(ViewWindow *vw, GList *list)
1399 {
1400         GtkWidget *menu;
1401         CViewConfirmD *d;
1402
1403         d = g_new(CViewConfirmD, 1);
1404         d->vw = vw;
1405         d->list = list;
1406
1407         menu = popup_menu_short_lived();
1408         g_signal_connect(G_OBJECT(menu), "destroy",
1409                          G_CALLBACK(view_dir_list_destroy), d);
1410
1411         menu_item_add_stock(menu, _("Dropped list includes folders."), GTK_STOCK_DND_MULTIPLE, NULL, NULL);
1412         menu_item_add_divider(menu);
1413         menu_item_add_stock(menu, _("_Add contents"), GTK_STOCK_OK, G_CALLBACK(view_dir_list_add), d);
1414         menu_item_add_stock(menu, _("Add contents _recursive"), GTK_STOCK_ADD, G_CALLBACK(view_dir_list_recurse), d);
1415         menu_item_add_stock(menu, _("_Skip folders"), GTK_STOCK_REMOVE, G_CALLBACK(view_dir_list_skip), d);
1416         menu_item_add_divider(menu);
1417         menu_item_add_stock(menu, _("Cancel"), GTK_STOCK_CANCEL, G_CALLBACK(view_dir_list_cancel), d);
1418
1419         return menu;
1420 }
1421
1422 /*
1423  *-----------------------------------------------------------------------------
1424  * image drag and drop routines
1425  *-----------------------------------------------------------------------------
1426  */
1427
1428 static void view_window_get_dnd_data(GtkWidget *widget, GdkDragContext *context,
1429                                      gint x, gint y,
1430                                      GtkSelectionData *selection_data, guint info,
1431                                      guint time, gpointer data)
1432 {
1433         ViewWindow *vw = data;
1434         ImageWindow *imd;
1435
1436         if (gtk_drag_get_source_widget(context) == vw->imd->pr) return;
1437
1438         imd = vw->imd;
1439
1440         if (info == TARGET_URI_LIST || info == TARGET_APP_COLLECTION_MEMBER)
1441                 {
1442                 CollectionData *source;
1443                 GList *list;
1444                 GList *info_list;
1445
1446                 if (info == TARGET_URI_LIST)
1447                         {
1448                         GList *work;
1449
1450                         list = uri_filelist_from_text((gchar *)selection_data->data, TRUE);
1451
1452                         work = list;
1453                         while (work)
1454                                 {
1455                                 FileData *fd = work->data;
1456                                 if (isdir(fd->path))
1457                                         {
1458                                         GtkWidget *menu;
1459                                         menu = view_confirm_dir_list(vw, list);
1460                                         gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 0, time);
1461                                         return;
1462                                         }
1463                                 work = work->next;
1464                                 }
1465
1466                         list = filelist_filter(list, FALSE);
1467
1468                         source = NULL;
1469                         info_list = NULL;
1470                         }
1471                 else
1472                         {
1473                         source = collection_from_dnd_data((gchar *)selection_data->data, &list, &info_list);
1474                         }
1475
1476                 if (list)
1477                         {
1478                         FileData *fd;
1479
1480                         fd = list->data;
1481                         if (isfile(fd->path))
1482                                 {
1483                                 view_slideshow_stop(vw);
1484                                 view_window_set_list(vw, NULL);
1485
1486                                 if (source && info_list)
1487                                         {
1488                                         image_change_from_collection(imd, source, info_list->data, image_zoom_get_default(imd, zoom_mode));
1489                                         }
1490                                 else
1491                                         {
1492                                         if (list->next)
1493                                                 {
1494                                                 vw->list = list;
1495                                                 list = NULL;
1496
1497                                                 vw->list_pointer = vw->list;
1498                                                 }
1499                                         image_change_fd(imd, fd, image_zoom_get_default(imd, zoom_mode));
1500                                         }
1501                                 }
1502                         }
1503                 filelist_free(list);
1504                 g_list_free(info_list);
1505                 }
1506 }
1507
1508 static void view_window_set_dnd_data(GtkWidget *widget, GdkDragContext *context,
1509                                      GtkSelectionData *selection_data, guint info,
1510                                      guint time, gpointer data)
1511 {
1512         ViewWindow *vw = data;
1513         FileData *fd;
1514
1515         fd = image_get_fd(vw->imd);
1516
1517         if (fd)
1518                 {
1519                 gchar *text = NULL;
1520                 gint len;
1521                 gint plain_text;
1522                 GList *list;
1523
1524                 switch (info)
1525                         {
1526                         case TARGET_URI_LIST:
1527                                 plain_text = FALSE;
1528                                 break;
1529                         case TARGET_TEXT_PLAIN:
1530                         default:
1531                                 plain_text = TRUE;
1532                                 break;
1533                         }
1534                 list = g_list_append(NULL, fd);
1535                 text = uri_text_from_filelist(list, &len, plain_text);
1536                 g_list_free(list);
1537                 if (text)
1538                         {
1539                         gtk_selection_data_set (selection_data, selection_data->target,
1540                                                 8, (guchar *)text, len);
1541                         g_free(text);
1542                         }
1543                 }
1544         else
1545                 {
1546                 gtk_selection_data_set (selection_data, selection_data->target,
1547                                         8, NULL, 0);
1548                 }
1549 }
1550
1551 static void view_window_dnd_init(ViewWindow *vw)
1552 {
1553         ImageWindow *imd;
1554
1555         imd = vw->imd;
1556
1557         gtk_drag_source_set(imd->pr, GDK_BUTTON2_MASK,
1558                             dnd_file_drag_types, dnd_file_drag_types_count,
1559                             GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
1560         g_signal_connect(G_OBJECT(imd->pr), "drag_data_get",
1561                          G_CALLBACK(view_window_set_dnd_data), vw);
1562
1563         gtk_drag_dest_set(imd->pr,
1564                           GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP,
1565                           dnd_file_drop_types, dnd_file_drop_types_count,
1566                           GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
1567         g_signal_connect(G_OBJECT(imd->pr), "drag_data_received",
1568                          G_CALLBACK(view_window_get_dnd_data), vw);
1569 }
1570
1571 /*
1572  *-----------------------------------------------------------------------------
1573  * maintenance (for rename, move, remove)
1574  *-----------------------------------------------------------------------------
1575  */
1576
1577 static void view_real_removed(ViewWindow *vw, FileData *fd, GList *ignore_list)
1578 {
1579         ImageWindow *imd;
1580         FileData *image_fd;
1581
1582         imd = view_window_active_image(vw);
1583         image_fd = image_get_fd(imd);
1584
1585         if (image_fd && image_fd == fd)
1586                 {
1587                 if (vw->list)
1588                         {
1589                         view_list_step(vw, TRUE);
1590                         if (image_get_fd(imd) == image_fd)
1591                                 {
1592                                 view_list_step(vw, FALSE);
1593                                 }
1594                         }
1595                 else if (view_window_contains_collection(vw))
1596                         {
1597                         view_collection_step(vw, TRUE);
1598                         if (image_get_fd(imd) == image_fd)
1599                                 {
1600                                 view_collection_step(vw, FALSE);
1601                                 }
1602                         }
1603                 if (image_get_fd(imd) == image_fd)
1604                         {
1605                         image_change_fd(imd, NULL, image_zoom_get_default(imd, zoom_mode));
1606                         }
1607                 }
1608
1609         if (vw->list)
1610                 {
1611                 GList *work;
1612                 GList *old;
1613
1614                 old = vw->list_pointer;
1615
1616                 work = vw->list;
1617                 while (work)
1618                         {
1619                         FileData *chk_fd;
1620                         GList *chk_link;
1621
1622                         chk_fd = work->data;
1623                         chk_link = work;
1624                         work = work->next;
1625
1626                         if (chk_fd == fd)
1627                                 {
1628                                 if (vw->list_pointer == chk_link)
1629                                         {
1630                                         vw->list_pointer = (chk_link->next) ? chk_link->next : chk_link->prev;
1631                                         }
1632                                 vw->list = g_list_remove(vw->list, chk_fd);
1633                                 file_data_unref(chk_fd);
1634                                 }
1635                         }
1636
1637                 /* handles stepping correctly when same image is in the list more than once */
1638                 if (old && old != vw->list_pointer)
1639                         {
1640                         FileData *fd;
1641
1642                         if (vw->list_pointer)
1643                                 {
1644                                 fd = vw->list_pointer->data;
1645                                 }
1646                         else
1647                                 {
1648                                 fd = NULL;
1649                                 }
1650
1651                         image_change_fd(imd, fd, image_zoom_get_default(imd, zoom_mode));
1652                         }
1653                 }
1654
1655         image_osd_update(imd);
1656 }
1657
1658 static void view_real_moved(ViewWindow *vw, FileData *fd)
1659 {
1660 /*
1661         ImageWindow *imd;
1662         const gchar *image_path;
1663
1664         imd = view_window_active_image(vw);
1665 */
1666 /*
1667         image_path = image_get_path(imd);
1668
1669         if (image_path && strcmp(image_path, fd->change->source) == 0)
1670                 {
1671                 image_set_fd(imd, dest);
1672                 }
1673 */
1674 /*
1675         if (vw->list)
1676                 {
1677                 GList *work;
1678                 work = vw->list;
1679                 while (work)
1680                         {
1681                         gchar *chk_path;
1682
1683                         chk_path = work->data;
1684
1685                         if (strcmp(chk_path, source) == 0)
1686                                 {
1687                                 work->data = g_strdup(dest);
1688                                 g_free(chk_path);
1689                                 }
1690
1691                         work = work->next;
1692                         }
1693                 }
1694 */
1695 }
1696
1697 void view_window_maint_removed(FileData *fd, GList *ignore_list)
1698 {
1699         GList *work = view_window_list;
1700         while (work)
1701                 {
1702                 ViewWindow *vw = work->data;
1703                 work = work->next;
1704
1705                 view_real_removed(vw, fd, ignore_list);
1706                 }
1707 }
1708
1709 void view_window_maint_moved(FileData *fd)
1710 {
1711         GList *work = view_window_list;
1712         while (work)
1713                 {
1714                 ViewWindow *vw = work->data;
1715                 work = work->next;
1716
1717                 view_real_moved(vw, fd);
1718                 }
1719 }
1720