updated copyright in source files
[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);
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         if (vw->fs) view_fullscreen_toggle(vw, FALSE);
1118
1119         imd = view_window_active_image(vw);
1120         info_window_new(image_get_fd(imd), NULL);
1121 }
1122
1123 static void view_wallpaper_cb(GtkWidget *widget, gpointer data)
1124 {
1125         ViewWindow *vw = data;
1126         ImageWindow *imd;
1127
1128         imd = view_window_active_image(vw);
1129         image_to_root_window(imd, (image_zoom_get(imd) == 0.0));
1130 }
1131
1132 static void view_zoom_in_cb(GtkWidget *widget, gpointer data)
1133 {
1134         ViewWindow *vw = data;
1135
1136         image_zoom_adjust(view_window_active_image(vw), get_zoom_increment());
1137 }
1138
1139 static void view_zoom_out_cb(GtkWidget *widget, gpointer data)
1140 {
1141         ViewWindow *vw = data;
1142
1143         image_zoom_adjust(view_window_active_image(vw), -get_zoom_increment());
1144 }
1145
1146 static void view_zoom_1_1_cb(GtkWidget *widget, gpointer data)
1147 {
1148         ViewWindow *vw = data;
1149
1150         image_zoom_set(view_window_active_image(vw), 1.0);
1151 }
1152
1153 static void view_zoom_fit_cb(GtkWidget *widget, gpointer data)
1154 {
1155         ViewWindow *vw = data;
1156
1157         image_zoom_set(view_window_active_image(vw), 0.0);
1158 }
1159
1160 static void view_copy_cb(GtkWidget *widget, gpointer data)
1161 {
1162         ViewWindow *vw = data;
1163         ImageWindow *imd;
1164
1165         imd = view_window_active_image(vw);
1166         file_util_copy(image_get_fd(imd), NULL, NULL, imd->widget);
1167 }
1168
1169 static void view_move_cb(GtkWidget *widget, gpointer data)
1170 {
1171         ViewWindow *vw = data;
1172         ImageWindow *imd;
1173
1174         imd = view_window_active_image(vw);
1175         file_util_move(image_get_fd(imd), NULL, NULL, imd->widget);
1176 }
1177
1178 static void view_rename_cb(GtkWidget *widget, gpointer data)
1179 {
1180         ViewWindow *vw = data;
1181         ImageWindow *imd;
1182
1183         imd = view_window_active_image(vw);
1184         file_util_rename(image_get_fd(imd), NULL, imd->widget);
1185 }
1186
1187 static void view_delete_cb(GtkWidget *widget, gpointer data)
1188 {
1189         ViewWindow *vw = data;
1190         ImageWindow *imd;
1191
1192         imd = view_window_active_image(vw);
1193         file_util_delete(image_get_fd(imd), NULL, imd->widget);
1194 }
1195
1196 static void view_fullscreen_cb(GtkWidget *widget, gpointer data)
1197 {
1198         ViewWindow *vw = data;
1199
1200         view_fullscreen_toggle(vw, FALSE);
1201 }
1202
1203 static void view_slideshow_start_cb(GtkWidget *widget, gpointer data)
1204 {
1205         ViewWindow *vw = data;
1206
1207         view_slideshow_start(vw);
1208 }
1209
1210 static void view_slideshow_stop_cb(GtkWidget *widget, gpointer data)
1211 {
1212         ViewWindow *vw = data;
1213
1214         view_slideshow_stop(vw);
1215 }
1216
1217 static void view_slideshow_pause_cb(GtkWidget *widget, gpointer data)
1218 {
1219         ViewWindow *vw = data;
1220
1221         slideshow_pause_toggle(vw->ss);
1222 }
1223
1224 static void view_close_cb(GtkWidget *widget, gpointer data)
1225 {
1226         ViewWindow *vw = data;
1227
1228         view_window_close(vw);
1229 }
1230
1231 static LayoutWindow *view_new_layout_with_path(const gchar *path)
1232 {
1233         LayoutWindow *nw;
1234
1235         nw = layout_new(NULL, FALSE, FALSE);
1236         layout_sort_set(nw, options->file_sort.method, options->file_sort.ascending);
1237         layout_set_path(nw, path);
1238         return nw;
1239 }
1240
1241
1242 static void view_set_layout_path_cb(GtkWidget *widget, gpointer data)
1243 {
1244         ViewWindow *vw = data;
1245         LayoutWindow *lw;
1246         const gchar *path;
1247         ImageWindow *imd;
1248
1249         imd = view_window_active_image(vw);
1250
1251         if (!imd || !imd->image_fd) return;
1252         path = imd->image_fd->path;
1253         if (!path) return;
1254
1255         lw = layout_find_by_image_fd(imd);
1256         if (lw)
1257                 layout_set_path(lw, path);
1258         else
1259                 view_new_layout_with_path(path);
1260         view_window_close(vw);
1261 }
1262
1263 static GtkWidget *view_popup_menu(ViewWindow *vw)
1264 {
1265         GtkWidget *menu;
1266         GtkWidget *item;
1267
1268         menu = popup_menu_short_lived();
1269
1270         menu_item_add_stock(menu, _("Zoom _in"), GTK_STOCK_ZOOM_IN, G_CALLBACK(view_zoom_in_cb), vw);
1271         menu_item_add_stock(menu, _("Zoom _out"), GTK_STOCK_ZOOM_OUT, G_CALLBACK(view_zoom_out_cb), vw);
1272         menu_item_add_stock(menu, _("Zoom _1:1"), GTK_STOCK_ZOOM_100, G_CALLBACK(view_zoom_1_1_cb), vw);
1273         menu_item_add_stock(menu, _("Fit image to _window"), GTK_STOCK_ZOOM_FIT, G_CALLBACK(view_zoom_fit_cb), vw);
1274         menu_item_add_divider(menu);
1275
1276         item = submenu_add_edit(menu, NULL, G_CALLBACK(view_edit_cb), vw);
1277         menu_item_add_divider(item);
1278         menu_item_add(item, _("Set as _wallpaper"), G_CALLBACK(view_wallpaper_cb), vw);
1279
1280         submenu_add_alter(menu, G_CALLBACK(view_alter_cb), vw);
1281
1282         menu_item_add_stock(menu, _("_Properties"), GTK_STOCK_PROPERTIES, G_CALLBACK(view_info_cb), vw);
1283
1284         menu_item_add_stock(menu, _("View in _new window"), GTK_STOCK_NEW, G_CALLBACK(view_new_window_cb), vw);
1285         item = menu_item_add(menu, _("_Go to directory view"), G_CALLBACK(view_set_layout_path_cb), vw);
1286
1287         menu_item_add_divider(menu);
1288         menu_item_add_stock(menu, _("_Copy..."), GTK_STOCK_COPY, G_CALLBACK(view_copy_cb), vw);
1289         menu_item_add(menu, _("_Move..."), G_CALLBACK(view_move_cb), vw);
1290         menu_item_add(menu, _("_Rename..."), G_CALLBACK(view_rename_cb), vw);
1291         menu_item_add_stock(menu, _("_Delete..."), GTK_STOCK_DELETE, G_CALLBACK(view_delete_cb), vw);
1292
1293         menu_item_add_divider(menu);
1294
1295         if (vw->ss)
1296                 {
1297                 menu_item_add(menu, _("_Stop slideshow"), G_CALLBACK(view_slideshow_stop_cb), vw);
1298                 if (slideshow_paused(vw->ss))
1299                         {
1300                         item = menu_item_add(menu, _("Continue slides_how"),
1301                                              G_CALLBACK(view_slideshow_pause_cb), vw);
1302                         }
1303                 else
1304                         {
1305                         item = menu_item_add(menu, _("Pause slides_how"),
1306                                              G_CALLBACK(view_slideshow_pause_cb), vw);
1307                         }
1308                 }
1309         else
1310                 {
1311                 item = menu_item_add(menu, _("_Start slideshow"), G_CALLBACK(view_slideshow_start_cb), vw);
1312                 gtk_widget_set_sensitive(item, (vw->list != NULL) || view_window_contains_collection(vw));
1313                 item = menu_item_add(menu, _("Pause slides_how"), G_CALLBACK(view_slideshow_pause_cb), vw);
1314                 gtk_widget_set_sensitive(item, FALSE);
1315                 }
1316
1317         if (vw->fs)
1318                 {
1319                 menu_item_add(menu, _("Exit _full screen"), G_CALLBACK(view_fullscreen_cb), vw);
1320                 }
1321         else
1322                 {
1323                 menu_item_add(menu, _("_Full screen"), G_CALLBACK(view_fullscreen_cb), vw);
1324                 }
1325
1326         menu_item_add_divider(menu);
1327         menu_item_add_stock(menu, _("C_lose window"), GTK_STOCK_CLOSE, G_CALLBACK(view_close_cb), vw);
1328
1329         return menu;
1330 }
1331
1332 /*
1333  *-------------------------------------------------------------------
1334  * dnd confirm dir
1335  *-------------------------------------------------------------------
1336  */
1337
1338 typedef struct {
1339         ViewWindow *vw;
1340         GList *list;
1341 } CViewConfirmD;
1342
1343 static void view_dir_list_cancel(GtkWidget *widget, gpointer data)
1344 {
1345         /* do nothing */
1346 }
1347
1348 static void view_dir_list_do(ViewWindow *vw, GList *list, gint skip, gint recurse)
1349 {
1350         GList *work;
1351
1352         view_window_set_list(vw, NULL);
1353
1354         work = list;
1355         while (work)
1356                 {
1357                 FileData *fd = work->data;
1358                 work = work->next;
1359
1360                 if (isdir(fd->path))
1361                         {
1362                         if (!skip)
1363                                 {
1364                                 GList *list = NULL;
1365
1366                                 if (recurse)
1367                                         {
1368                                         list = filelist_recursive(fd->path);
1369                                         }
1370                                 else
1371                                         { /*FIXME */
1372                                         filelist_read(fd->path, &list, NULL);
1373                                         list = filelist_sort_path(list);
1374                                         list = filelist_filter(list, FALSE);
1375                                         }
1376                                 if (list) vw->list = g_list_concat(vw->list, list);
1377                                 }
1378                         }
1379                 else
1380                         {
1381                         /* FIXME: no filtering here */
1382                         vw->list = g_list_append(vw->list, file_data_ref(fd));
1383                         }
1384                 }
1385
1386         if (vw->list)
1387                 {
1388                 FileData *fd;
1389
1390                 vw->list_pointer = vw->list;
1391                 fd = vw->list->data;
1392                 image_change_fd(vw->imd, fd, image_zoom_get_default(vw->imd, options->image.zoom_mode));
1393
1394                 work = vw->list->next;
1395                 if (options->image.enable_read_ahead && work)
1396                         {
1397                         fd = work->data;
1398                         image_prebuffer_set(vw->imd, fd);
1399                         }
1400                 }
1401         else
1402                 {
1403                 image_change_fd(vw->imd, NULL, image_zoom_get_default(vw->imd, options->image.zoom_mode));
1404                 }
1405 }
1406
1407 static void view_dir_list_add(GtkWidget *widget, gpointer data)
1408 {
1409         CViewConfirmD *d = data;
1410         view_dir_list_do(d->vw, d->list, FALSE, FALSE);
1411 }
1412
1413 static void view_dir_list_recurse(GtkWidget *widget, gpointer data)
1414 {
1415         CViewConfirmD *d = data;
1416         view_dir_list_do(d->vw, d->list, FALSE, TRUE);
1417 }
1418
1419 static void view_dir_list_skip(GtkWidget *widget, gpointer data)
1420 {
1421         CViewConfirmD *d = data;
1422         view_dir_list_do(d->vw, d->list, TRUE, FALSE);
1423 }
1424
1425 static void view_dir_list_destroy(GtkWidget *widget, gpointer data)
1426 {
1427         CViewConfirmD *d = data;
1428         filelist_free(d->list);
1429         g_free(d);
1430 }
1431
1432 static GtkWidget *view_confirm_dir_list(ViewWindow *vw, GList *list)
1433 {
1434         GtkWidget *menu;
1435         CViewConfirmD *d;
1436
1437         d = g_new(CViewConfirmD, 1);
1438         d->vw = vw;
1439         d->list = list;
1440
1441         menu = popup_menu_short_lived();
1442         g_signal_connect(G_OBJECT(menu), "destroy",
1443                          G_CALLBACK(view_dir_list_destroy), d);
1444
1445         menu_item_add_stock(menu, _("Dropped list includes folders."), GTK_STOCK_DND_MULTIPLE, NULL, NULL);
1446         menu_item_add_divider(menu);
1447         menu_item_add_stock(menu, _("_Add contents"), GTK_STOCK_OK, G_CALLBACK(view_dir_list_add), d);
1448         menu_item_add_stock(menu, _("Add contents _recursive"), GTK_STOCK_ADD, G_CALLBACK(view_dir_list_recurse), d);
1449         menu_item_add_stock(menu, _("_Skip folders"), GTK_STOCK_REMOVE, G_CALLBACK(view_dir_list_skip), d);
1450         menu_item_add_divider(menu);
1451         menu_item_add_stock(menu, _("Cancel"), GTK_STOCK_CANCEL, G_CALLBACK(view_dir_list_cancel), d);
1452
1453         return menu;
1454 }
1455
1456 /*
1457  *-----------------------------------------------------------------------------
1458  * image drag and drop routines
1459  *-----------------------------------------------------------------------------
1460  */
1461
1462 static void view_window_get_dnd_data(GtkWidget *widget, GdkDragContext *context,
1463                                      gint x, gint y,
1464                                      GtkSelectionData *selection_data, guint info,
1465                                      guint time, gpointer data)
1466 {
1467         ViewWindow *vw = data;
1468         ImageWindow *imd;
1469
1470         if (gtk_drag_get_source_widget(context) == vw->imd->pr) return;
1471
1472         imd = vw->imd;
1473
1474         if (info == TARGET_URI_LIST || info == TARGET_APP_COLLECTION_MEMBER)
1475                 {
1476                 CollectionData *source;
1477                 GList *list;
1478                 GList *info_list;
1479
1480                 if (info == TARGET_URI_LIST)
1481                         {
1482                         GList *work;
1483
1484                         list = uri_filelist_from_text((gchar *)selection_data->data, TRUE);
1485
1486                         work = list;
1487                         while (work)
1488                                 {
1489                                 FileData *fd = work->data;
1490                                 if (isdir(fd->path))
1491                                         {
1492                                         GtkWidget *menu;
1493                                         menu = view_confirm_dir_list(vw, list);
1494                                         gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 0, time);
1495                                         return;
1496                                         }
1497                                 work = work->next;
1498                                 }
1499
1500                         list = filelist_filter(list, FALSE);
1501
1502                         source = NULL;
1503                         info_list = NULL;
1504                         }
1505                 else
1506                         {
1507                         source = collection_from_dnd_data((gchar *)selection_data->data, &list, &info_list);
1508                         }
1509
1510                 if (list)
1511                         {
1512                         FileData *fd;
1513
1514                         fd = list->data;
1515                         if (isfile(fd->path))
1516                                 {
1517                                 view_slideshow_stop(vw);
1518                                 view_window_set_list(vw, NULL);
1519
1520                                 if (source && info_list)
1521                                         {
1522                                         image_change_from_collection(imd, source, info_list->data, image_zoom_get_default(imd, options->image.zoom_mode));
1523                                         }
1524                                 else
1525                                         {
1526                                         if (list->next)
1527                                                 {
1528                                                 vw->list = list;
1529                                                 list = NULL;
1530
1531                                                 vw->list_pointer = vw->list;
1532                                                 }
1533                                         image_change_fd(imd, fd, image_zoom_get_default(imd, options->image.zoom_mode));
1534                                         }
1535                                 }
1536                         }
1537                 filelist_free(list);
1538                 g_list_free(info_list);
1539                 }
1540 }
1541
1542 static void view_window_set_dnd_data(GtkWidget *widget, GdkDragContext *context,
1543                                      GtkSelectionData *selection_data, guint info,
1544                                      guint time, gpointer data)
1545 {
1546         ViewWindow *vw = data;
1547         FileData *fd;
1548
1549         fd = image_get_fd(vw->imd);
1550
1551         if (fd)
1552                 {
1553                 gchar *text = NULL;
1554                 gint len;
1555                 gint plain_text;
1556                 GList *list;
1557
1558                 switch (info)
1559                         {
1560                         case TARGET_URI_LIST:
1561                                 plain_text = FALSE;
1562                                 break;
1563                         case TARGET_TEXT_PLAIN:
1564                         default:
1565                                 plain_text = TRUE;
1566                                 break;
1567                         }
1568                 list = g_list_append(NULL, fd);
1569                 text = uri_text_from_filelist(list, &len, plain_text);
1570                 g_list_free(list);
1571                 if (text)
1572                         {
1573                         gtk_selection_data_set (selection_data, selection_data->target,
1574                                                 8, (guchar *)text, len);
1575                         g_free(text);
1576                         }
1577                 }
1578         else
1579                 {
1580                 gtk_selection_data_set (selection_data, selection_data->target,
1581                                         8, NULL, 0);
1582                 }
1583 }
1584
1585 static void view_window_dnd_init(ViewWindow *vw)
1586 {
1587         ImageWindow *imd;
1588
1589         imd = vw->imd;
1590
1591         gtk_drag_source_set(imd->pr, GDK_BUTTON2_MASK,
1592                             dnd_file_drag_types, dnd_file_drag_types_count,
1593                             GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
1594         g_signal_connect(G_OBJECT(imd->pr), "drag_data_get",
1595                          G_CALLBACK(view_window_set_dnd_data), vw);
1596
1597         gtk_drag_dest_set(imd->pr,
1598                           GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP,
1599                           dnd_file_drop_types, dnd_file_drop_types_count,
1600                           GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
1601         g_signal_connect(G_OBJECT(imd->pr), "drag_data_received",
1602                          G_CALLBACK(view_window_get_dnd_data), vw);
1603 }
1604
1605 /*
1606  *-----------------------------------------------------------------------------
1607  * maintenance (for rename, move, remove)
1608  *-----------------------------------------------------------------------------
1609  */
1610
1611 static void view_real_removed(ViewWindow *vw, FileData *fd, GList *ignore_list)
1612 {
1613         ImageWindow *imd;
1614         FileData *image_fd;
1615
1616         imd = view_window_active_image(vw);
1617         image_fd = image_get_fd(imd);
1618
1619         if (image_fd && image_fd == fd)
1620                 {
1621                 if (vw->list)
1622                         {
1623                         view_list_step(vw, TRUE);
1624                         if (image_get_fd(imd) == image_fd)
1625                                 {
1626                                 view_list_step(vw, FALSE);
1627                                 }
1628                         }
1629                 else if (view_window_contains_collection(vw))
1630                         {
1631                         view_collection_step(vw, TRUE);
1632                         if (image_get_fd(imd) == image_fd)
1633                                 {
1634                                 view_collection_step(vw, FALSE);
1635                                 }
1636                         }
1637                 if (image_get_fd(imd) == image_fd)
1638                         {
1639                         image_change_fd(imd, NULL, image_zoom_get_default(imd, options->image.zoom_mode));
1640                         }
1641                 }
1642
1643         if (vw->list)
1644                 {
1645                 GList *work;
1646                 GList *old;
1647
1648                 old = vw->list_pointer;
1649
1650                 work = vw->list;
1651                 while (work)
1652                         {
1653                         FileData *chk_fd;
1654                         GList *chk_link;
1655
1656                         chk_fd = work->data;
1657                         chk_link = work;
1658                         work = work->next;
1659
1660                         if (chk_fd == fd)
1661                                 {
1662                                 if (vw->list_pointer == chk_link)
1663                                         {
1664                                         vw->list_pointer = (chk_link->next) ? chk_link->next : chk_link->prev;
1665                                         }
1666                                 vw->list = g_list_remove(vw->list, chk_fd);
1667                                 file_data_unref(chk_fd);
1668                                 }
1669                         }
1670
1671                 /* handles stepping correctly when same image is in the list more than once */
1672                 if (old && old != vw->list_pointer)
1673                         {
1674                         FileData *fd;
1675
1676                         if (vw->list_pointer)
1677                                 {
1678                                 fd = vw->list_pointer->data;
1679                                 }
1680                         else
1681                                 {
1682                                 fd = NULL;
1683                                 }
1684
1685                         image_change_fd(imd, fd, image_zoom_get_default(imd, options->image.zoom_mode));
1686                         }
1687                 }
1688
1689         image_osd_update(imd);
1690 }
1691
1692 static void view_real_moved(ViewWindow *vw, FileData *fd)
1693 {
1694 /*
1695         ImageWindow *imd;
1696         const gchar *image_path;
1697
1698         imd = view_window_active_image(vw);
1699 */
1700 /*
1701         image_path = image_get_path(imd);
1702
1703         if (image_path && strcmp(image_path, fd->change->source) == 0)
1704                 {
1705                 image_set_fd(imd, dest);
1706                 }
1707 */
1708 /*
1709         if (vw->list)
1710                 {
1711                 GList *work;
1712                 work = vw->list;
1713                 while (work)
1714                         {
1715                         gchar *chk_path;
1716
1717                         chk_path = work->data;
1718
1719                         if (strcmp(chk_path, source) == 0)
1720                                 {
1721                                 work->data = g_strdup(dest);
1722                                 g_free(chk_path);
1723                                 }
1724
1725                         work = work->next;
1726                         }
1727                 }
1728 */
1729 }
1730
1731 void view_window_maint_removed(FileData *fd, GList *ignore_list)
1732 {
1733         GList *work = view_window_list;
1734         while (work)
1735                 {
1736                 ViewWindow *vw = work->data;
1737                 work = work->next;
1738
1739                 view_real_removed(vw, fd, ignore_list);
1740                 }
1741 }
1742
1743 void view_window_maint_moved(FileData *fd)
1744 {
1745         GList *work = view_window_list;
1746         while (work)
1747                 {
1748                 ViewWindow *vw = work->data;
1749                 work = work->next;
1750
1751                 view_real_moved(vw, fd);
1752                 }
1753 }