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