split filelist.c to filefilter.c and filedata.c
[geeqie.git] / src / layout_image.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 #include "main.h"
14 #include "layout_image.h"
15
16 #include "collect.h"
17 #include "dnd.h"
18 #include "debug.h"
19 #include "editors.h"
20 #include "filedata.h"
21 #include "fullscreen.h"
22 #include "image.h"
23 #include "image-overlay.h"
24 #include "img-view.h"
25 #include "info.h"
26 #include "layout.h"
27 #include "layout_util.h"
28 #include "menu.h"
29 #include "pixbuf_util.h"
30 #include "utilops.h"
31 #include "slideshow.h"
32 #include "ui_bookmark.h"
33 #include "ui_fileops.h"
34 #include "ui_menu.h"
35
36 #include <gdk/gdkkeysyms.h> /* for keyboard values */
37
38
39 static GtkWidget *layout_image_pop_menu(LayoutWindow *lw);
40 static void layout_image_set_buttons(LayoutWindow *lw);
41
42 /*
43  *----------------------------------------------------------------------------
44  * full screen overlay
45  *----------------------------------------------------------------------------
46  */
47
48 void layout_image_overlay_toggle(LayoutWindow *lw)
49 {
50         if (!lw) return;
51         image_osd_toggle(lw->image);
52 }
53
54 /*
55  *----------------------------------------------------------------------------
56  * full screen
57  *----------------------------------------------------------------------------
58  */
59 #if 0
60 static void layout_image_fullscreen_menu_pos_cb(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer data)
61 {
62         LayoutWindow *lw = data;
63
64         if (!lw->full_screen) return;
65
66         gdk_window_get_origin(lw->full_screen->imd->pr->window, x, y);
67         popup_menu_position_clamp(menu, x, y, 0);
68 }
69
70 static void layout_image_full_screen_menu_popup(LayoutWindow *lw)
71 {
72         GtkWidget *menu;
73
74         menu = layout_image_pop_menu(lw);
75         gtk_menu_popup(GTK_MENU(menu), NULL, NULL, layout_image_fullscreen_menu_pos_cb, lw, 0, GDK_CURRENT_TIME);
76 }
77
78 /* this is handled by layout_key_press_cb */
79
80
81 static gint layout_image_full_screen_key_press_cb(GtkWidget *widget, GdkEventKey *event, gpointer data)
82 {
83         LayoutWindow *lw = data;
84         gint stop_signal;
85         gint x = 0;
86         gint y = 0;
87
88         stop_signal = TRUE;
89         switch (event->keyval)
90                 {
91                 case GDK_Left: case GDK_KP_Left:
92                         x -= 1;
93                         break;
94                 case GDK_Right: case GDK_KP_Right:
95                         x += 1;
96                         break;
97                 case GDK_Up: case GDK_KP_Up:
98                         y -= 1;
99                         break;
100                 case GDK_Down: case GDK_KP_Down:
101                         y += 1;
102                         break;
103                 default:
104                         stop_signal = FALSE;
105                         break;
106                 }
107
108         if (x != 0 || y!= 0)
109                 {
110                 if (event->state & GDK_SHIFT_MASK)
111                         {
112                         x *= 3;
113                         y *= 3;
114                         }
115
116                 keyboard_scroll_calc(&x, &y, event);
117                 layout_image_scroll(lw, x, y);
118                 }
119
120         if (stop_signal) return stop_signal;
121
122         if (event->state & GDK_CONTROL_MASK)
123                 {
124                 gint n = -1;
125
126                 stop_signal = TRUE;
127                 switch (event->keyval)
128                         {
129                         case '1':
130                                 n = 0;
131                                 break;
132                         case '2':
133                                 n = 1;
134                                 break;
135                         case '3':
136                                 n = 2;
137                                 break;
138                         case '4':
139                                 n = 3;
140                                 break;
141                         case '5':
142                                 n = 4;
143                                 break;
144                         case '6':
145                                 n = 5;
146                                 break;
147                         case '7':
148                                 n = 6;
149                                 break;
150                         case '8':
151                                 n = 7;
152                                 break;
153                         case '9':
154                                 n = 8;
155                                 break;
156                         case '0':
157                                 n = 9;
158                                 break;
159                         case 'C': case 'c':
160                                 file_util_copy(layout_image_get_fd(lw), NULL, NULL, widget);
161                                 break;
162                         case 'M': case 'm':
163                                 file_util_move(layout_image_get_fd(lw), NULL, NULL, widget);
164                                 break;
165                         case 'R': case 'r':
166                                 file_util_rename(layout_image_get_fd(lw), NULL, widget);
167                                 break;
168                         case 'D': case 'd':
169                                 file_util_delete(layout_image_get_fd(lw), NULL, widget);
170                                 break;
171                         case 'P': case 'p':
172                                 info_window_new(layout_image_get_fd(lw), NULL, NULL);
173                                 break;
174                         case 'Q': case 'q':
175                                 exit_program();
176                                 return FALSE;
177                                 break;
178                         default:
179                                 stop_signal = FALSE;
180                                 break;
181                         }
182                 if (n != -1)
183                         {
184                         if (!editor_window_flag_set(n))
185                                 {
186                                 layout_image_full_screen_stop(lw);
187                                 }
188                         start_editor_from_file(n, layout_image_get_fd(lw));
189                         }
190                 }
191         else if (event->state & GDK_SHIFT_MASK)
192                 {
193                 stop_signal = TRUE;
194                 switch (event->keyval)
195                         {
196                         case 'R': case 'r':
197                                 layout_image_alter(lw, ALTER_ROTATE_180);
198                                 break;
199                         case 'M': case 'm':
200                                 layout_image_alter(lw, ALTER_MIRROR);
201                                 break;
202                         case 'F': case 'f':
203                                 layout_image_alter(lw, ALTER_FLIP);
204                                 break;
205                         case 'G': case 'g':
206                                 layout_image_alter(lw, ALTER_DESATURATE);
207                                 break;
208                         default:
209                                 stop_signal = FALSE;
210                                 break;
211                         }
212                 }
213         else
214                 {
215                 stop_signal = TRUE;
216                 switch (event->keyval)
217                         {
218                         case '+': case '=': case GDK_KP_Add:
219                                 layout_image_zoom_adjust(lw, get_zoom_increment());
220                                 break;
221                         case '-': case GDK_KP_Subtract:
222                                 layout_image_zoom_adjust(lw, -get_zoom_increment());
223                                 break;
224                         case 'X': case 'x': case GDK_KP_Multiply:
225                                 layout_image_zoom_set(lw, 0.0);
226                                 break;
227                         case 'Z': case 'z': case GDK_KP_Divide:
228                         case '1':
229                                 layout_image_zoom_set(lw, 1.0);
230                                 break;
231                         case '2':
232                                 layout_image_zoom_set(lw, 2.0);
233                                 break;
234                         case '3':
235                                 layout_image_zoom_set(lw, 3.0);
236                                 break;
237                         case '4':
238                                 layout_image_zoom_set(lw, 4.0);
239                                 break;
240                         case '7':
241                                 layout_image_zoom_set(lw, -4.0);
242                                 break;
243                         case '8':
244                                 layout_image_zoom_set(lw, -3.0);
245                                 break;
246                         case '9':
247                                 layout_image_zoom_set(lw, -2.0);
248                                 break;
249                         case 'W': case 'w':
250                                 layout_image_zoom_set_fill_geometry(lw, FALSE);
251                                 break;
252                         case 'H': case 'h':
253                                 layout_image_zoom_set_fill_geometry(lw, TRUE);
254                                 break;
255                         case GDK_Page_Up: case GDK_KP_Page_Up:
256                         case GDK_BackSpace:
257                         case 'B': case 'b':
258                                 layout_image_prev(lw);
259                                 break;
260                         case GDK_Page_Down: case GDK_KP_Page_Down:
261                         case GDK_space:
262                         case 'N': case 'n':
263                                 layout_image_next(lw);
264                                 break;
265                         case GDK_Home: case GDK_KP_Home:
266                                 layout_image_first(lw);
267                                 break;
268                         case GDK_End: case GDK_KP_End:
269                                 layout_image_last(lw);
270                                 break;
271                         case ']':
272                                 layout_image_alter(lw, ALTER_ROTATE_90);
273                                 break;
274                         case '[':
275                                 layout_image_alter(lw, ALTER_ROTATE_90_CC);
276                                 break;
277                         case GDK_Delete: case GDK_KP_Delete:
278                                 if (enable_delete_key)
279                                         {
280                                         file_util_delete(layout_image_get_fd(lw), NULL, widget);
281                                         }
282                                 break;
283                         case GDK_Escape:
284                                 layout_image_full_screen_stop(lw);
285                                 break;
286                         case 'R': case 'r':
287                                 layout_refresh(lw);
288                                 break;
289                         case 'S': case 's':
290                                 layout_image_slideshow_toggle(lw);
291                                 break;
292                         case 'P': case 'p':
293                                 layout_image_slideshow_pause_toggle(lw);
294                                 break;
295                         case 'F': case 'f':
296                         case 'V': case 'v':
297                         case GDK_F11:
298                                 layout_image_full_screen_stop(lw);
299                                 break;
300                         case GDK_Menu:
301                         case GDK_F10:
302                                 layout_image_full_screen_menu_popup(lw);
303                                 break;
304                         case 'I': case 'i':
305                                 layout_image_overlay_toggle(lw);
306                                 break;
307                         default:
308                                 stop_signal = FALSE;
309                                 break;
310                         }
311                 }
312
313         return stop_signal;
314 }
315
316 #endif
317
318 static void layout_image_full_screen_stop_func(FullScreenData *fs, gpointer data)
319 {
320         LayoutWindow *lw = data;
321
322         /* restore image window */
323         lw->image = fs->normal_imd;
324
325         if (lw->slideshow)
326                 {
327                 lw->slideshow->imd = lw->image;
328                 }
329
330         lw->full_screen = NULL;
331 }
332
333 void layout_image_full_screen_start(LayoutWindow *lw)
334 {
335         if (!layout_valid(&lw)) return;
336
337         if (lw->full_screen) return;
338
339         lw->full_screen = fullscreen_start(lw->window, lw->image,
340                                            layout_image_full_screen_stop_func, lw);
341
342         /* set to new image window */
343         lw->image = lw->full_screen->imd;
344
345         if (lw->slideshow)
346                 {
347                 lw->slideshow->imd = lw->image;
348                 }
349
350         layout_image_set_buttons(lw);
351
352         g_signal_connect(G_OBJECT(lw->full_screen->window), "key_press_event",
353                          G_CALLBACK(layout_key_press_cb), lw);
354
355         layout_actions_add_window(lw, lw->full_screen->window);
356 #if 0
357         gtk_widget_set_sensitive(lw->window, FALSE);
358         if (lw->tools) gtk_widget_set_sensitive(lw->tools, FALSE);
359 #endif
360
361         if (image_osd_get(lw->full_screen->normal_imd, NULL, NULL))
362                 {
363                 image_osd_set(lw->image, TRUE, TRUE);
364                 image_osd_set(lw->full_screen->normal_imd, FALSE, FALSE);
365                 }
366 }
367
368 void layout_image_full_screen_stop(LayoutWindow *lw)
369 {
370         if (!layout_valid(&lw)) return;
371         if (!lw->full_screen) return;
372
373         if (image_osd_get(lw->image, NULL, NULL))
374                 {
375                 image_osd_set(lw->full_screen->normal_imd, FALSE, TRUE);
376                 }
377         fullscreen_stop(lw->full_screen);
378
379 #if 0
380         gtk_widget_set_sensitive(lw->window, TRUE);
381         if (lw->tools) gtk_widget_set_sensitive(lw->tools, TRUE);
382 #endif
383 }
384
385 void layout_image_full_screen_toggle(LayoutWindow *lw)
386 {
387         if (!layout_valid(&lw)) return;
388         if (lw->full_screen)
389                 {
390                 layout_image_full_screen_stop(lw);
391                 }
392         else
393                 {
394                 layout_image_full_screen_start(lw);
395                 }
396 }
397
398 gint layout_image_full_screen_active(LayoutWindow *lw)
399 {
400         if (!layout_valid(&lw)) return FALSE;
401
402         return (lw->full_screen != NULL);
403 }
404
405 /*
406  *----------------------------------------------------------------------------
407  * slideshow
408  *----------------------------------------------------------------------------
409  */
410
411 static void layout_image_slideshow_next(LayoutWindow *lw)
412 {
413         if (lw->slideshow) slideshow_next(lw->slideshow);
414 }
415
416 static void layout_image_slideshow_prev(LayoutWindow *lw)
417 {
418         if (lw->slideshow) slideshow_prev(lw->slideshow);
419 }
420
421 static void layout_image_slideshow_stop_func(SlideShowData *ss, gpointer data)
422 {
423         LayoutWindow *lw = data;
424
425         lw->slideshow = NULL;
426         layout_status_update_info(lw, NULL);
427 }
428
429 void layout_image_slideshow_start(LayoutWindow *lw)
430 {
431         CollectionData *cd;
432         CollectInfo *info;
433
434         if (!layout_valid(&lw)) return;
435         if (lw->slideshow) return;
436
437         cd = image_get_collection(lw->image, &info);
438
439         if (cd && info)
440                 {
441                 lw->slideshow = slideshow_start_from_collection(lw->image, cd,
442                                 layout_image_slideshow_stop_func, lw, info);
443                 }
444         else
445                 {
446                 lw->slideshow = slideshow_start(lw->image, lw,
447                                 layout_list_get_index(lw, layout_image_get_path(lw)),
448                                 layout_image_slideshow_stop_func, lw);
449                 }
450
451         layout_status_update_info(lw, NULL);
452 }
453
454 /* note that slideshow will take ownership of the list, do not free it */
455 void layout_image_slideshow_start_from_list(LayoutWindow *lw, GList *list)
456 {
457         if (!layout_valid(&lw)) return;
458
459         if (lw->slideshow || !list)
460                 {
461                 filelist_free(list);
462                 return;
463                 }
464
465         lw->slideshow = slideshow_start_from_filelist(lw->image, list,
466                                                        layout_image_slideshow_stop_func, lw);
467
468         layout_status_update_info(lw, NULL);
469 }
470
471 void layout_image_slideshow_stop(LayoutWindow *lw)
472 {
473         if (!layout_valid(&lw)) return;
474
475         if (!lw->slideshow) return;
476
477         slideshow_free(lw->slideshow);
478         /* the stop_func sets lw->slideshow to NULL for us */
479 }
480
481 void layout_image_slideshow_toggle(LayoutWindow *lw)
482 {
483         if (!layout_valid(&lw)) return;
484
485         if (lw->slideshow)
486                 {
487                 layout_image_slideshow_stop(lw);
488                 }
489         else
490                 {
491                 layout_image_slideshow_start(lw);
492                 }
493 }
494
495 gint layout_image_slideshow_active(LayoutWindow *lw)
496 {
497         if (!layout_valid(&lw)) return FALSE;
498
499         return (lw->slideshow != NULL);
500 }
501
502 gint layout_image_slideshow_pause_toggle(LayoutWindow *lw)
503 {
504         gint ret;
505
506         if (!layout_valid(&lw)) return FALSE;
507
508         ret = slideshow_pause_toggle(lw->slideshow);
509
510         layout_status_update_info(lw, NULL);
511
512         return ret;
513 }
514
515 gint layout_image_slideshow_paused(LayoutWindow *lw)
516 {
517         if (!layout_valid(&lw)) return FALSE;
518
519         return (slideshow_paused(lw->slideshow));
520 }
521
522 static gint layout_image_slideshow_continue_check(LayoutWindow *lw)
523 {
524         if (!lw->slideshow) return FALSE;
525
526         if (!slideshow_should_continue(lw->slideshow))
527                 {
528                 layout_image_slideshow_stop(lw);
529                 return FALSE;
530                 }
531
532         return TRUE;
533 }
534
535 /*
536  *----------------------------------------------------------------------------
537  * pop-up menus
538  *----------------------------------------------------------------------------
539  */
540
541 static void li_pop_menu_zoom_in_cb(GtkWidget *widget, gpointer data)
542 {
543         LayoutWindow *lw = data;
544
545         layout_image_zoom_adjust(lw, get_zoom_increment());
546 }
547
548 static void li_pop_menu_zoom_out_cb(GtkWidget *widget, gpointer data)
549 {
550         LayoutWindow *lw = data;
551         layout_image_zoom_adjust(lw, -get_zoom_increment());
552 }
553
554 static void li_pop_menu_zoom_1_1_cb(GtkWidget *widget, gpointer data)
555 {
556         LayoutWindow *lw = data;
557
558         layout_image_zoom_set(lw, 1.0);
559 }
560
561 static void li_pop_menu_zoom_fit_cb(GtkWidget *widget, gpointer data)
562 {
563         LayoutWindow *lw = data;
564
565         layout_image_zoom_set(lw, 0.0);
566 }
567
568 static void li_pop_menu_edit_cb(GtkWidget *widget, gpointer data)
569 {
570         LayoutWindow *lw;
571         gint n;
572
573         lw = submenu_item_get_data(widget);
574         n = GPOINTER_TO_INT(data);
575
576         if (!editor_window_flag_set(n))
577                 {
578                 layout_image_full_screen_stop(lw);
579                 }
580         start_editor_from_file(n, layout_image_get_fd(lw));
581 }
582
583 static void li_pop_menu_wallpaper_cb(GtkWidget *widget, gpointer data)
584 {
585         LayoutWindow *lw = data;
586
587         layout_image_to_root(lw);
588 }
589
590 static void li_pop_menu_alter_cb(GtkWidget *widget, gpointer data)
591 {
592         LayoutWindow *lw = data;
593         AlterType type;
594
595         lw = submenu_item_get_data(widget);
596         type = (AlterType)GPOINTER_TO_INT(data);
597
598         image_alter(lw->image, type);
599 }
600
601 static void li_pop_menu_info_cb(GtkWidget *widget, gpointer data)
602 {
603         LayoutWindow *lw = data;
604
605         info_window_new(layout_image_get_fd(lw), NULL, lw->full_screen ? lw->full_screen->window : NULL);
606 }
607
608 static void li_pop_menu_new_cb(GtkWidget *widget, gpointer data)
609 {
610         LayoutWindow *lw = data;
611
612         view_window_new(layout_image_get_fd(lw));
613 }
614
615 static GtkWidget *li_pop_menu_click_parent(GtkWidget *widget, LayoutWindow *lw)
616 {
617         GtkWidget *menu;
618         GtkWidget *parent;
619
620         menu = gtk_widget_get_toplevel(widget);
621         if (!menu) return NULL;
622
623         parent = g_object_get_data(G_OBJECT(menu), "click_parent");
624
625         if (!parent && lw->full_screen)
626                 {
627                 parent = lw->full_screen->imd->widget;
628                 }
629
630         return parent;
631 }
632
633 static void li_pop_menu_copy_cb(GtkWidget *widget, gpointer data)
634 {
635         LayoutWindow *lw = data;
636
637         file_util_copy(layout_image_get_fd(lw), NULL, NULL,
638                        li_pop_menu_click_parent(widget, lw));
639 }
640
641 static void li_pop_menu_copy_path_cb(GtkWidget *widget, gpointer data)
642 {
643         LayoutWindow *lw = data;
644
645         file_util_copy_path_to_clipboard(layout_image_get_fd(lw));
646 }
647
648 static void li_pop_menu_move_cb(GtkWidget *widget, gpointer data)
649 {
650         LayoutWindow *lw = data;
651
652         file_util_move(layout_image_get_fd(lw), NULL, NULL,
653                        li_pop_menu_click_parent(widget, lw));
654 }
655
656 static void li_pop_menu_rename_cb(GtkWidget *widget, gpointer data)
657 {
658         LayoutWindow *lw = data;
659
660         file_util_rename(layout_image_get_fd(lw), NULL,
661                          li_pop_menu_click_parent(widget, lw));
662 }
663
664 static void li_pop_menu_delete_cb(GtkWidget *widget, gpointer data)
665 {
666         LayoutWindow *lw = data;
667
668         file_util_delete(layout_image_get_fd(lw), NULL,
669                          li_pop_menu_click_parent(widget, lw));
670 }
671
672 static void li_pop_menu_slide_start_cb(GtkWidget *widget, gpointer data)
673 {
674         LayoutWindow *lw = data;
675
676         layout_image_slideshow_start(lw);
677 }
678
679 static void li_pop_menu_slide_stop_cb(GtkWidget *widget, gpointer data)
680 {
681         LayoutWindow *lw = data;
682
683         layout_image_slideshow_stop(lw);
684 }
685
686 static void li_pop_menu_slide_pause_cb(GtkWidget *widget, gpointer data)
687 {
688         LayoutWindow *lw = data;
689
690         layout_image_slideshow_pause_toggle(lw);
691 }
692
693 static void li_pop_menu_full_screen_cb(GtkWidget *widget, gpointer data)
694 {
695         LayoutWindow *lw = data;
696
697         layout_image_full_screen_toggle(lw);
698 }
699
700 static void li_pop_menu_hide_cb(GtkWidget *widget, gpointer data)
701 {
702         LayoutWindow *lw = data;
703
704         layout_tools_hide_toggle(lw);
705 }
706
707 static void li_set_layout_path_cb(GtkWidget *widget, gpointer data)
708 {
709         LayoutWindow *lw = data;
710         const gchar *path;
711
712         if (!layout_valid(&lw)) return;
713
714         path = layout_image_get_path(lw);
715         if (path) layout_set_path(lw, path);
716 }
717
718 static gint li_check_if_current_path(LayoutWindow *lw, const gchar *path)
719 {
720         gchar *dirname;
721         gint ret;
722
723         if (!path || !layout_valid(&lw) || !lw->path) return FALSE;
724
725         dirname = g_path_get_dirname(path);
726         ret = (strcmp(lw->path, dirname) == 0);
727         g_free(dirname);
728         return ret;
729 }
730
731 static GtkWidget *layout_image_pop_menu(LayoutWindow *lw)
732 {
733         GtkWidget *menu;
734         GtkWidget *item;
735         GtkWidget *submenu;
736         const gchar *path;
737         gint fullscreen;
738
739         path = layout_image_get_path(lw);
740         fullscreen = layout_image_full_screen_active(lw);
741
742         menu = popup_menu_short_lived();
743
744         menu_item_add_stock(menu, _("Zoom _in"), GTK_STOCK_ZOOM_IN, G_CALLBACK(li_pop_menu_zoom_in_cb), lw);
745         menu_item_add_stock(menu, _("Zoom _out"), GTK_STOCK_ZOOM_OUT, G_CALLBACK(li_pop_menu_zoom_out_cb), lw);
746         menu_item_add_stock(menu, _("Zoom _1:1"), GTK_STOCK_ZOOM_100, G_CALLBACK(li_pop_menu_zoom_1_1_cb), lw);
747         menu_item_add_stock(menu, _("Fit image to _window"), GTK_STOCK_ZOOM_FIT, G_CALLBACK(li_pop_menu_zoom_fit_cb), lw);
748         menu_item_add_divider(menu);
749
750         submenu = submenu_add_edit(menu, &item, G_CALLBACK(li_pop_menu_edit_cb), lw);
751         if (!path) gtk_widget_set_sensitive(item, FALSE);
752         menu_item_add_divider(submenu);
753         menu_item_add(submenu, _("Set as _wallpaper"), G_CALLBACK(li_pop_menu_wallpaper_cb), lw);
754
755         item = submenu_add_alter(menu, G_CALLBACK(li_pop_menu_alter_cb), lw);
756
757         item = menu_item_add_stock(menu, _("_Properties"), GTK_STOCK_PROPERTIES, G_CALLBACK(li_pop_menu_info_cb), lw);
758         if (!path) gtk_widget_set_sensitive(item, FALSE);
759
760         item = menu_item_add_stock(menu, _("View in _new window"), GTK_STOCK_NEW, G_CALLBACK(li_pop_menu_new_cb), lw);
761         if (!path || fullscreen) gtk_widget_set_sensitive(item, FALSE);
762
763         item = menu_item_add(menu, _("_Go to directory view"), G_CALLBACK(li_set_layout_path_cb), lw);
764         if (!path || li_check_if_current_path(lw, path)) gtk_widget_set_sensitive(item, FALSE);
765
766         menu_item_add_divider(menu);
767
768         item = menu_item_add_stock(menu, _("_Copy..."), GTK_STOCK_COPY, G_CALLBACK(li_pop_menu_copy_cb), lw);
769         if (!path) gtk_widget_set_sensitive(item, FALSE);
770         item = menu_item_add(menu, _("_Move..."), G_CALLBACK(li_pop_menu_move_cb), lw);
771         if (!path) gtk_widget_set_sensitive(item, FALSE);
772         item = menu_item_add(menu, _("_Rename..."), G_CALLBACK(li_pop_menu_rename_cb), lw);
773         if (!path) gtk_widget_set_sensitive(item, FALSE);
774         item = menu_item_add_stock(menu, _("_Delete..."), GTK_STOCK_DELETE, G_CALLBACK(li_pop_menu_delete_cb), lw);
775         if (!path) gtk_widget_set_sensitive(item, FALSE);
776         
777         if (options->show_copy_path)
778                 {
779                 item = menu_item_add(menu, _("_Copy path"), G_CALLBACK(li_pop_menu_copy_path_cb), lw);
780                 if (!path) gtk_widget_set_sensitive(item, FALSE);
781         }
782
783         menu_item_add_divider(menu);
784
785         if (layout_image_slideshow_active(lw))
786                 {
787                 menu_item_add(menu, _("_Stop slideshow"), G_CALLBACK(li_pop_menu_slide_stop_cb), lw);
788                 if (layout_image_slideshow_paused(lw))
789                         {
790                         item = menu_item_add(menu, _("Continue slides_how"),
791                                              G_CALLBACK(li_pop_menu_slide_pause_cb), lw);
792                         }
793                 else
794                         {
795                         item = menu_item_add(menu, _("Pause slides_how"),
796                                              G_CALLBACK(li_pop_menu_slide_pause_cb), lw);
797                         }
798                 }
799         else
800                 {
801                 menu_item_add(menu, _("_Start slideshow"), G_CALLBACK(li_pop_menu_slide_start_cb), lw);
802                 item = menu_item_add(menu, _("Pause slides_how"), G_CALLBACK(li_pop_menu_slide_pause_cb), lw);
803                 gtk_widget_set_sensitive(item, FALSE);
804                 }
805
806         if (!fullscreen)
807                 {
808                 menu_item_add(menu, _("_Full screen"), G_CALLBACK(li_pop_menu_full_screen_cb), lw);
809                 }
810         else
811                 {
812                 menu_item_add(menu, _("Exit _full screen"), G_CALLBACK(li_pop_menu_full_screen_cb), lw);
813                 }
814
815         menu_item_add_divider(menu);
816
817         item = menu_item_add_check(menu, _("Hide file _list"), lw->tools_hidden,
818                                    G_CALLBACK(li_pop_menu_hide_cb), lw);
819         if (fullscreen) gtk_widget_set_sensitive(item, FALSE);
820
821         return menu;
822 }
823
824 static void layout_image_menu_pos_cb(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer data)
825 {
826         LayoutWindow *lw = data;
827
828         gdk_window_get_origin(lw->image->pr->window, x, y);
829         popup_menu_position_clamp(menu, x, y, 0);
830 }
831
832 void layout_image_menu_popup(LayoutWindow *lw)
833 {
834         GtkWidget *menu;
835
836         menu = layout_image_pop_menu(lw);
837         gtk_menu_popup(GTK_MENU(menu), NULL, NULL, layout_image_menu_pos_cb, lw, 0, GDK_CURRENT_TIME);
838 }
839
840 /*
841  *----------------------------------------------------------------------------
842  * dnd
843  *----------------------------------------------------------------------------
844  */
845
846 static void layout_image_dnd_receive(GtkWidget *widget, GdkDragContext *context,
847                                      gint x, gint y,
848                                      GtkSelectionData *selection_data, guint info,
849                                      guint time, gpointer data)
850 {
851         LayoutWindow *lw = data;
852         gint i;
853
854
855         for (i = 0; i < MAX_SPLIT_IMAGES; i++)
856                 {
857                 if (lw->split_images[i] && lw->split_images[i]->pr == widget)
858                         break;
859                 }
860         if (i < MAX_SPLIT_IMAGES)
861                 {
862                 DEBUG_1("dnd image activate %d", i);
863                 layout_image_activate(lw, i);
864                 }
865
866
867         if (info == TARGET_URI_LIST || info == TARGET_APP_COLLECTION_MEMBER)
868                 {
869                 CollectionData *source;
870                 GList *list;
871                 GList *info_list;
872
873                 if (info == TARGET_URI_LIST)
874                         {
875                         list = uri_filelist_from_text((gchar *)selection_data->data, TRUE);
876                         source = NULL;
877                         info_list = NULL;
878                         }
879                 else
880                         {
881                         source = collection_from_dnd_data((gchar *)selection_data->data, &list, &info_list);
882                         }
883
884                 if (list)
885                         {
886                         FileData *fd = list->data;
887
888                         if (isfile(fd->path))
889                                 {
890                                 gchar *base;
891                                 gint row;
892
893                                 base = remove_level_from_path(fd->path);
894                                 if (strcmp(base, layout_get_path(lw)) != 0)
895                                         {
896                                         layout_set_path(lw, base);
897                                         }
898                                 g_free(base);
899
900                                 row = layout_list_get_index(lw, fd->path);
901                                 if (source && info_list)
902                                         {
903                                         layout_image_set_collection(lw, source, info_list->data);
904                                         }
905                                 else if (row == -1)
906                                         {
907                                         layout_image_set_fd(lw, fd);
908                                         }
909                                 else
910                                         {
911                                         layout_image_set_index(lw, row);
912                                         }
913                                 }
914                         else if (isdir(fd->path))
915                                 {
916                                 layout_set_path(lw, fd->path);
917                                 layout_image_set_fd(lw, NULL);
918                                 }
919                         }
920
921                 filelist_free(list);
922                 g_list_free(info_list);
923                 }
924 }
925
926 static void layout_image_dnd_get(GtkWidget *widget, GdkDragContext *context,
927                                  GtkSelectionData *selection_data, guint info,
928                                  guint time, gpointer data)
929 {
930         LayoutWindow *lw = data;
931         FileData *fd;
932         gint i;
933
934
935         for (i = 0; i < MAX_SPLIT_IMAGES; i++)
936                 {
937                 if (lw->split_images[i] && lw->split_images[i]->pr == widget)
938                         break;
939                 }
940         if (i < MAX_SPLIT_IMAGES)
941                 {
942                 DEBUG_1("dnd get from %d", i);
943                 fd = image_get_fd(lw->split_images[i]);
944                 }
945         else
946                 fd = layout_image_get_fd(lw);
947
948         if (fd)
949                 {
950                 gchar *text = NULL;
951                 gint len;
952                 gint plain_text;
953                 GList *list;
954
955                 switch (info)
956                         {
957                         case TARGET_URI_LIST:
958                                 plain_text = FALSE;
959                                 break;
960                         case TARGET_TEXT_PLAIN:
961                         default:
962                                 plain_text = TRUE;
963                                 break;
964                         }
965                 list = g_list_append(NULL, fd);
966                 text = uri_text_from_filelist(list, &len, plain_text);
967                 g_list_free(list);
968                 if (text)
969                         {
970                         gtk_selection_data_set(selection_data, selection_data->target,
971                                                8, (guchar *)text, len);
972                         g_free(text);
973                         }
974                 }
975         else
976                 {
977                 gtk_selection_data_set(selection_data, selection_data->target,
978                                        8, NULL, 0);
979                 }
980 }
981
982 static void layout_image_dnd_end(GtkWidget *widget, GdkDragContext *context, gpointer data)
983 {
984         LayoutWindow *lw = data;
985         if (context->action == GDK_ACTION_MOVE)
986                 {
987                 const gchar *path;
988                 gint row;
989
990                 path = layout_image_get_path(lw);
991                 row = layout_list_get_index(lw, path);
992                 if (row < 0) return;
993
994                 if (!isfile(path))
995                         {
996                         if (row < layout_list_count(lw, NULL) - 1)
997                                 {
998                                 layout_image_next(lw);
999                                 }
1000                         else
1001                                 {
1002                                 layout_image_prev(lw);
1003                                 }
1004                         }
1005                 layout_refresh(lw);
1006                 }
1007 }
1008
1009 static void layout_image_dnd_init(LayoutWindow *lw, gint i)
1010 {
1011         ImageWindow *imd = lw->split_images[i];
1012
1013         gtk_drag_source_set(imd->pr, GDK_BUTTON2_MASK,
1014                             dnd_file_drag_types, dnd_file_drag_types_count,
1015                             GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
1016         g_signal_connect(G_OBJECT(imd->pr), "drag_data_get",
1017                          G_CALLBACK(layout_image_dnd_get), lw);
1018         g_signal_connect(G_OBJECT(imd->pr), "drag_end",
1019                          G_CALLBACK(layout_image_dnd_end), lw);
1020
1021         gtk_drag_dest_set(imd->pr,
1022                           GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP,
1023                           dnd_file_drop_types, dnd_file_drop_types_count,
1024                           GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
1025         g_signal_connect(G_OBJECT(imd->pr), "drag_data_received",
1026                          G_CALLBACK(layout_image_dnd_receive), lw);
1027 }
1028
1029
1030 /*
1031  *----------------------------------------------------------------------------
1032  * misc
1033  *----------------------------------------------------------------------------
1034  */
1035
1036 void layout_image_to_root(LayoutWindow *lw)
1037 {
1038         image_to_root_window(lw->image, (image_zoom_get(lw->image) == 0));
1039 }
1040
1041 /*
1042  *----------------------------------------------------------------------------
1043  * manipulation + accessors
1044  *----------------------------------------------------------------------------
1045  */
1046
1047 void layout_image_scroll(LayoutWindow *lw, gint x, gint y)
1048 {
1049         gdouble dx, dy;
1050         gint width, height, i;
1051         if (!layout_valid(&lw)) return;
1052
1053         image_scroll(lw->image, x, y);
1054
1055         image_get_image_size(lw->image, &width, &height);
1056         dx = (gdouble) x / width;
1057         dy = (gdouble) y / height;
1058         
1059         for (i = 0; i < MAX_SPLIT_IMAGES; i++)
1060                 {
1061                 if (lw->split_images[i] && lw->split_images[i] != lw->image && lw->connect_scroll)
1062                         {
1063                         gdouble sx, sy;
1064                         image_get_scroll_center(lw->split_images[i], &sx, &sy);
1065                         sx += dx;
1066                         sy += dy;
1067                         image_set_scroll_center(lw->split_images[i], sx, sy);
1068                         }
1069                 }
1070
1071 }
1072
1073 void layout_image_zoom_adjust(LayoutWindow *lw, gdouble increment)
1074 {
1075         gint i;
1076         if (!layout_valid(&lw)) return;
1077
1078         image_zoom_adjust(lw->image, increment);
1079
1080         for (i = 0; i < MAX_SPLIT_IMAGES; i++)
1081                 {
1082                 if (lw->split_images[i] && lw->split_images[i] != lw->image && lw->connect_zoom)
1083                         image_zoom_adjust(lw->split_images[i], increment); ;
1084                 }
1085 }
1086
1087 void layout_image_zoom_adjust_at_point(LayoutWindow *lw, gdouble increment, gint x, gint y)
1088 {
1089         gint i;
1090         if (!layout_valid(&lw)) return;
1091
1092         image_zoom_adjust_at_point(lw->image, increment, x, y);
1093
1094         for (i = 0; i < MAX_SPLIT_IMAGES; i++)
1095                 {
1096                 if (lw->split_images[i] && lw->split_images[i] != lw->image && lw->connect_zoom)
1097                         image_zoom_adjust_at_point(lw->split_images[i], increment, x, y);
1098                 }
1099 }
1100
1101 void layout_image_zoom_set(LayoutWindow *lw, gdouble zoom)
1102 {
1103         gint i;
1104         if (!layout_valid(&lw)) return;
1105
1106         image_zoom_set(lw->image, zoom);
1107
1108         for (i=0; i < MAX_SPLIT_IMAGES; i++)
1109                 {
1110                 if (lw->split_images[i] && lw->split_images[i] != lw->image && lw->connect_zoom)
1111                         image_zoom_set(lw->split_images[i], zoom);
1112                 }
1113 }
1114
1115 void layout_image_zoom_set_fill_geometry(LayoutWindow *lw, gint vertical)
1116 {
1117         if (!layout_valid(&lw)) return;
1118
1119         image_zoom_set_fill_geometry(lw->image, vertical);
1120 }
1121
1122 void layout_image_alter(LayoutWindow *lw, AlterType type)
1123 {
1124         if (!layout_valid(&lw)) return;
1125
1126         image_alter(lw->image, type);
1127 }
1128
1129 const gchar *layout_image_get_path(LayoutWindow *lw)
1130 {
1131         if (!layout_valid(&lw)) return NULL;
1132
1133         return image_get_path(lw->image);
1134 }
1135
1136 const gchar *layout_image_get_name(LayoutWindow *lw)
1137 {
1138         if (!layout_valid(&lw)) return NULL;
1139
1140         return image_get_name(lw->image);
1141 }
1142
1143 FileData *layout_image_get_fd(LayoutWindow *lw)
1144 {
1145         if (!layout_valid(&lw)) return NULL;
1146
1147         return image_get_fd(lw->image);
1148 }
1149
1150 CollectionData *layout_image_get_collection(LayoutWindow *lw, CollectInfo **info)
1151 {
1152         if (!layout_valid(&lw)) return NULL;
1153
1154         return image_get_collection(lw->image, info);
1155 }
1156
1157 gint layout_image_get_index(LayoutWindow *lw)
1158 {
1159         return layout_list_get_index(lw, image_get_path(lw->image));
1160 }
1161
1162 /*
1163  *----------------------------------------------------------------------------
1164  * image changers
1165  *----------------------------------------------------------------------------
1166  */
1167
1168 void layout_image_set_fd(LayoutWindow *lw, FileData *fd)
1169 {
1170         gdouble sx, sy;
1171         if (!layout_valid(&lw)) return;
1172
1173         image_get_scroll_center(lw->image, &sx, &sy);
1174
1175         image_change_fd(lw->image, fd, image_zoom_get_default(lw->image, options->image.zoom_mode));
1176
1177         image_set_scroll_center(lw->image, sx, sy);
1178
1179         layout_list_sync_fd(lw, fd);
1180         layout_image_slideshow_continue_check(lw);
1181         layout_bars_new_image(lw);
1182 }
1183
1184 void layout_image_set_with_ahead(LayoutWindow *lw, FileData *fd, FileData *read_ahead_fd)
1185 {
1186         if (!layout_valid(&lw)) return;
1187
1188 /*
1189 This should be handled at the caller: in vflist_select_image
1190         if (path)
1191                 {
1192                 const gchar *old_path;
1193
1194                 old_path = layout_image_get_path(lw);
1195                 if (old_path && strcmp(path, old_path) == 0) return;
1196                 }
1197 */
1198         layout_image_set_fd(lw, fd);
1199         if (options->image.enable_read_ahead) image_prebuffer_set(lw->image, read_ahead_fd);
1200 }
1201
1202 void layout_image_set_index(LayoutWindow *lw, gint index)
1203 {
1204         FileData *fd;
1205         FileData *read_ahead_fd;
1206         gint old;
1207
1208         if (!layout_valid(&lw)) return;
1209
1210         old = layout_list_get_index(lw, layout_image_get_path(lw));
1211         fd = layout_list_get_fd(lw, index);
1212
1213         if (old > index)
1214                 {
1215                 read_ahead_fd = layout_list_get_fd(lw, index - 1);
1216                 }
1217         else
1218                 {
1219                 read_ahead_fd = layout_list_get_fd(lw, index + 1);
1220                 }
1221
1222         if (layout_selection_count(lw, 0) > 1)
1223                 {
1224                 GList *x = layout_selection_list_by_index(lw);
1225                 GList *y;
1226                 GList *last;
1227
1228                 for (last = y = x; y; y = y->next)
1229                         last = y;
1230                 for (y = x; y && (GPOINTER_TO_INT(y->data)) != index; y = y->next)
1231                         ;
1232
1233                 if (y)
1234                         {
1235                         gint newindex;
1236
1237                         if ((index > old && (index != GPOINTER_TO_INT(last->data) || old != GPOINTER_TO_INT(x->data)))
1238                             || (old == GPOINTER_TO_INT(last->data) && index == GPOINTER_TO_INT(x->data)))
1239                                 {
1240                                 if (y->next)
1241                                         newindex = GPOINTER_TO_INT(y->next->data);
1242                                 else
1243                                         newindex = GPOINTER_TO_INT(x->data);
1244                                 }
1245                         else
1246                                 {
1247                                 if (y->prev)
1248                                         newindex = GPOINTER_TO_INT(y->prev->data);
1249                                 else
1250                                         newindex = GPOINTER_TO_INT(last->data);
1251                                 }
1252
1253                         read_ahead_fd = layout_list_get_fd(lw, newindex);
1254                         }
1255
1256                 while (x)
1257                         x = g_list_remove(x, x->data);
1258                 }
1259
1260         layout_image_set_with_ahead(lw, fd, read_ahead_fd);
1261 }
1262
1263 static void layout_image_set_collection_real(LayoutWindow *lw, CollectionData *cd, CollectInfo *info, gint forward)
1264 {
1265         if (!layout_valid(&lw)) return;
1266
1267         image_change_from_collection(lw->image, cd, info, image_zoom_get_default(lw->image, options->image.zoom_mode));
1268         if (options->image.enable_read_ahead)
1269                 {
1270                 CollectInfo *r_info;
1271                 if (forward)
1272                         {
1273                         r_info = collection_next_by_info(cd, info);
1274                         if (!r_info) r_info = collection_prev_by_info(cd, info);
1275                         }
1276                 else
1277                         {
1278                         r_info = collection_prev_by_info(cd, info);
1279                         if (!r_info) r_info = collection_next_by_info(cd, info);
1280                         }
1281                 if (r_info) image_prebuffer_set(lw->image, r_info->fd);
1282                 }
1283
1284         layout_image_slideshow_continue_check(lw);
1285         layout_bars_new_image(lw);
1286 }
1287
1288 void layout_image_set_collection(LayoutWindow *lw, CollectionData *cd, CollectInfo *info)
1289 {
1290         layout_image_set_collection_real(lw, cd, info, TRUE);
1291         layout_list_sync_fd(lw, layout_image_get_fd(lw));
1292 }
1293
1294 void layout_image_refresh(LayoutWindow *lw)
1295 {
1296         if (!layout_valid(&lw)) return;
1297
1298         image_reload(lw->image);
1299 }
1300
1301 void layout_image_color_profile_set(LayoutWindow *lw,
1302                                     gint input_type, gint screen_type,
1303                                     gint use_image)
1304 {
1305         if (!layout_valid(&lw)) return;
1306
1307         image_color_profile_set(lw->image, input_type, screen_type, use_image);
1308 }
1309
1310 gint layout_image_color_profile_get(LayoutWindow *lw,
1311                                     gint *input_type, gint *screen_type,
1312                                     gint *use_image)
1313 {
1314         if (!layout_valid(&lw)) return FALSE;
1315
1316         return image_color_profile_get(lw->image, input_type, screen_type, use_image);
1317 }
1318
1319 void layout_image_color_profile_set_use(LayoutWindow *lw, gint enable)
1320 {
1321         if (!layout_valid(&lw)) return;
1322
1323         image_color_profile_set_use(lw->image, enable);
1324
1325         if (lw->info_color)
1326                 {
1327 #ifndef HAVE_LCMS
1328                 enable = FALSE;
1329 #endif
1330                 gtk_widget_set_sensitive(GTK_BIN(lw->info_color)->child, enable);
1331                 }
1332 }
1333
1334 gint layout_image_color_profile_get_use(LayoutWindow *lw)
1335 {
1336         if (!layout_valid(&lw)) return FALSE;
1337
1338         return image_color_profile_get_use(lw->image);
1339 }
1340
1341 gint layout_image_color_profile_get_from_image(LayoutWindow *lw)
1342 {
1343         if (!layout_valid(&lw)) return FALSE;
1344
1345         return image_color_profile_get_from_image(lw->image);
1346 }
1347
1348 /*
1349  *----------------------------------------------------------------------------
1350  * list walkers
1351  *----------------------------------------------------------------------------
1352  */
1353
1354 void layout_image_next(LayoutWindow *lw)
1355 {
1356         gint current;
1357         CollectionData *cd;
1358         CollectInfo *info;
1359
1360         if (!layout_valid(&lw)) return;
1361
1362         if (layout_image_slideshow_active(lw))
1363                 {
1364                 layout_image_slideshow_next(lw);
1365                 return;
1366                 }
1367
1368         if (layout_selection_count(lw, 0) > 1)
1369                 {
1370                 GList *x = layout_selection_list_by_index(lw);
1371                 gint old = layout_list_get_index(lw, layout_image_get_path(lw));
1372                 GList *y;
1373
1374                 for (y = x; y && (GPOINTER_TO_INT(y->data)) != old; y = y->next)
1375                         ;
1376                 if (y)
1377                         {
1378                         if (y->next)
1379                                 layout_image_set_index(lw, GPOINTER_TO_INT(y->next->data));
1380                         else
1381                                 layout_image_set_index(lw, GPOINTER_TO_INT(x->data));
1382                         }
1383                 while (x)
1384                         x = g_list_remove(x, x->data);
1385                 if (y) /* not dereferenced */
1386                         return;
1387                 }
1388
1389         cd = image_get_collection(lw->image, &info);
1390
1391         if (cd && info)
1392                 {
1393                 info = collection_next_by_info(cd, info);
1394                 if (info)
1395                         {
1396                         layout_image_set_collection_real(lw, cd, info, TRUE);
1397                         }
1398                 else
1399                         {
1400                         image_osd_icon(lw->image, IMAGE_OSD_LAST, -1);
1401                         }
1402                 return;
1403                 }
1404
1405         current = layout_image_get_index(lw);
1406
1407         if (current >= 0)
1408                 {
1409                 if (current < layout_list_count(lw, NULL) - 1)
1410                         {
1411                         layout_image_set_index(lw, current + 1);
1412                         }
1413                 else
1414                         {
1415                         image_osd_icon(lw->image, IMAGE_OSD_LAST, -1);
1416                         }
1417                 }
1418         else
1419                 {
1420                 layout_image_set_index(lw, 0);
1421                 }
1422 }
1423
1424 void layout_image_prev(LayoutWindow *lw)
1425 {
1426         gint current;
1427         CollectionData *cd;
1428         CollectInfo *info;
1429
1430         if (!layout_valid(&lw)) return;
1431
1432         if (layout_image_slideshow_active(lw))
1433                 {
1434                 layout_image_slideshow_prev(lw);
1435                 return;
1436                 }
1437
1438         if (layout_selection_count(lw, 0) > 1)
1439                 {
1440                 GList *x = layout_selection_list_by_index(lw);
1441                 gint old = layout_list_get_index(lw, layout_image_get_path(lw));
1442                 GList *y;
1443                 GList *last;
1444
1445                 for (last = y = x; y; y = y->next)
1446                         last = y;
1447                 for (y = x; y && (GPOINTER_TO_INT(y->data)) != old; y = y->next)
1448                         ;
1449                 if (y)
1450                         {
1451                         if (y->prev)
1452                                 layout_image_set_index(lw, GPOINTER_TO_INT(y->prev->data));
1453                         else
1454                                 layout_image_set_index(lw, GPOINTER_TO_INT(last->data));
1455                         }
1456                 while (x)
1457                         x = g_list_remove(x, x->data);
1458                 if (y) /* not dereferenced */
1459                         return;
1460                 }
1461
1462         cd = image_get_collection(lw->image, &info);
1463
1464         if (cd && info)
1465                 {
1466                 info = collection_prev_by_info(cd, info);
1467                 if (info)
1468                         {
1469                         layout_image_set_collection_real(lw, cd, info, FALSE);
1470                         }
1471                 else
1472                         {
1473                         image_osd_icon(lw->image, IMAGE_OSD_FIRST, -1);
1474                         }
1475                 return;
1476                 }
1477
1478         current = layout_image_get_index(lw);
1479
1480         if (current >= 0)
1481                 {
1482                 if (current > 0)
1483                         {
1484                         layout_image_set_index(lw, current - 1);
1485                         }
1486                 else
1487                         {
1488                         image_osd_icon(lw->image, IMAGE_OSD_FIRST, -1);
1489                         }
1490                 }
1491         else
1492                 {
1493                 layout_image_set_index(lw, layout_list_count(lw, NULL) - 1);
1494                 }
1495 }
1496
1497 void layout_image_first(LayoutWindow *lw)
1498 {
1499         gint current;
1500         CollectionData *cd;
1501         CollectInfo *info;
1502
1503         if (!layout_valid(&lw)) return;
1504
1505         cd = image_get_collection(lw->image, &info);
1506
1507         if (cd && info)
1508                 {
1509                 CollectInfo *new;
1510                 new = collection_get_first(cd);
1511                 if (new != info) layout_image_set_collection_real(lw, cd, new, TRUE);
1512                 return;
1513                 }
1514
1515         current = layout_image_get_index(lw);
1516         if (current != 0 && layout_list_count(lw, NULL) > 0)
1517                 {
1518                 layout_image_set_index(lw, 0);
1519                 }
1520 }
1521
1522 void layout_image_last(LayoutWindow *lw)
1523 {
1524         gint current;
1525         gint count;
1526         CollectionData *cd;
1527         CollectInfo *info;
1528
1529         if (!layout_valid(&lw)) return;
1530
1531         cd = image_get_collection(lw->image, &info);
1532
1533         if (cd && info)
1534                 {
1535                 CollectInfo *new;
1536                 new = collection_get_last(cd);
1537                 if (new != info) layout_image_set_collection_real(lw, cd, new, FALSE);
1538                 return;
1539                 }
1540
1541         current = layout_image_get_index(lw);
1542         count = layout_list_count(lw, NULL);
1543         if (current != count - 1 && count > 0)
1544                 {
1545                 layout_image_set_index(lw, count - 1);
1546                 }
1547 }
1548
1549 /*
1550  *----------------------------------------------------------------------------
1551  * mouse callbacks
1552  *----------------------------------------------------------------------------
1553  */
1554
1555 static gint image_idx(LayoutWindow *lw, ImageWindow *imd)
1556 {
1557         gint i;
1558
1559         for (i = 0; i < MAX_SPLIT_IMAGES; i++)
1560                 {
1561                 if (lw->split_images[i] == imd)
1562                         break;
1563                 }
1564         if (i < MAX_SPLIT_IMAGES)
1565                 {
1566                 return i;
1567                 }
1568         return -1;
1569 }
1570
1571
1572 static void layout_image_button_cb(ImageWindow *imd, gint button, guint32 time,
1573                                    gdouble x, gdouble y, guint state, gpointer data)
1574 {
1575         LayoutWindow *lw = data;
1576         GtkWidget *menu;
1577
1578         switch (button)
1579                 {
1580                 case MOUSE_BUTTON_LEFT:
1581                         layout_image_next(lw);
1582                         break;
1583                 case MOUSE_BUTTON_MIDDLE:
1584                         layout_image_prev(lw);
1585                         break;
1586                 case MOUSE_BUTTON_RIGHT:
1587                         menu = layout_image_pop_menu(lw);
1588                         if (imd == lw->image)
1589                                 {
1590                                 g_object_set_data(G_OBJECT(menu), "click_parent", imd->widget);
1591                                 }
1592                         gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 3, time);
1593                         break;
1594                 default:
1595                         break;
1596                 }
1597 }
1598
1599 static void layout_image_scroll_cb(ImageWindow *imd, GdkScrollDirection direction, guint32 time,
1600                                    gdouble x, gdouble y, guint state, gpointer data)
1601 {
1602         LayoutWindow *lw = data;
1603
1604         gint i = image_idx(lw, imd);
1605
1606         if (i != -1)
1607                 {
1608                 DEBUG_1("image activate scroll %d", i);
1609                 layout_image_activate(lw, i);
1610                 }
1611
1612
1613         if (state & GDK_CONTROL_MASK)
1614                 {
1615                 switch (direction)
1616                         {
1617                         case GDK_SCROLL_UP:
1618                                 layout_image_zoom_adjust_at_point(lw, get_zoom_increment(), x, y);
1619                                 break;
1620                         case GDK_SCROLL_DOWN:
1621                                 layout_image_zoom_adjust_at_point(lw, -get_zoom_increment(), x, y);
1622                                 break;
1623                         default:
1624                                 break;
1625                         }
1626                 }
1627         else if ( (state & GDK_SHIFT_MASK) != (options->mousewheel_scrolls))
1628                 {
1629                 switch (direction)
1630                         {
1631                         case GDK_SCROLL_UP:
1632                                 image_scroll(imd, 0, -MOUSEWHEEL_SCROLL_SIZE);
1633                                 break;
1634                         case GDK_SCROLL_DOWN:
1635                                 image_scroll(imd, 0, MOUSEWHEEL_SCROLL_SIZE);
1636                                 break;
1637                         case GDK_SCROLL_LEFT:
1638                                 image_scroll(imd, -MOUSEWHEEL_SCROLL_SIZE, 0);
1639                                 break;
1640                         case GDK_SCROLL_RIGHT:
1641                                 image_scroll(imd, MOUSEWHEEL_SCROLL_SIZE, 0);
1642                                 break;
1643                         default:
1644                                 break;
1645                         }
1646                 }
1647         else
1648                 {
1649                 switch (direction)
1650                         {
1651                         case GDK_SCROLL_UP:
1652                                 layout_image_prev(lw);
1653                                 break;
1654                         case GDK_SCROLL_DOWN:
1655                                 layout_image_next(lw);
1656                                 break;
1657                         default:
1658                                 break;
1659                         }
1660                 }
1661 }
1662
1663 static void layout_image_drag_cb(ImageWindow *imd, gint button, guint32 time,
1664                                  gdouble x, gdouble y, guint state, gdouble dx, gdouble dy, gpointer data)
1665 {
1666         gint i;
1667         LayoutWindow *lw = data;
1668
1669
1670         for (i=0; i < MAX_SPLIT_IMAGES; i++)
1671                 {
1672                 if (lw->split_images[i] && lw->split_images[i] != imd)
1673                         if (lw->connect_scroll)
1674                                 {
1675                                 gdouble sx, sy;
1676                                 if (state & GDK_CONTROL_MASK)
1677                                         {
1678                                         image_get_scroll_center(imd, &sx, &sy);
1679                                         }
1680                                 else
1681                                         {
1682                                         image_get_scroll_center(lw->split_images[i], &sx, &sy);
1683                                         sx += dx;
1684                                         sy += dy;
1685                                         }
1686                                 image_set_scroll_center(lw->split_images[i], sx, sy);
1687                                 }
1688                 }
1689 }
1690
1691 static void layout_image_button_inactive_cb(ImageWindow *imd, gint button, guint32 time,
1692                                    gdouble x, gdouble y, guint state, gpointer data)
1693 {
1694         LayoutWindow *lw = data;
1695         GtkWidget *menu;
1696         gint i = image_idx(lw, imd);
1697
1698         if (i != -1)
1699                 {
1700                 layout_image_activate(lw, i);
1701                 }
1702
1703         switch (button)
1704                 {
1705                 case MOUSE_BUTTON_RIGHT:
1706                         menu = layout_image_pop_menu(lw);
1707                         if (imd == lw->image)
1708                                 {
1709                                 g_object_set_data(G_OBJECT(menu), "click_parent", imd->widget);
1710                                 }
1711                         gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 3, time);
1712                         break;
1713                 default:
1714                         break;
1715                 }
1716
1717 }
1718
1719 static void layout_image_drag_inactive_cb(ImageWindow *imd, gint button, guint32 time,
1720                                  gdouble x, gdouble y, guint state, gdouble dx, gdouble dy, gpointer data)
1721 {
1722         LayoutWindow *lw = data;
1723
1724         gint i = image_idx(lw, imd);
1725
1726         if (i != -1)
1727                 {
1728                 layout_image_activate(lw, i);
1729                 }
1730
1731
1732         /* continue as with active image */
1733         layout_image_drag_cb(imd, button, time, x, y, state, dx, dy, data);
1734 }
1735
1736
1737 static void layout_image_set_buttons(LayoutWindow *lw)
1738 {
1739         image_set_button_func(lw->image, layout_image_button_cb, lw);
1740         image_set_scroll_func(lw->image, layout_image_scroll_cb, lw);
1741 }
1742
1743 static void layout_image_set_buttons_inactive(LayoutWindow *lw, gint i)
1744 {
1745         image_set_button_func(lw->split_images[i], layout_image_button_inactive_cb, lw);
1746         image_set_scroll_func(lw->split_images[i], layout_image_scroll_cb, lw);
1747 }
1748
1749 /*
1750  *----------------------------------------------------------------------------
1751  * setup
1752  *----------------------------------------------------------------------------
1753  */
1754
1755 static void layout_image_update_cb(ImageWindow *imd, gpointer data)
1756 {
1757         LayoutWindow *lw = data;
1758         layout_status_update_image(lw);
1759 }
1760
1761 GtkWidget *layout_image_new(LayoutWindow *lw, gint i)
1762 {
1763         if (!lw->split_images[i])
1764                 {
1765                 lw->split_images[i] = image_new(TRUE);
1766
1767                 gtk_widget_ref(lw->split_images[i]->widget);
1768
1769                 image_background_set_color(lw->split_images[i], options->image.use_custom_border_color ? &options->image.border_color : NULL);
1770
1771                 image_auto_refresh(lw->split_images[i], 0);
1772
1773                 layout_image_dnd_init(lw, i);
1774                 image_color_profile_set(lw->split_images[i],
1775                                         options->color_profile.input_type,
1776                                         options->color_profile.screen_type,
1777                                         options->color_profile.use_image);
1778                 image_color_profile_set_use(lw->split_images[i], options->color_profile.enabled);
1779                 }
1780
1781         return lw->split_images[i]->widget;
1782 }
1783
1784 void layout_image_deactivate(LayoutWindow *lw, gint i)
1785 {
1786
1787         if (!lw->split_images[i]) return;
1788         image_set_update_func(lw->split_images[i], NULL, NULL);
1789         layout_image_set_buttons_inactive(lw, i);
1790         image_set_drag_func(lw->split_images[i], layout_image_drag_inactive_cb, lw);
1791
1792         image_attach_window(lw->split_images[i], NULL, NULL, NULL, FALSE);
1793         image_select(lw->split_images[i], FALSE);
1794 }
1795
1796
1797 void layout_image_activate(LayoutWindow *lw, gint i)
1798 {
1799         FileData *fd;
1800
1801         if (!lw->split_images[i]) return;
1802
1803         /* deactivate currently active */
1804         if (lw->active_split_image != i)
1805                 layout_image_deactivate(lw, lw->active_split_image);
1806
1807         lw->image = lw->split_images[i];
1808         lw->active_split_image = i;
1809
1810         image_set_update_func(lw->image, layout_image_update_cb, lw);
1811         layout_image_set_buttons(lw);
1812         image_set_drag_func(lw->image, layout_image_drag_cb, lw);
1813
1814         image_attach_window(lw->image, lw->window, NULL, GQ_APPNAME, FALSE);
1815
1816         /* do not hilight selected image in SPLIT_NONE */
1817         /* maybe the image should be selected always and hilight should be controled by
1818            another image option */
1819         if (lw->split_mode != SPLIT_NONE)
1820                 image_select(lw->split_images[i], TRUE);
1821         else
1822                 image_select(lw->split_images[i], FALSE);
1823
1824         fd = image_get_fd(lw->image);
1825
1826         if (fd)
1827                 {
1828 //              layout_list_sync_path(lw, path);
1829                 layout_set_path(lw, fd->path);
1830                 }
1831 }
1832
1833
1834 GtkWidget *layout_image_setup_split_none(LayoutWindow *lw)
1835 {
1836         gint i;
1837
1838         lw->split_mode = SPLIT_NONE;
1839
1840         if (!lw->split_images[0])
1841                 {
1842                 layout_image_new(lw, 0);
1843                 image_set_frame(lw->split_images[0], (!lw->tools_float && !lw->tools_hidden));
1844                 image_set_selectable(lw->split_images[0], 0);
1845                 layout_image_activate(lw, 0);
1846                 }
1847         else
1848                 {
1849                 image_set_frame(lw->split_images[0], (!lw->tools_float && !lw->tools_hidden));
1850                 image_set_selectable(lw->split_images[0], 0);
1851                 }
1852
1853         for (i = 1; i < MAX_SPLIT_IMAGES; i++)
1854                 {
1855                 if (lw->split_images[i])
1856                         {
1857                         gtk_widget_unref(lw->split_images[i]->widget);
1858                         lw->split_images[i] = NULL;
1859                         }
1860                 }
1861
1862
1863         layout_image_activate(lw, 0);
1864
1865         lw->split_image_widget = lw->split_images[0]->widget;
1866
1867         return lw->split_image_widget;
1868 }
1869
1870 GtkWidget *layout_image_setup_split_hv(LayoutWindow *lw, gboolean horizontal)
1871 {
1872         GtkWidget *paned;
1873         gint i;
1874
1875         lw->split_mode = horizontal ? SPLIT_HOR : SPLIT_VERT;
1876
1877         if (!lw->split_images[0])
1878                 {
1879                 layout_image_new(lw, 0);
1880                 }
1881         image_set_frame(lw->split_images[0], 1);
1882         image_set_selectable(lw->split_images[0], 1);
1883
1884         if (!lw->split_images[1])
1885                 {
1886                 layout_image_new(lw, 1);
1887                 image_set_frame(lw->split_images[1], 1);
1888                 image_set_selectable(lw->split_images[1], 1);
1889                 if (lw->image)
1890                         {
1891                         gdouble sx, sy;
1892                         image_change_fd(lw->split_images[1],
1893                                         image_get_fd(lw->image), image_zoom_get(lw->image));
1894                         image_get_scroll_center(lw->image, &sx, &sy);
1895                         image_set_scroll_center(lw->split_images[1], sx, sy);
1896                         }
1897                 layout_image_deactivate(lw, 1);
1898                 layout_image_activate(lw, 0);
1899                 }
1900         else
1901                 {
1902                 image_set_frame(lw->split_images[1], 1);
1903                 image_set_selectable(lw->split_images[1], 1);
1904                 }
1905
1906
1907         for (i = 2; i < MAX_SPLIT_IMAGES; i++)
1908                 {
1909                 if (lw->split_images[i])
1910                         {
1911                         gtk_widget_unref(lw->split_images[i]->widget);
1912                         lw->split_images[i] = NULL;
1913                         }
1914                 }
1915
1916         if (!lw->image || lw->active_split_image < 0 || lw->active_split_image > 1)
1917                 {
1918                 layout_image_activate(lw, 0);
1919                 }
1920
1921         /* horizontal split means vpaned and vice versa */
1922         if (horizontal)
1923                 paned = gtk_vpaned_new();
1924         else
1925                 paned = gtk_hpaned_new();
1926
1927         gtk_paned_pack1(GTK_PANED(paned), lw->split_images[0]->widget, TRUE, TRUE);
1928         gtk_paned_pack2(GTK_PANED(paned), lw->split_images[1]->widget, TRUE, TRUE);
1929
1930         gtk_widget_show(lw->split_images[0]->widget);
1931         gtk_widget_show(lw->split_images[1]->widget);
1932
1933
1934         lw->split_image_widget = paned;
1935
1936         return lw->split_image_widget;
1937
1938 }
1939
1940 GtkWidget *layout_image_setup_split_quad(LayoutWindow *lw)
1941 {
1942         GtkWidget *hpaned;
1943         GtkWidget *vpaned1;
1944         GtkWidget *vpaned2;
1945         gint i;
1946
1947         lw->split_mode = SPLIT_QUAD;
1948
1949         if (!lw->split_images[0])
1950                 {
1951                 layout_image_new(lw, 0);
1952                 }
1953
1954         image_set_frame(lw->split_images[0], 1);
1955         image_set_selectable(lw->split_images[0], 1);
1956
1957         if (!lw->split_images[1])
1958                 {
1959                 layout_image_activate(lw, 0);
1960                 }
1961
1962         for (i = 1; i < 4; i++)
1963                 if (!lw->split_images[i])
1964                         {
1965                         layout_image_new(lw, i);
1966                         image_set_frame(lw->split_images[i], 1);
1967                         image_set_selectable(lw->split_images[i], 1);
1968                         if (lw->image)
1969                                 {
1970                                 gdouble sx, sy;
1971                                 image_change_fd(lw->split_images[i],
1972                                         image_get_fd(lw->image), image_zoom_get(lw->image));
1973                                 image_get_scroll_center(lw->image, &sx, &sy);
1974                                 image_set_scroll_center(lw->split_images[i], sx, sy);
1975                                 }
1976                         layout_image_deactivate(lw, i);
1977                         }
1978                 else
1979                         {
1980                         image_set_frame(lw->split_images[i], 1);
1981                         image_set_selectable(lw->split_images[i], 1);
1982                         }
1983
1984         for (i = 4; i < MAX_SPLIT_IMAGES; i++)
1985                 {
1986                 if (lw->split_images[i])
1987                         {
1988                         gtk_widget_unref(lw->split_images[i]->widget);
1989                         lw->split_images[i] = NULL;
1990                         }
1991                 }
1992
1993
1994         if (!lw->image || lw->active_split_image < 0 || lw->active_split_image > 3)
1995                 {
1996                 layout_image_activate(lw, 0);
1997                 }
1998
1999         hpaned = gtk_hpaned_new();
2000         vpaned1 = gtk_vpaned_new();
2001         vpaned2 = gtk_vpaned_new();
2002
2003         gtk_paned_pack1(GTK_PANED(vpaned1), lw->split_images[0]->widget, TRUE, TRUE);
2004         gtk_paned_pack2(GTK_PANED(vpaned1), lw->split_images[2]->widget, TRUE, TRUE);
2005
2006         gtk_paned_pack1(GTK_PANED(vpaned2), lw->split_images[1]->widget, TRUE, TRUE);
2007         gtk_paned_pack2(GTK_PANED(vpaned2), lw->split_images[3]->widget, TRUE, TRUE);
2008
2009         gtk_paned_pack1(GTK_PANED(hpaned), vpaned1, TRUE, TRUE);
2010         gtk_paned_pack2(GTK_PANED(hpaned), vpaned2, TRUE, TRUE);
2011
2012
2013         for (i = 0; i < 4; i++)
2014                 gtk_widget_show(lw->split_images[i]->widget);
2015
2016         gtk_widget_show(vpaned1);
2017         gtk_widget_show(vpaned2);
2018
2019
2020         lw->split_image_widget = hpaned;
2021
2022         return lw->split_image_widget;
2023
2024 }
2025
2026 GtkWidget *layout_image_setup_split(LayoutWindow *lw, ImageSplitMode mode)
2027 {
2028         switch (mode)
2029                 {
2030                 case SPLIT_HOR:
2031                         return layout_image_setup_split_hv(lw, TRUE);
2032                 case SPLIT_VERT:
2033                         return layout_image_setup_split_hv(lw, FALSE);
2034                 case SPLIT_QUAD:
2035                         return layout_image_setup_split_quad(lw);
2036                 case SPLIT_NONE:
2037                 default:
2038                         return layout_image_setup_split_none(lw);
2039                 }
2040 }
2041
2042
2043 /*
2044  *-----------------------------------------------------------------------------
2045  * maintenance (for rename, move, remove)
2046  *-----------------------------------------------------------------------------
2047  */
2048
2049 void layout_image_maint_renamed(LayoutWindow *lw, FileData *fd)
2050 {
2051         FileData *img_fd;
2052
2053         img_fd = layout_image_get_fd(lw);
2054         if (img_fd == fd)
2055                 {
2056                 image_set_fd(lw->image, fd);
2057                 layout_bars_maint_renamed(lw);
2058                 }
2059 }
2060
2061 void layout_image_maint_removed(LayoutWindow *lw, FileData *fd)
2062 {
2063         FileData *img_fd;
2064
2065         img_fd = layout_image_get_fd(lw);
2066         if (img_fd == fd)
2067                 {
2068                 CollectionData *cd;
2069                 CollectInfo *info;
2070
2071                 cd = image_get_collection(lw->image, &info);
2072                 if (cd && info)
2073                         {
2074                         CollectInfo *new;
2075
2076                         new = collection_next_by_info(cd, info);
2077                         if (!new) new = collection_prev_by_info(cd, info);
2078
2079                         if (new)
2080                                 {
2081                                 layout_image_set_collection(lw, cd, new);
2082                                 return;
2083                                 }
2084                         }
2085
2086                 layout_image_set_fd(lw, NULL);
2087                 }
2088 }
2089
2090 void layout_image_maint_moved(LayoutWindow *lw, FileData *fd)
2091 {
2092         layout_image_maint_renamed(lw, fd);
2093 }