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