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