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