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