fixed keyboard controll of image widget
[geeqie.git] / src / layout_util.c
1 /*
2  * Geeqie
3  * (C) 2004 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
14 #include "main.h"
15 #include "layout_util.h"
16
17 #include "advanced_exif.h"
18 #include "bar_sort.h"
19 #include "bar.h"
20 #include "cache_maint.h"
21 #include "collect.h"
22 #include "collect-dlg.h"
23 #include "compat.h"
24 #include "color-man.h"
25 #include "dupe.h"
26 #include "editors.h"
27 #include "filedata.h"
28 #include "history_list.h"
29 #include "image-overlay.h"
30 #include "histogram.h"
31 #include "img-view.h"
32 #include "layout_image.h"
33 #include "logwindow.h"
34 #include "misc.h"
35 #include "pan-view.h"
36 #include "pixbuf_util.h"
37 #include "preferences.h"
38 #include "print.h"
39 #include "search.h"
40 #include "ui_fileops.h"
41 #include "ui_menu.h"
42 #include "ui_misc.h"
43 #include "ui_tabcomp.h"
44 #include "utilops.h"
45 #include "view_dir.h"
46 #include "window.h"
47 #include "metadata.h"
48 #include "rcfile.h"
49 #include "desktop_file.h"
50
51 #include <gdk/gdkkeysyms.h> /* for keyboard values */
52
53
54 #define MENU_EDIT_ACTION_OFFSET 16
55
56 static gboolean layout_bar_enabled(LayoutWindow *lw);
57 static gboolean layout_bar_sort_enabled(LayoutWindow *lw);
58 static void layout_util_sync_views(LayoutWindow *lw);
59
60 /*
61  *-----------------------------------------------------------------------------
62  * keyboard handler
63  *-----------------------------------------------------------------------------
64  */
65
66 static guint tree_key_overrides[] = {
67         GDK_KEY_Page_Up,        GDK_KEY_KP_Page_Up,
68         GDK_KEY_Page_Down,      GDK_KEY_KP_Page_Down,
69         GDK_KEY_Home,   GDK_KEY_KP_Home,
70         GDK_KEY_End,    GDK_KEY_KP_End
71 };
72
73 static gboolean layout_key_match(guint keyval)
74 {
75         guint i;
76
77         for (i = 0; i < sizeof(tree_key_overrides) / sizeof(guint); i++)
78                 {
79                 if (keyval == tree_key_overrides[i]) return TRUE;
80                 }
81
82         return FALSE;
83 }
84
85 gboolean layout_key_press_cb(GtkWidget *widget, GdkEventKey *event, gpointer data)
86 {
87         LayoutWindow *lw = data;
88         GtkWidget *focused;
89         gboolean stop_signal = FALSE;
90         gint x = 0;
91         gint y = 0;
92
93 #if GTK_CHECK_VERSION(2,20,0)
94         if (lw->path_entry && gtk_widget_has_focus(lw->path_entry))
95 #else
96         if (lw->path_entry && GTK_WIDGET_HAS_FOCUS(lw->path_entry))
97 #endif
98                 {
99                 if (event->keyval == GDK_KEY_Escape && lw->dir_fd)
100                         {
101                         gtk_entry_set_text(GTK_ENTRY(lw->path_entry), lw->dir_fd->path);
102                         }
103
104                 /* the gtkaccelgroup of the window is stealing presses before they get to the entry (and more),
105                  * so when the some widgets have focus, give them priority (HACK)
106                  */
107                 if (gtk_widget_event(lw->path_entry, (GdkEvent *)event))
108                         {
109                         return TRUE;
110                         }
111                 }
112 #if GTK_CHECK_VERSION(2,20,0)
113         if (lw->vd && lw->options.dir_view_type == DIRVIEW_TREE && gtk_widget_has_focus(lw->vd->view) &&
114 #else
115         if (lw->vd && lw->options.dir_view_type == DIRVIEW_TREE && GTK_WIDGET_HAS_FOCUS(lw->vd->view) &&
116 #endif
117             !layout_key_match(event->keyval) &&
118             gtk_widget_event(lw->vd->view, (GdkEvent *)event))
119                 {
120                 return TRUE;
121                 }
122         if (lw->bar &&
123             bar_event(lw->bar, (GdkEvent *)event))
124                 {
125                 return TRUE;
126                 }
127
128 /*
129         if (event->type == GDK_KEY_PRESS && lw->full_screen &&
130             gtk_accel_groups_activate(G_OBJECT(lw->window), event->keyval, event->state))
131                 return TRUE;
132 */
133
134         focused = gtk_container_get_focus_child(GTK_CONTAINER(lw->image->widget));
135         if (lw->image &&
136 #if GTK_CHECK_VERSION(2,20,0)
137             (focused && gtk_widget_has_focus(focused) || (lw->tools && widget == lw->window) || lw->full_screen) )
138 #else
139             (focused && GTK_WIDGET_HAS_FOCUS(focused) || (lw->tools && widget == lw->window) || lw->full_screen) )
140 #endif
141                 {
142                 stop_signal = TRUE;
143                 switch (event->keyval)
144                         {
145                         case GDK_KEY_Left: case GDK_KEY_KP_Left:
146                                 x -= 1;
147                                 break;
148                         case GDK_KEY_Right: case GDK_KEY_KP_Right:
149                                 x += 1;
150                                 break;
151                         case GDK_KEY_Up: case GDK_KEY_KP_Up:
152                                 y -= 1;
153                                 break;
154                         case GDK_KEY_Down: case GDK_KEY_KP_Down:
155                                 y += 1;
156                                 break;
157                         default:
158                                 stop_signal = FALSE;
159                                 break;
160                         }
161
162                 if (!stop_signal &&
163                     !(event->state & GDK_CONTROL_MASK))
164                         {
165                         stop_signal = TRUE;
166                         switch (event->keyval)
167                                 {
168                                 case GDK_KEY_Menu:
169                                         layout_image_menu_popup(lw);
170                                         break;
171                                 default:
172                                         stop_signal = FALSE;
173                                         break;
174                                 }
175                         }
176                 }
177
178         if (x != 0 || y!= 0)
179                 {
180                 keyboard_scroll_calc(&x, &y, event);
181                 layout_image_scroll(lw, x, y, (event->state & GDK_SHIFT_MASK));
182                 }
183
184         return stop_signal;
185 }
186
187 void layout_keyboard_init(LayoutWindow *lw, GtkWidget *window)
188 {
189         g_signal_connect(G_OBJECT(window), "key_press_event",
190                          G_CALLBACK(layout_key_press_cb), lw);
191 }
192
193 /*
194  *-----------------------------------------------------------------------------
195  * menu callbacks
196  *-----------------------------------------------------------------------------
197  */
198
199
200 static GtkWidget *layout_window(LayoutWindow *lw)
201 {
202         return lw->full_screen ? lw->full_screen->window : lw->window;
203 }
204
205 static void layout_exit_fullscreen(LayoutWindow *lw)
206 {
207         if (!lw->full_screen) return;
208         layout_image_full_screen_stop(lw);
209 }
210
211 static void layout_menu_new_window_cb(GtkAction *action, gpointer data)
212 {
213         LayoutWindow *lw = data;
214         LayoutWindow *nw;
215         LayoutOptions lop;
216         gboolean tmp = options->save_window_positions;
217         options->save_window_positions = FALSE; /* let the windowmanager decide for the first time */
218
219         layout_exit_fullscreen(lw);
220
221         layout_sync_options_with_current_state(lw);
222         lop = lw->options; /* we can copy it directly, no strings are modified */
223
224         lop.id = NULL; /* get a new id */
225         nw = layout_new(NULL, &lop);
226         layout_sort_set(nw, options->file_sort.method, options->file_sort.ascending);
227         layout_set_fd(nw, lw->dir_fd);
228         options->save_window_positions = tmp;
229 }
230
231 static void layout_menu_new_cb(GtkAction *action, gpointer data)
232 {
233         LayoutWindow *lw = data;
234
235         layout_exit_fullscreen(lw);
236         collection_window_new(NULL);
237 }
238
239 static void layout_menu_open_cb(GtkAction *action, gpointer data)
240 {
241         LayoutWindow *lw = data;
242
243         layout_exit_fullscreen(lw);
244         collection_dialog_load(NULL);
245 }
246
247 static void layout_menu_search_cb(GtkAction *action, gpointer data)
248 {
249         LayoutWindow *lw = data;
250
251         layout_exit_fullscreen(lw);
252         search_new(lw->dir_fd, layout_image_get_fd(lw));
253 }
254
255 static void layout_menu_dupes_cb(GtkAction *action, gpointer data)
256 {
257         LayoutWindow *lw = data;
258
259         layout_exit_fullscreen(lw);
260         dupe_window_new(DUPE_MATCH_NAME);
261 }
262
263 static void layout_menu_pan_cb(GtkAction *action, gpointer data)
264 {
265         LayoutWindow *lw = data;
266
267         layout_exit_fullscreen(lw);
268         pan_window_new(lw->dir_fd);
269 }
270
271 static void layout_menu_print_cb(GtkAction *action, gpointer data)
272 {
273         LayoutWindow *lw = data;
274
275         print_window_new(layout_image_get_fd(lw), layout_selection_list(lw), layout_list(lw), layout_window(lw));
276 }
277
278 static void layout_menu_dir_cb(GtkAction *action, gpointer data)
279 {
280         LayoutWindow *lw = data;
281
282         if (lw->vd) vd_new_folder(lw->vd, lw->dir_fd);
283 }
284
285 static void layout_menu_copy_cb(GtkAction *action, gpointer data)
286 {
287         LayoutWindow *lw = data;
288
289         file_util_copy(NULL, layout_selection_list(lw), NULL, layout_window(lw));
290 }
291
292 static void layout_menu_copy_path_cb(GtkAction *action, gpointer data)
293 {
294         LayoutWindow *lw = data;
295
296         file_util_copy_path_list_to_clipboard(layout_selection_list(lw));
297 }
298
299 static void layout_menu_move_cb(GtkAction *action, gpointer data)
300 {
301         LayoutWindow *lw = data;
302
303         file_util_move(NULL, layout_selection_list(lw), NULL, layout_window(lw));
304 }
305
306 static void layout_menu_rename_cb(GtkAction *action, gpointer data)
307 {
308         LayoutWindow *lw = data;
309
310         file_util_rename(NULL, layout_selection_list(lw), layout_window(lw));
311 }
312
313 static void layout_menu_delete_cb(GtkAction *action, gpointer data)
314 {
315         LayoutWindow *lw = data;
316
317         file_util_delete(NULL, layout_selection_list(lw), layout_window(lw));
318 }
319
320 static void layout_menu_disable_grouping_cb(GtkAction *action, gpointer data)
321 {
322         LayoutWindow *lw = data;
323
324         file_data_disable_grouping_list(layout_selection_list(lw), TRUE);
325 }
326
327 static void layout_menu_enable_grouping_cb(GtkAction *action, gpointer data)
328 {
329         LayoutWindow *lw = data;
330
331         file_data_disable_grouping_list(layout_selection_list(lw), FALSE);
332 }
333
334 static void layout_menu_close_cb(GtkAction *action, gpointer data)
335 {
336         LayoutWindow *lw = data;
337
338         layout_exit_fullscreen(lw);
339         layout_close(lw);
340 }
341
342 static void layout_menu_exit_cb(GtkAction *action, gpointer data)
343 {
344         exit_program();
345 }
346
347 static void layout_menu_alter_90_cb(GtkAction *action, gpointer data)
348 {
349         LayoutWindow *lw = data;
350
351         layout_image_alter_orientation(lw, ALTER_ROTATE_90);
352 }
353
354 static void layout_menu_alter_90cc_cb(GtkAction *action, gpointer data)
355 {
356         LayoutWindow *lw = data;
357
358         layout_image_alter_orientation(lw, ALTER_ROTATE_90_CC);
359 }
360
361 static void layout_menu_alter_180_cb(GtkAction *action, gpointer data)
362 {
363         LayoutWindow *lw = data;
364
365         layout_image_alter_orientation(lw, ALTER_ROTATE_180);
366 }
367
368 static void layout_menu_alter_mirror_cb(GtkAction *action, gpointer data)
369 {
370         LayoutWindow *lw = data;
371
372         layout_image_alter_orientation(lw, ALTER_MIRROR);
373 }
374
375 static void layout_menu_alter_flip_cb(GtkAction *action, gpointer data)
376 {
377         LayoutWindow *lw = data;
378
379         layout_image_alter_orientation(lw, ALTER_FLIP);
380 }
381
382 static void layout_menu_alter_desaturate_cb(GtkToggleAction *action, gpointer data)
383 {
384         LayoutWindow *lw = data;
385
386         layout_image_set_desaturate(lw, gtk_toggle_action_get_active(action));
387 }
388
389 static void layout_menu_alter_none_cb(GtkAction *action, gpointer data)
390 {
391         LayoutWindow *lw = data;
392
393         layout_image_alter_orientation(lw, ALTER_NONE);
394 }
395
396 static void layout_menu_config_cb(GtkAction *action, gpointer data)
397 {
398         LayoutWindow *lw = data;
399
400         layout_exit_fullscreen(lw);
401         show_config_window();
402 }
403
404 static void layout_menu_editors_cb(GtkAction *action, gpointer data)
405 {
406         LayoutWindow *lw = data;
407
408         layout_exit_fullscreen(lw);
409         show_editor_list_window();
410 }
411
412 static void layout_menu_layout_config_cb(GtkAction *action, gpointer data)
413 {
414         LayoutWindow *lw = data;
415
416         layout_exit_fullscreen(lw);
417         layout_show_config_window(lw);
418 }
419
420 static void layout_menu_remove_thumb_cb(GtkAction *action, gpointer data)
421 {
422         LayoutWindow *lw = data;
423
424         layout_exit_fullscreen(lw);
425         cache_manager_show();
426 }
427
428 static void layout_menu_wallpaper_cb(GtkAction *action, gpointer data)
429 {
430         LayoutWindow *lw = data;
431
432         layout_image_to_root(lw);
433 }
434
435 /* single window zoom */
436 static void layout_menu_zoom_in_cb(GtkAction *action, gpointer data)
437 {
438         LayoutWindow *lw = data;
439
440         layout_image_zoom_adjust(lw, get_zoom_increment(), FALSE);
441 }
442
443 static void layout_menu_zoom_out_cb(GtkAction *action, gpointer data)
444 {
445         LayoutWindow *lw = data;
446
447         layout_image_zoom_adjust(lw, -get_zoom_increment(), FALSE);
448 }
449
450 static void layout_menu_zoom_1_1_cb(GtkAction *action, gpointer data)
451 {
452         LayoutWindow *lw = data;
453
454         layout_image_zoom_set(lw, 1.0, FALSE);
455 }
456
457 static void layout_menu_zoom_fit_cb(GtkAction *action, gpointer data)
458 {
459         LayoutWindow *lw = data;
460
461         layout_image_zoom_set(lw, 0.0, FALSE);
462 }
463
464 static void layout_menu_zoom_fit_hor_cb(GtkAction *action, gpointer data)
465 {
466         LayoutWindow *lw = data;
467
468         layout_image_zoom_set_fill_geometry(lw, FALSE, FALSE);
469 }
470
471 static void layout_menu_zoom_fit_vert_cb(GtkAction *action, gpointer data)
472 {
473         LayoutWindow *lw = data;
474
475         layout_image_zoom_set_fill_geometry(lw, TRUE, FALSE);
476 }
477
478 static void layout_menu_zoom_2_1_cb(GtkAction *action, gpointer data)
479 {
480         LayoutWindow *lw = data;
481
482         layout_image_zoom_set(lw, 2.0, FALSE);
483 }
484
485 static void layout_menu_zoom_3_1_cb(GtkAction *action, gpointer data)
486 {
487         LayoutWindow *lw = data;
488
489         layout_image_zoom_set(lw, 3.0, FALSE);
490 }
491 static void layout_menu_zoom_4_1_cb(GtkAction *action, gpointer data)
492 {
493         LayoutWindow *lw = data;
494
495         layout_image_zoom_set(lw, 4.0, FALSE);
496 }
497
498 static void layout_menu_zoom_1_2_cb(GtkAction *action, gpointer data)
499 {
500         LayoutWindow *lw = data;
501
502         layout_image_zoom_set(lw, -2.0, FALSE);
503 }
504
505 static void layout_menu_zoom_1_3_cb(GtkAction *action, gpointer data)
506 {
507         LayoutWindow *lw = data;
508
509         layout_image_zoom_set(lw, -3.0, FALSE);
510 }
511
512 static void layout_menu_zoom_1_4_cb(GtkAction *action, gpointer data)
513 {
514         LayoutWindow *lw = data;
515
516         layout_image_zoom_set(lw, -4.0, FALSE);
517 }
518
519 /* connected zoom */
520 static void layout_menu_connect_zoom_in_cb(GtkAction *action, gpointer data)
521 {
522         LayoutWindow *lw = data;
523
524         layout_image_zoom_adjust(lw, get_zoom_increment(), TRUE);
525 }
526
527 static void layout_menu_connect_zoom_out_cb(GtkAction *action, gpointer data)
528 {
529         LayoutWindow *lw = data;
530
531         layout_image_zoom_adjust(lw, -get_zoom_increment(), TRUE);
532 }
533
534 static void layout_menu_connect_zoom_1_1_cb(GtkAction *action, gpointer data)
535 {
536         LayoutWindow *lw = data;
537
538         layout_image_zoom_set(lw, 1.0, TRUE);
539 }
540
541 static void layout_menu_connect_zoom_fit_cb(GtkAction *action, gpointer data)
542 {
543         LayoutWindow *lw = data;
544
545         layout_image_zoom_set(lw, 0.0, TRUE);
546 }
547
548 static void layout_menu_connect_zoom_fit_hor_cb(GtkAction *action, gpointer data)
549 {
550         LayoutWindow *lw = data;
551
552         layout_image_zoom_set_fill_geometry(lw, FALSE, TRUE);
553 }
554
555 static void layout_menu_connect_zoom_fit_vert_cb(GtkAction *action, gpointer data)
556 {
557         LayoutWindow *lw = data;
558
559         layout_image_zoom_set_fill_geometry(lw, TRUE, TRUE);
560 }
561
562 static void layout_menu_connect_zoom_2_1_cb(GtkAction *action, gpointer data)
563 {
564         LayoutWindow *lw = data;
565
566         layout_image_zoom_set(lw, 2.0, TRUE);
567 }
568
569 static void layout_menu_connect_zoom_3_1_cb(GtkAction *action, gpointer data)
570 {
571         LayoutWindow *lw = data;
572
573         layout_image_zoom_set(lw, 3.0, TRUE);
574 }
575 static void layout_menu_connect_zoom_4_1_cb(GtkAction *action, gpointer data)
576 {
577         LayoutWindow *lw = data;
578
579         layout_image_zoom_set(lw, 4.0, TRUE);
580 }
581
582 static void layout_menu_connect_zoom_1_2_cb(GtkAction *action, gpointer data)
583 {
584         LayoutWindow *lw = data;
585
586         layout_image_zoom_set(lw, -2.0, TRUE);
587 }
588
589 static void layout_menu_connect_zoom_1_3_cb(GtkAction *action, gpointer data)
590 {
591         LayoutWindow *lw = data;
592
593         layout_image_zoom_set(lw, -3.0, TRUE);
594 }
595
596 static void layout_menu_connect_zoom_1_4_cb(GtkAction *action, gpointer data)
597 {
598         LayoutWindow *lw = data;
599
600         layout_image_zoom_set(lw, -4.0, TRUE);
601 }
602
603
604 static void layout_menu_split_cb(GtkRadioAction *action, GtkRadioAction *current, gpointer data)
605 {
606         LayoutWindow *lw = data;
607         ImageSplitMode mode;
608
609         layout_exit_fullscreen(lw);
610         mode = gtk_radio_action_get_current_value(action);
611         layout_split_change(lw, mode);
612 }
613
614
615 static void layout_menu_thumb_cb(GtkToggleAction *action, gpointer data)
616 {
617         LayoutWindow *lw = data;
618
619         layout_thumb_set(lw, gtk_toggle_action_get_active(action));
620 }
621
622
623 static void layout_menu_list_cb(GtkRadioAction *action, GtkRadioAction *current, gpointer data)
624 {
625         LayoutWindow *lw = data;
626         
627         layout_exit_fullscreen(lw);
628         layout_views_set(lw, lw->options.dir_view_type, (FileViewType) gtk_radio_action_get_current_value(action));
629 }
630
631 static void layout_menu_view_dir_as_cb(GtkRadioAction *action, GtkRadioAction *current, gpointer data)
632 {
633         LayoutWindow *lw = data;
634
635         layout_exit_fullscreen(lw);
636         layout_views_set(lw, (DirViewType) gtk_radio_action_get_current_value(action), lw->options.file_view_type);
637 }
638
639 static void layout_menu_view_in_new_window_cb(GtkAction *action, gpointer data)
640 {
641         LayoutWindow *lw = data;
642
643         layout_exit_fullscreen(lw);
644         view_window_new(layout_image_get_fd(lw));
645 }
646
647 static void layout_menu_fullscreen_cb(GtkAction *action, gpointer data)
648 {
649         LayoutWindow *lw = data;
650
651         layout_image_full_screen_toggle(lw);
652 }
653
654 static void layout_menu_escape_cb(GtkAction *action, gpointer data)
655 {
656         LayoutWindow *lw = data;
657
658         layout_exit_fullscreen(lw);
659
660         /* FIXME:interrupting thumbs no longer allowed */
661 #if 0
662         interrupt_thumbs();
663 #endif
664 }
665
666 static void layout_menu_overlay_toggle_cb(GtkAction *action, gpointer data)
667 {
668         LayoutWindow *lw = data;
669
670         image_osd_toggle(lw->image);
671         layout_util_sync_views(lw);
672 }
673
674
675 static void layout_menu_overlay_cb(GtkToggleAction *action, gpointer data)
676 {
677         LayoutWindow *lw = data;
678         
679         if (gtk_toggle_action_get_active(action))
680                 {
681                 OsdShowFlags flags = image_osd_get(lw->image);
682                 
683                 if ((flags | OSD_SHOW_INFO | OSD_SHOW_STATUS) != flags)
684                         image_osd_set(lw->image, flags | OSD_SHOW_INFO | OSD_SHOW_STATUS);
685                 }
686         else
687                 {
688                 GtkToggleAction *histogram_action = GTK_TOGGLE_ACTION(gtk_action_group_get_action(lw->action_group, "ImageHistogram"));
689                 
690                 image_osd_set(lw->image, OSD_SHOW_NOTHING);
691                 gtk_toggle_action_set_active(histogram_action, FALSE); /* this calls layout_menu_histogram_cb */
692                 }
693 }
694
695 static void layout_menu_histogram_cb(GtkToggleAction *action, gpointer data)
696 {
697         LayoutWindow *lw = data;
698
699         if (gtk_toggle_action_get_active(action))
700                 {
701                 image_osd_set(lw->image, OSD_SHOW_INFO | OSD_SHOW_STATUS | OSD_SHOW_HISTOGRAM);
702                 layout_util_sync_views(lw); /* show the overlay state, default channel and mode in the menu */
703                 }
704         else
705                 {
706                 OsdShowFlags flags = image_osd_get(lw->image);
707                 if (flags & OSD_SHOW_HISTOGRAM)
708                         image_osd_set(lw->image, flags & ~OSD_SHOW_HISTOGRAM);
709                 }
710 }
711
712 static void layout_menu_histogram_toggle_channel_cb(GtkAction *action, gpointer data)
713 {
714         LayoutWindow *lw = data;
715
716         image_osd_histogram_toggle_channel(lw->image);
717         layout_util_sync_views(lw);
718 }
719
720 static void layout_menu_histogram_toggle_mode_cb(GtkAction *action, gpointer data)
721 {
722         LayoutWindow *lw = data;
723
724         image_osd_histogram_toggle_mode(lw->image);
725         layout_util_sync_views(lw);
726 }
727
728 static void layout_menu_histogram_channel_cb(GtkRadioAction *action, GtkRadioAction *current, gpointer data)
729 {
730         LayoutWindow *lw = data;
731         gint channel = gtk_radio_action_get_current_value(action);
732         GtkToggleAction *histogram_action = GTK_TOGGLE_ACTION(gtk_action_group_get_action(lw->action_group, "ImageHistogram"));
733
734         if (channel < 0 || channel >= HCHAN_COUNT) return;
735         
736         gtk_toggle_action_set_active(histogram_action, TRUE); /* this calls layout_menu_histogram_cb */
737         image_osd_histogram_set_channel(lw->image, channel);
738 }
739
740 static void layout_menu_histogram_mode_cb(GtkRadioAction *action, GtkRadioAction *current, gpointer data)
741 {
742         LayoutWindow *lw = data;
743         gint mode = gtk_radio_action_get_current_value(action);
744         GtkToggleAction *histogram_action = GTK_TOGGLE_ACTION(gtk_action_group_get_action(lw->action_group, "ImageHistogram"));
745
746         if (mode < 0 || mode > 1) return;
747         
748         gtk_toggle_action_set_active(histogram_action, TRUE); /* this calls layout_menu_histogram_cb */
749         image_osd_histogram_set_mode(lw->image, mode);
750 }
751
752 static void layout_menu_refresh_cb(GtkAction *action, gpointer data)
753 {
754         LayoutWindow *lw = data;
755
756         layout_refresh(lw);
757 }
758
759 static void layout_menu_bar_exif_cb(GtkAction *action, gpointer data)
760 {
761         LayoutWindow *lw = data;
762         
763         layout_exit_fullscreen(lw);
764         layout_exif_window_new(lw);
765 }
766
767 static void layout_menu_float_cb(GtkToggleAction *action, gpointer data)
768 {
769         LayoutWindow *lw = data;
770
771         if (lw->options.tools_float == gtk_toggle_action_get_active(action)) return;
772
773         layout_exit_fullscreen(lw);
774         layout_tools_float_toggle(lw);
775 }
776
777 static void layout_menu_hide_cb(GtkAction *action, gpointer data)
778 {
779         LayoutWindow *lw = data;
780
781         layout_exit_fullscreen(lw);
782         layout_tools_hide_toggle(lw);
783 }
784
785 static void layout_menu_toolbar_cb(GtkToggleAction *action, gpointer data)
786 {
787         LayoutWindow *lw = data;
788
789         if (lw->options.toolbar_hidden == gtk_toggle_action_get_active(action)) return;
790
791         layout_exit_fullscreen(lw);
792         layout_toolbar_toggle(lw);
793 }
794
795 static void layout_menu_info_pixel_cb(GtkToggleAction *action, gpointer data)
796 {
797         LayoutWindow *lw = data;
798
799         if (lw->options.show_info_pixel == gtk_toggle_action_get_active(action)) return;
800
801         layout_exit_fullscreen(lw);
802         layout_info_pixel_set(lw, !lw->options.show_info_pixel);
803 }
804
805 /* NOTE: these callbacks are called also from layout_util_sync_views */
806 static void layout_menu_bar_cb(GtkToggleAction *action, gpointer data)
807 {
808         LayoutWindow *lw = data;
809
810         if (layout_bar_enabled(lw) == gtk_toggle_action_get_active(action)) return;
811
812         layout_exit_fullscreen(lw);
813         layout_bar_toggle(lw);
814 }
815
816 static void layout_menu_bar_sort_cb(GtkToggleAction *action, gpointer data)
817 {
818         LayoutWindow *lw = data;
819
820         if (layout_bar_sort_enabled(lw) == gtk_toggle_action_get_active(action)) return;
821
822         layout_exit_fullscreen(lw);
823         layout_bar_sort_toggle(lw);
824 }
825
826 static void layout_menu_slideshow_cb(GtkToggleAction *action, gpointer data)
827 {
828         LayoutWindow *lw = data;
829
830         if (layout_image_slideshow_active(lw) == gtk_toggle_action_get_active(action)) return;
831         layout_image_slideshow_toggle(lw);
832 }
833
834 static void layout_menu_slideshow_pause_cb(GtkAction *action, gpointer data)
835 {
836         LayoutWindow *lw = data;
837
838         layout_image_slideshow_pause_toggle(lw);
839 }
840
841
842 static void layout_menu_stereo_mode_next_cb(GtkAction *action, gpointer data)
843 {
844         LayoutWindow *lw = data;
845         gint mode = layout_image_stereo_pixbuf_get(lw);
846         
847         /* 0->1, 1->2, 2->3, 3->1 - disable auto, then cycle */
848         mode = mode % 3 + 1;
849         
850         GtkAction *radio = gtk_action_group_get_action(lw->action_group, "StereoAuto");
851         radio_action_set_current_value(GTK_RADIO_ACTION(radio), mode);
852         
853         /*
854         this is called via fallback in layout_menu_stereo_mode_cb
855         layout_image_stereo_pixbuf_set(lw, mode);
856         */
857
858 }
859
860 static void layout_menu_stereo_mode_cb(GtkRadioAction *action, GtkRadioAction *current, gpointer data)
861 {
862         LayoutWindow *lw = data;
863         gint mode = gtk_radio_action_get_current_value(action);
864         layout_image_stereo_pixbuf_set(lw, mode);
865 }
866
867 static void layout_menu_help_cb(GtkAction *action, gpointer data)
868 {
869         LayoutWindow *lw = data;
870
871         layout_exit_fullscreen(lw);
872         help_window_show("html_contents");
873 }
874
875 static void layout_menu_help_keys_cb(GtkAction *action, gpointer data)
876 {
877         LayoutWindow *lw = data;
878
879         layout_exit_fullscreen(lw);
880         help_window_show("documentation");
881 }
882
883 static void layout_menu_notes_cb(GtkAction *action, gpointer data)
884 {
885         LayoutWindow *lw = data;
886         
887         layout_exit_fullscreen(lw);
888         help_window_show("release_notes");
889 }
890
891 static void layout_menu_about_cb(GtkAction *action, gpointer data)
892 {
893         LayoutWindow *lw = data;
894
895         layout_exit_fullscreen(lw);
896         show_about_window();
897 }
898
899 static void layout_menu_log_window_cb(GtkAction *action, gpointer data)
900 {
901         LayoutWindow *lw = data;
902
903         layout_exit_fullscreen(lw);
904         log_window_new();
905 }
906
907
908 /*
909  *-----------------------------------------------------------------------------
910  * select menu
911  *-----------------------------------------------------------------------------
912  */
913
914 static void layout_menu_select_all_cb(GtkAction *action, gpointer data)
915 {
916         LayoutWindow *lw = data;
917
918         layout_select_all(lw);
919 }
920
921 static void layout_menu_unselect_all_cb(GtkAction *action, gpointer data)
922 {
923         LayoutWindow *lw = data;
924
925         layout_select_none(lw);
926 }
927
928 static void layout_menu_invert_selection_cb(GtkAction *action, gpointer data)
929 {
930         LayoutWindow *lw = data;
931
932         layout_select_invert(lw);
933 }
934
935 static void layout_menu_marks_cb(GtkToggleAction *action, gpointer data)
936 {
937         LayoutWindow *lw = data;
938
939         layout_marks_set(lw, gtk_toggle_action_get_active(action));
940 }
941
942
943 static void layout_menu_set_mark_sel_cb(GtkAction *action, gpointer data)
944 {
945         LayoutWindow *lw = data;
946         gint mark = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(action), "mark_num"));
947         g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
948
949         layout_selection_to_mark(lw, mark, STM_MODE_SET);
950 }
951
952 static void layout_menu_res_mark_sel_cb(GtkAction *action, gpointer data)
953 {
954         LayoutWindow *lw = data;
955         gint mark = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(action), "mark_num"));
956         g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
957
958         layout_selection_to_mark(lw, mark, STM_MODE_RESET);
959 }
960
961 static void layout_menu_toggle_mark_sel_cb(GtkAction *action, gpointer data)
962 {
963         LayoutWindow *lw = data;
964         gint mark = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(action), "mark_num"));
965         g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
966
967         layout_selection_to_mark(lw, mark, STM_MODE_TOGGLE);
968 }
969
970 static void layout_menu_sel_mark_cb(GtkAction *action, gpointer data)
971 {
972         LayoutWindow *lw = data;
973         gint mark = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(action), "mark_num"));
974         g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
975
976         layout_mark_to_selection(lw, mark, MTS_MODE_SET);
977 }
978
979 static void layout_menu_sel_mark_or_cb(GtkAction *action, gpointer data)
980 {
981         LayoutWindow *lw = data;
982         gint mark = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(action), "mark_num"));
983         g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
984
985         layout_mark_to_selection(lw, mark, MTS_MODE_OR);
986 }
987
988 static void layout_menu_sel_mark_and_cb(GtkAction *action, gpointer data)
989 {
990         LayoutWindow *lw = data;
991         gint mark = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(action), "mark_num"));
992         g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
993
994         layout_mark_to_selection(lw, mark, MTS_MODE_AND);
995 }
996
997 static void layout_menu_sel_mark_minus_cb(GtkAction *action, gpointer data)
998 {
999         LayoutWindow *lw = data;
1000         gint mark = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(action), "mark_num"));
1001         g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
1002
1003         layout_mark_to_selection(lw, mark, MTS_MODE_MINUS);
1004 }
1005
1006 static void layout_menu_mark_filter_toggle_cb(GtkAction *action, gpointer data)
1007 {
1008         LayoutWindow *lw = data;
1009         gint mark = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(action), "mark_num"));
1010         g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
1011
1012         layout_marks_set(lw, TRUE);
1013         layout_mark_filter_toggle(lw, mark);
1014 }
1015
1016
1017 /*
1018  *-----------------------------------------------------------------------------
1019  * go menu
1020  *-----------------------------------------------------------------------------
1021  */
1022
1023 static void layout_menu_image_first_cb(GtkAction *action, gpointer data)
1024 {
1025         LayoutWindow *lw = data;
1026         layout_image_first(lw);
1027 }
1028
1029 static void layout_menu_image_prev_cb(GtkAction *action, gpointer data)
1030 {
1031         LayoutWindow *lw = data;
1032         layout_image_prev(lw);
1033 }
1034
1035 static void layout_menu_image_next_cb(GtkAction *action, gpointer data)
1036 {
1037         LayoutWindow *lw = data;
1038         layout_image_next(lw);
1039 }
1040
1041 static void layout_menu_image_last_cb(GtkAction *action, gpointer data)
1042 {
1043         LayoutWindow *lw = data;
1044         layout_image_last(lw);
1045 }
1046
1047 static void layout_menu_back_cb(GtkAction *action, gpointer data)
1048 {
1049         LayoutWindow *lw = data;
1050         FileData *dir_fd;
1051         gchar *path = NULL;
1052         GList *list = history_list_get_by_key("path_list");
1053         gint n = 0;
1054
1055         while (list)
1056                 {
1057                 if (n == 1) {
1058                         /* Previous path from history */
1059                         path = (gchar *)list->data;
1060                         break;
1061                 }
1062                 list = list->next;
1063                 n++;
1064                 }
1065
1066         if (!path) return;
1067         
1068         /* Open previous path */
1069         dir_fd = file_data_new_dir(path);
1070         layout_set_fd(lw, dir_fd);
1071         file_data_unref(dir_fd);
1072 }
1073
1074 static void layout_menu_home_cb(GtkAction *action, gpointer data)
1075 {
1076         LayoutWindow *lw = data;
1077         const gchar *path;
1078         
1079         if (lw->options.home_path && *lw->options.home_path)
1080                 path = lw->options.home_path;
1081         else
1082                 path = homedir();
1083
1084         if (path)
1085                 {
1086                 FileData *dir_fd = file_data_new_dir(path);
1087                 layout_set_fd(lw, dir_fd);
1088                 file_data_unref(dir_fd);
1089                 }
1090 }
1091
1092
1093 /*
1094  *-----------------------------------------------------------------------------
1095  * edit menu
1096  *-----------------------------------------------------------------------------
1097  */
1098
1099 static void layout_menu_edit_cb(GtkAction *action, gpointer data)
1100 {
1101         LayoutWindow *lw = data;
1102         const gchar *key = gtk_action_get_name(action);
1103         
1104         if (!editor_window_flag_set(key))
1105                 layout_exit_fullscreen(lw);
1106
1107         file_util_start_editor_from_filelist(key, layout_selection_list(lw), layout_get_path(lw), lw->window);
1108 }
1109
1110
1111 static void layout_menu_metadata_write_cb(GtkAction *action, gpointer data)
1112 {
1113         metadata_write_queue_confirm(TRUE, NULL, NULL);
1114 }
1115
1116
1117 /*
1118  *-----------------------------------------------------------------------------
1119  * color profile button (and menu)
1120  *-----------------------------------------------------------------------------
1121  */
1122
1123 static void layout_color_menu_enable_cb(GtkToggleAction *action, gpointer data)
1124 {
1125 #ifdef HAVE_LCMS
1126         LayoutWindow *lw = data;
1127
1128         if (layout_image_color_profile_get_use(lw) == gtk_toggle_action_get_active(action)) return;
1129
1130         layout_image_color_profile_set_use(lw, gtk_toggle_action_get_active(action));
1131         layout_util_sync_color(lw);
1132         layout_image_refresh(lw);
1133 #endif
1134 }
1135
1136 static void layout_color_menu_use_image_cb(GtkToggleAction *action, gpointer data)
1137 {
1138 #ifdef HAVE_LCMS
1139         LayoutWindow *lw = data;
1140         gint input;
1141         gboolean use_image;
1142
1143         if (!layout_image_color_profile_get(lw, &input, &use_image)) return;
1144         if (use_image == gtk_toggle_action_get_active(action)) return;
1145         layout_image_color_profile_set(lw, input, gtk_toggle_action_get_active(action));
1146         layout_util_sync_color(lw);
1147         layout_image_refresh(lw);
1148 #endif
1149 }
1150
1151 static void layout_color_menu_input_cb(GtkRadioAction *action, GtkRadioAction *current, gpointer data)
1152 {
1153 #ifdef HAVE_LCMS
1154         LayoutWindow *lw = data;
1155         gint type;
1156         gint input;
1157         gboolean use_image;
1158
1159         type = gtk_radio_action_get_current_value(action);
1160         if (type < 0 || type >= COLOR_PROFILE_FILE + COLOR_PROFILE_INPUTS) return;
1161
1162         if (!layout_image_color_profile_get(lw, &input, &use_image)) return;
1163         if (type == input) return;
1164
1165         layout_image_color_profile_set(lw, type, use_image);
1166         layout_image_refresh(lw);
1167 #endif
1168 }
1169
1170
1171 /*
1172  *-----------------------------------------------------------------------------
1173  * recent menu
1174  *-----------------------------------------------------------------------------
1175  */
1176
1177 static void layout_menu_recent_cb(GtkWidget *widget, gpointer data)
1178 {
1179         gint n;
1180         gchar *path;
1181
1182         n = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "recent_index"));
1183
1184         path = g_list_nth_data(history_list_get_by_key("recent"), n);
1185
1186         if (!path) return;
1187
1188         /* make a copy of it */
1189         path = g_strdup(path);
1190         collection_window_new(path);
1191         g_free(path);
1192 }
1193
1194 static void layout_menu_recent_update(LayoutWindow *lw)
1195 {
1196         GtkWidget *menu;
1197         GtkWidget *recent;
1198         GtkWidget *item;
1199         GList *list;
1200         gint n;
1201
1202         if (!lw->ui_manager) return;
1203
1204         list = history_list_get_by_key("recent");
1205         n = 0;
1206
1207         menu = gtk_menu_new();
1208
1209         while (list)
1210                 {
1211                 const gchar *filename = filename_from_path((gchar *)list->data);
1212                 gchar *name;
1213                 gboolean free_name = FALSE;
1214
1215                 if (file_extension_match(filename, GQ_COLLECTION_EXT))
1216                         {
1217                         name = remove_extension_from_path(filename);
1218                         free_name = TRUE;
1219                         }
1220                 else
1221                         {
1222                         name = (gchar *) filename;
1223                         }
1224
1225                 item = menu_item_add_simple(menu, name, G_CALLBACK(layout_menu_recent_cb), lw);
1226                 if (free_name) g_free(name);
1227                 g_object_set_data(G_OBJECT(item), "recent_index", GINT_TO_POINTER(n));
1228                 list = list->next;
1229                 n++;
1230                 }
1231
1232         if (n == 0)
1233                 {
1234                 menu_item_add(menu, _("Empty"), NULL, NULL);
1235                 }
1236
1237         recent = gtk_ui_manager_get_widget(lw->ui_manager, "/MainMenu/FileMenu/OpenRecent");
1238         gtk_menu_item_set_submenu(GTK_MENU_ITEM(recent), menu);
1239         gtk_widget_set_sensitive(recent, (n != 0));
1240 }
1241
1242 void layout_recent_update_all(void)
1243 {
1244         GList *work;
1245
1246         work = layout_window_list;
1247         while (work)
1248                 {
1249                 LayoutWindow *lw = work->data;
1250                 work = work->next;
1251
1252                 layout_menu_recent_update(lw);
1253                 }
1254 }
1255
1256 void layout_recent_add_path(const gchar *path)
1257 {
1258         if (!path) return;
1259
1260         history_list_add_to_key("recent", path, options->open_recent_list_maxsize);
1261
1262         layout_recent_update_all();
1263 }
1264
1265 /*
1266  *-----------------------------------------------------------------------------
1267  * menu
1268  *-----------------------------------------------------------------------------
1269  */
1270
1271 #define CB G_CALLBACK
1272
1273 static GtkActionEntry menu_entries[] = {
1274   { "FileMenu",         NULL,                   N_("_File"),                            NULL,                   NULL,                                   NULL },
1275   { "GoMenu",           NULL,                   N_("_Go"),                              NULL,                   NULL,                                   NULL },
1276   { "EditMenu",         NULL,                   N_("_Edit"),                            NULL,                   NULL,                                   NULL },
1277   { "SelectMenu",       NULL,                   N_("_Select"),                          NULL,                   NULL,                                   NULL },
1278   { "OrientationMenu",  NULL,                   N_("_Orientation"),                     NULL,                   NULL,                                   NULL },
1279   { "ExternalMenu",     NULL,                   N_("E_xternal Editors"),                NULL,                   NULL,                                   NULL },
1280   { "PreferencesMenu",  NULL,                   N_("P_references"),                     NULL,                   NULL,                                   NULL },
1281   { "ViewMenu",         NULL,                   N_("_View"),                            NULL,                   NULL,                                   NULL },
1282   { "FileDirMenu",      NULL,                   N_("_Files and Folders"),               NULL,                   NULL,                                   NULL },
1283   { "ZoomMenu",         NULL,                   N_("_Zoom"),                            NULL,                   NULL,                                   NULL },
1284   { "ColorMenu",        NULL,                   N_("_Color Management"),                NULL,                   NULL,                                   NULL },
1285   { "ConnectZoomMenu",  NULL,                   N_("_Connected Zoom"),                  NULL,                   NULL,                                   NULL },
1286   { "SplitMenu",        NULL,                   N_("Spli_t"),                           NULL,                   NULL,                                   NULL },
1287   { "StereoMenu",       NULL,                   N_("Stere_o"),                          NULL,                   NULL,                                   NULL },
1288   { "OverlayMenu",      NULL,                   N_("Image _Overlay"),                   NULL,                   NULL,                                   NULL },
1289   { "HelpMenu",         NULL,                   N_("_Help"),                            NULL,                   NULL,                                   NULL },
1290
1291   { "FirstImage",       GTK_STOCK_GOTO_TOP,     N_("_First Image"),                     "Home",                 N_("First Image"),                      CB(layout_menu_image_first_cb) },
1292   { "PrevImage",        GTK_STOCK_GO_UP,        N_("_Previous Image"),                  "BackSpace",            N_("Previous Image"),                   CB(layout_menu_image_prev_cb) },
1293   { "PrevImageAlt1",    GTK_STOCK_GO_UP,        N_("_Previous Image"),                  "Page_Up",              N_("Previous Image"),                   CB(layout_menu_image_prev_cb) },
1294   { "PrevImageAlt2",    GTK_STOCK_GO_UP,        N_("_Previous Image"),                  "KP_Page_Up",           N_("Previous Image"),                   CB(layout_menu_image_prev_cb) },
1295   { "NextImage",        GTK_STOCK_GO_DOWN,      N_("_Next Image"),                      "space",                N_("Next Image"),                       CB(layout_menu_image_next_cb) },
1296   { "NextImageAlt1",    GTK_STOCK_GO_DOWN,      N_("_Next Image"),                      "Page_Down",            N_("Next Image"),                       CB(layout_menu_image_next_cb) },
1297   { "NextImageAlt2",    GTK_STOCK_GO_DOWN,      N_("_Next Image"),                      "KP_Page_Down",         N_("Next Image"),                       CB(layout_menu_image_next_cb) },
1298   { "LastImage",        GTK_STOCK_GOTO_BOTTOM,  N_("_Last Image"),                      "End",                  N_("Last Image"),                       CB(layout_menu_image_last_cb) },
1299   { "Back",             GTK_STOCK_GO_BACK,      N_("_Back"),                            NULL,                   N_("Back"),                             CB(layout_menu_back_cb) },
1300   { "Home",             GTK_STOCK_HOME,         N_("_Home"),                            NULL,                   N_("Home"),                             CB(layout_menu_home_cb) },
1301
1302   { "NewWindow",        GTK_STOCK_NEW,          N_("New _window"),                      "<control>N",           N_("New window"),                       CB(layout_menu_new_window_cb) },
1303   { "NewCollection",    GTK_STOCK_INDEX,        N_("_New collection"),                  "C",                    N_("New collection"),                   CB(layout_menu_new_cb) },
1304   { "OpenCollection",   GTK_STOCK_OPEN,         N_("_Open collection..."),              "O",                    N_("Open collection..."),               CB(layout_menu_open_cb) },
1305   { "OpenRecent",       NULL,                   N_("Open recen_t"),                     NULL,                   N_("Open recent"),                      NULL },
1306   { "Search",           GTK_STOCK_FIND,         N_("_Search..."),                       "F3",                   N_("Search..."),                        CB(layout_menu_search_cb) },
1307   { "FindDupes",        GTK_STOCK_FIND,         N_("_Find duplicates..."),              "D",                    N_("Find duplicates..."),               CB(layout_menu_dupes_cb) },
1308   { "PanView",          NULL,                   N_("Pa_n view"),                        "<control>J",           N_("Pan view"),                         CB(layout_menu_pan_cb) },
1309   { "Print",            GTK_STOCK_PRINT,        N_("_Print..."),                        "<shift>P",             N_("Print..."),                         CB(layout_menu_print_cb) },
1310   { "NewFolder",        GTK_STOCK_DIRECTORY,    N_("N_ew folder..."),                   "<control>F",           N_("New folder..."),                    CB(layout_menu_dir_cb) },
1311   { "Copy",             GTK_STOCK_COPY,         N_("_Copy..."),                         "<control>C",           N_("Copy..."),                          CB(layout_menu_copy_cb) },
1312   { "Move",             NULL,                   N_("_Move..."),                         "<control>M",           N_("Move..."),                          CB(layout_menu_move_cb) },
1313   { "Rename",           NULL,                   N_("_Rename..."),                       "<control>R",           N_("Rename..."),                        CB(layout_menu_rename_cb) },
1314   { "Delete",           GTK_STOCK_DELETE,       N_("_Delete..."),                       "<control>D",           N_("Delete..."),                        CB(layout_menu_delete_cb) },
1315   { "DeleteAlt1",       GTK_STOCK_DELETE,       N_("_Delete..."),                       "Delete",               N_("Delete..."),                        CB(layout_menu_delete_cb) },
1316   { "DeleteAlt2",       GTK_STOCK_DELETE,       N_("_Delete..."),                       "KP_Delete",            N_("Delete..."),                        CB(layout_menu_delete_cb) },
1317   { "EnableGrouping",   NULL,                   N_("Enable file _grouping"),            NULL,                   N_("Enable file grouping"),             CB(layout_menu_enable_grouping_cb) },
1318   { "DisableGrouping",  NULL,                   N_("Disable file groupi_ng"),           NULL,                   N_("Disable file grouping"),            CB(layout_menu_disable_grouping_cb) },
1319   { "CopyPath",         NULL,                   N_("_Copy path to clipboard"),          NULL,                   N_("Copy path to clipboard"),           CB(layout_menu_copy_path_cb) },
1320   { "CloseWindow",      GTK_STOCK_CLOSE,        N_("C_lose window"),                    "<control>W",           N_("Close window"),                     CB(layout_menu_close_cb) },
1321   { "Quit",             GTK_STOCK_QUIT,         N_("_Quit"),                            "<control>Q",           N_("Quit"),                             CB(layout_menu_exit_cb) },
1322   { "RotateCW",         NULL,                   N_("_Rotate clockwise"),                "bracketright",         N_("Rotate clockwise"),                 CB(layout_menu_alter_90_cb) },
1323   { "RotateCCW",        NULL,                   N_("Rotate _counterclockwise"),         "bracketleft",          N_("Rotate counterclockwise"),          CB(layout_menu_alter_90cc_cb) },
1324   { "Rotate180",        NULL,                   N_("Rotate 1_80"),                      "<shift>R",             N_("Rotate 180"),                       CB(layout_menu_alter_180_cb) },
1325   { "Mirror",           NULL,                   N_("_Mirror"),                          "<shift>M",             N_("Mirror"),                           CB(layout_menu_alter_mirror_cb) },
1326   { "Flip",             NULL,                   N_("_Flip"),                            "<shift>F",             N_("Flip"),                             CB(layout_menu_alter_flip_cb) },
1327   { "AlterNone",        NULL,                   N_("_Original state"),                  "<shift>O",             N_("Original state"),                   CB(layout_menu_alter_none_cb) },
1328   { "SelectAll",        NULL,                   N_("Select _all"),                      "<control>A",           N_("Select all"),                       CB(layout_menu_select_all_cb) },
1329   { "SelectNone",       NULL,                   N_("Select _none"),                     "<control><shift>A",    N_("Select none"),                      CB(layout_menu_unselect_all_cb) },
1330   { "SelectInvert",     NULL,                   N_("_Invert Selection"),                "<control><shift>I",    N_("Invert Selection"),                 CB(layout_menu_invert_selection_cb) },
1331   { "Preferences",      GTK_STOCK_PREFERENCES,  N_("P_references..."),                  "<control>O",           N_("Preferences..."),                   CB(layout_menu_config_cb) },
1332   { "Editors",          GTK_STOCK_PREFERENCES,  N_("Configure _Editors..."),            NULL,                   N_("Configure Editors..."),             CB(layout_menu_editors_cb) },
1333   { "LayoutConfig",     GTK_STOCK_PREFERENCES,  N_("_Configure this window..."),        NULL,                   N_("Configure this window..."),         CB(layout_menu_layout_config_cb) },
1334   { "Maintenance",      NULL,                   N_("_Thumbnail maintenance..."),        NULL,                   N_("Thumbnail maintenance..."),         CB(layout_menu_remove_thumb_cb) },
1335   { "Wallpaper",        NULL,                   N_("Set as _wallpaper"),                NULL,                   N_("Set as wallpaper"),                 CB(layout_menu_wallpaper_cb) },
1336   { "SaveMetadata",     GTK_STOCK_SAVE,         N_("_Save metadata"),                   "<control>S",           N_("Save metadata"),                    CB(layout_menu_metadata_write_cb) },
1337   { "ZoomIn",           GTK_STOCK_ZOOM_IN,      N_("Zoom _in"),                         "equal",                N_("Zoom in"),                          CB(layout_menu_zoom_in_cb) },
1338   { "ZoomInAlt1",       GTK_STOCK_ZOOM_IN,      N_("Zoom _in"),                         "KP_Add",               N_("Zoom in"),                          CB(layout_menu_zoom_in_cb) },
1339   { "ZoomOut",          GTK_STOCK_ZOOM_OUT,     N_("Zoom _out"),                        "minus",                N_("Zoom out"),                         CB(layout_menu_zoom_out_cb) },
1340   { "ZoomOutAlt1",      GTK_STOCK_ZOOM_OUT,     N_("Zoom _out"),                        "KP_Subtract",          N_("Zoom out"),                         CB(layout_menu_zoom_out_cb) },
1341   { "Zoom100",          GTK_STOCK_ZOOM_100,     N_("Zoom _1:1"),                        "Z",                    N_("Zoom 1:1"),                         CB(layout_menu_zoom_1_1_cb) },
1342   { "Zoom100Alt1",      GTK_STOCK_ZOOM_100,     N_("Zoom _1:1"),                        "KP_Divide",            N_("Zoom 1:1"),                         CB(layout_menu_zoom_1_1_cb) },
1343   { "ZoomFit",          GTK_STOCK_ZOOM_FIT,     N_("_Zoom to fit"),                     "X",                    N_("Zoom to fit"),                      CB(layout_menu_zoom_fit_cb) },
1344   { "ZoomFitAlt1",      GTK_STOCK_ZOOM_FIT,     N_("_Zoom to fit"),                     "KP_Multiply",          N_("Zoom to fit"),                      CB(layout_menu_zoom_fit_cb) },
1345   { "ZoomFillHor",      NULL,                   N_("Fit _Horizontally"),                "H",                    N_("Fit Horizontally"),                 CB(layout_menu_zoom_fit_hor_cb) },
1346   { "ZoomFillVert",     NULL,                   N_("Fit _Vertically"),                  "W",                    N_("Fit Vertically"),                   CB(layout_menu_zoom_fit_vert_cb) },
1347   { "Zoom200",          NULL,                   N_("Zoom _2:1"),                        NULL,                   N_("Zoom 2:1"),                         CB(layout_menu_zoom_2_1_cb) },
1348   { "Zoom300",          NULL,                   N_("Zoom _3:1"),                        NULL,                   N_("Zoom 3:1"),                         CB(layout_menu_zoom_3_1_cb) },
1349   { "Zoom400",          NULL,                   N_("Zoom _4:1"),                        NULL,                   N_("Zoom 4:1"),                         CB(layout_menu_zoom_4_1_cb) },
1350   { "Zoom50",           NULL,                   N_("Zoom 1:2"),                         NULL,                   N_("Zoom 1:2"),                         CB(layout_menu_zoom_1_2_cb) },
1351   { "Zoom33",           NULL,                   N_("Zoom 1:3"),                         NULL,                   N_("Zoom 1:3"),                         CB(layout_menu_zoom_1_3_cb) },
1352   { "Zoom25",           NULL,                   N_("Zoom 1:4"),                         NULL,                   N_("Zoom 1:4"),                         CB(layout_menu_zoom_1_4_cb) },
1353   { "ConnectZoomIn",    GTK_STOCK_ZOOM_IN,      N_("Zoom _in"),                         "plus",                 N_("Connected Zoom in"),                CB(layout_menu_connect_zoom_in_cb) },
1354   { "ConnectZoomInAlt1",GTK_STOCK_ZOOM_IN,      N_("Zoom _in"),                         "<shift>KP_Add",        N_("Connected Zoom in"),                CB(layout_menu_connect_zoom_in_cb) },
1355   { "ConnectZoomOut",   GTK_STOCK_ZOOM_OUT,     N_("Zoom _out"),                        "underscore",           N_("Connected Zoom out"),               CB(layout_menu_connect_zoom_out_cb) },
1356   { "ConnectZoomOutAlt1",GTK_STOCK_ZOOM_OUT,    N_("Zoom _out"),                        "<shift>KP_Subtract",   N_("Connected Zoom out"),               CB(layout_menu_connect_zoom_out_cb) },
1357   { "ConnectZoom100",   GTK_STOCK_ZOOM_100,     N_("Zoom _1:1"),                        "<shift>Z",             N_("Connected Zoom 1:1"),               CB(layout_menu_connect_zoom_1_1_cb) },
1358   { "ConnectZoom100Alt1",GTK_STOCK_ZOOM_100,    N_("Zoom _1:1"),                        "<shift>KP_Divide",     N_("Connected Zoom 1:1"),               CB(layout_menu_connect_zoom_1_1_cb) },
1359   { "ConnectZoomFit",   GTK_STOCK_ZOOM_FIT,     N_("_Zoom to fit"),                     "<shift>X",             N_("Connected Zoom to fit"),            CB(layout_menu_connect_zoom_fit_cb) },
1360   { "ConnectZoomFitAlt1",GTK_STOCK_ZOOM_FIT,    N_("_Zoom to fit"),                     "<shift>KP_Multiply",   N_("Connected Zoom to fit"),            CB(layout_menu_connect_zoom_fit_cb) },
1361   { "ConnectZoomFillHor",NULL,                  N_("Fit _Horizontally"),                "<shift>H",             N_("Connected Fit Horizontally"),       CB(layout_menu_connect_zoom_fit_hor_cb) },
1362   { "ConnectZoomFillVert",NULL,                 N_("Fit _Vertically"),                  "<shift>W",             N_("Connected Fit Vertically"),         CB(layout_menu_connect_zoom_fit_vert_cb) },
1363   { "ConnectZoom200",   NULL,                   N_("Zoom _2:1"),                        NULL,                   N_("Connected Zoom 2:1"),               CB(layout_menu_connect_zoom_2_1_cb) },
1364   { "ConnectZoom300",   NULL,                   N_("Zoom _3:1"),                        NULL,                   N_("Connected Zoom 3:1"),               CB(layout_menu_connect_zoom_3_1_cb) },
1365   { "ConnectZoom400",   NULL,                   N_("Zoom _4:1"),                        NULL,                   N_("Connected Zoom 4:1"),               CB(layout_menu_connect_zoom_4_1_cb) },
1366   { "ConnectZoom50",    NULL,                   N_("Zoom 1:2"),                         NULL,                   N_("Connected Zoom 1:2"),               CB(layout_menu_connect_zoom_1_2_cb) },
1367   { "ConnectZoom33",    NULL,                   N_("Zoom 1:3"),                         NULL,                   N_("Connected Zoom 1:3"),               CB(layout_menu_connect_zoom_1_3_cb) },
1368   { "ConnectZoom25",    NULL,                   N_("Zoom 1:4"),                         NULL,                   N_("Connected Zoom 1:4"),               CB(layout_menu_connect_zoom_1_4_cb) },
1369   { "ViewInNewWindow",  NULL,                   N_("_View in new window"),              "<control>V",           N_("View in new window"),               CB(layout_menu_view_in_new_window_cb) },
1370   { "FullScreen",       GTK_STOCK_FULLSCREEN,   N_("F_ull screen"),                     "F",                    N_("Full screen"),                      CB(layout_menu_fullscreen_cb) },
1371   { "FullScreenAlt1",   GTK_STOCK_FULLSCREEN,   N_("F_ull screen"),                     "V",                    N_("Full screen"),                      CB(layout_menu_fullscreen_cb) },
1372   { "FullScreenAlt2",   GTK_STOCK_FULLSCREEN,   N_("F_ull screen"),                     "F11",                  N_("Full screen"),                      CB(layout_menu_fullscreen_cb) },
1373   { "Escape",           GTK_STOCK_LEAVE_FULLSCREEN,N_("_Leave full screen"),            "Escape",               N_("Leave full screen"),                CB(layout_menu_escape_cb) },
1374   { "EscapeAlt1",       GTK_STOCK_LEAVE_FULLSCREEN,N_("_Leave full screen"),            "Q",                    N_("Leave full screen"),                CB(layout_menu_escape_cb) },
1375   { "ImageOverlayCycle",NULL,                   N_("_Cycle through overlay modes"),     "I",                    N_("Cycle through Overlay modes"),      CB(layout_menu_overlay_toggle_cb) },
1376   { "HistogramChanCycle",NULL,                  N_("Cycle through histogram ch_annels"),"K",                    N_("Cycle through histogram channels"), CB(layout_menu_histogram_toggle_channel_cb) },
1377   { "HistogramModeCycle",NULL,                  N_("Cycle through histogram mo_des"),   "J",                    N_("Cycle through histogram modes"),    CB(layout_menu_histogram_toggle_mode_cb) },
1378   { "HideTools",        NULL,                   N_("_Hide file list"),                  "<control>H",           N_("Hide file list"),                   CB(layout_menu_hide_cb) },
1379   { "SlideShowPause",   GTK_STOCK_MEDIA_PAUSE,  N_("_Pause slideshow"),                 "P",                    N_("Pause slideshow"),                  CB(layout_menu_slideshow_pause_cb) },
1380   { "Refresh",          GTK_STOCK_REFRESH,      N_("_Refresh"),                         "R",                    N_("Refresh"),                          CB(layout_menu_refresh_cb) },
1381   { "HelpContents",     GTK_STOCK_HELP,         N_("_Contents"),                        "F1",                   N_("Contents"),                         CB(layout_menu_help_cb) },
1382   { "HelpShortcuts",    NULL,                   N_("_Keyboard shortcuts"),              NULL,                   N_("Keyboard shortcuts"),               CB(layout_menu_help_keys_cb) },
1383   { "HelpNotes",        NULL,                   N_("_Release notes"),                   NULL,                   N_("Release notes"),                    CB(layout_menu_notes_cb) },
1384   { "About",            GTK_STOCK_ABOUT,        N_("_About"),                           NULL,                   N_("About"),                            CB(layout_menu_about_cb) },
1385   { "LogWindow",        NULL,                   N_("_Log Window"),                      NULL,                   N_("Log Window"),                       CB(layout_menu_log_window_cb) },
1386   { "ExifWin",          NULL,                   N_("_Exif window"),                     "<control>E",           N_("Exif window"),                      CB(layout_menu_bar_exif_cb) },
1387   { "StereoCycle",      NULL,                   N_("_Cycle through stereo modes"),      NULL,                   N_("Cycle through stereo modes"),       CB(layout_menu_stereo_mode_next_cb) },
1388
1389 };
1390
1391 static GtkToggleActionEntry menu_toggle_entries[] = {
1392   { "Thumbnails",       PIXBUF_INLINE_ICON_THUMB,N_("Show _Thumbnails"),                "T",                    N_("Show Thumbnails"),                  CB(layout_menu_thumb_cb),        FALSE },
1393   { "ShowMarks",        NULL,                   N_("Show _Marks"),                      "M",                    N_("Show Marks"),                       CB(layout_menu_marks_cb),        FALSE  },
1394   { "ShowInfoPixel",    GTK_STOCK_COLOR_PICKER, N_("Pi_xel Info"),                      NULL,                   N_("Show Pixel Info"),                  CB(layout_menu_info_pixel_cb),   FALSE  },
1395   { "FloatTools",       PIXBUF_INLINE_ICON_FLOAT,N_("_Float file list"),                "L",                    N_("Float file list"),                  CB(layout_menu_float_cb),        FALSE  },
1396   { "HideToolbar",      NULL,                   N_("Hide tool_bar"),                    NULL,                   N_("Hide toolbar"),                     CB(layout_menu_toolbar_cb),      FALSE  },
1397   { "SBar",             NULL,                   N_("_Info sidebar"),                    "<control>K",           N_("Info sidebar"),                     CB(layout_menu_bar_cb),          FALSE  },
1398   { "SBarSort",         NULL,                   N_("Sort _manager"),                    "<shift>S",             N_("Sort manager"),                     CB(layout_menu_bar_sort_cb),     FALSE  },
1399   { "SlideShow",        GTK_STOCK_MEDIA_PLAY,   N_("Toggle _slideshow"),                "S",                    N_("Toggle slideshow"),                 CB(layout_menu_slideshow_cb),    FALSE  },
1400   { "UseColorProfiles", GTK_STOCK_SELECT_COLOR, N_("Use _color profiles"),              NULL,                   N_("Use color profiles"),               CB(layout_color_menu_enable_cb), FALSE},
1401   { "UseImageProfile",  NULL,                   N_("Use profile from _image"),          NULL,                   N_("Use profile from image"),           CB(layout_color_menu_use_image_cb), FALSE},
1402   { "Grayscale",        NULL,                   N_("Toggle _grayscale"),                "<shift>G",             N_("Toggle grayscale"),                 CB(layout_menu_alter_desaturate_cb), FALSE},
1403   { "ImageOverlay",     NULL,                   N_("Image _Overlay"),                   NULL,                   N_("Image Overlay"),                    CB(layout_menu_overlay_cb),      FALSE },
1404   { "ImageHistogram",   NULL,                   N_("_Show Histogram"),                  NULL,                   N_("Show Histogram"),                   CB(layout_menu_histogram_cb),    FALSE },
1405 };
1406
1407 static GtkRadioActionEntry menu_radio_entries[] = {
1408   { "ViewList",         NULL,                   N_("Image _List"),                      "<control>L",           N_("View Images as List"),              FILEVIEW_LIST },
1409   { "ViewIcons",        NULL,                   N_("I_cons"),                           "<control>I",           N_("View Images as Icons"),             FILEVIEW_ICON }
1410 };
1411
1412 static GtkRadioActionEntry menu_view_dir_radio_entries[] = {
1413   { "FolderList",       NULL,                   N_("Folder Li_st"),                     "<meta>L",              N_("View Folders as List"),             DIRVIEW_LIST },
1414   { "FolderTree",       NULL,                   N_("Folder T_ree"),                     "<control>T",           N_("View Folders as Tree"),             DIRVIEW_TREE },
1415 };
1416
1417 static GtkRadioActionEntry menu_split_radio_entries[] = {
1418   { "SplitHorizontal",  NULL,                   N_("_Horizontal"),                      "E",                    N_("Split Horizontal"),                 SPLIT_HOR },
1419   { "SplitVertical",    NULL,                   N_("_Vertical"),                        "U",                    N_("Split Vertical"),                           SPLIT_VERT },
1420   { "SplitQuad",        NULL,                   N_("_Quad"),                            NULL,                   N_("Split Quad"),                               SPLIT_QUAD },
1421   { "SplitSingle",      NULL,                   N_("_Single"),                          "Y",                    N_("Split Single"),                             SPLIT_NONE }
1422 };
1423
1424 static GtkRadioActionEntry menu_color_radio_entries[] = {
1425   { "ColorProfile0",    NULL,                   N_("Input _0: sRGB"),                   NULL,                   N_("Input 0: sRGB"),                    COLOR_PROFILE_SRGB },
1426   { "ColorProfile1",    NULL,                   N_("Input _1: AdobeRGB compatible"),    NULL,                   N_("Input 1: AdobeRGB compatible"),     COLOR_PROFILE_ADOBERGB },
1427   { "ColorProfile2",    NULL,                   N_("Input _2"),                         NULL,                   N_("Input 2"),                          COLOR_PROFILE_FILE },
1428   { "ColorProfile3",    NULL,                   N_("Input _3"),                         NULL,                   N_("Input 3"),                          COLOR_PROFILE_FILE + 1 },
1429   { "ColorProfile4",    NULL,                   N_("Input _4"),                         NULL,                   N_("Input 4"),                          COLOR_PROFILE_FILE + 2 },
1430   { "ColorProfile5",    NULL,                   N_("Input _5"),                         NULL,                   N_("Input 5"),                          COLOR_PROFILE_FILE + 3 }
1431 };
1432
1433 static GtkRadioActionEntry menu_histogram_channel[] = {
1434   { "HistogramChanR",   NULL,                   N_("Histogram on _Red"),                NULL,                   N_("Histogram on Red"),         HCHAN_R },
1435   { "HistogramChanG",   NULL,                   N_("Histogram on _Green"),              NULL,                   N_("Histogram on Green"),       HCHAN_G },
1436   { "HistogramChanB",   NULL,                   N_("Histogram on _Blue"),               NULL,                   N_("Histogram on Blue"),        HCHAN_B },
1437   { "HistogramChanRGB", NULL,                   N_("_Histogram on RGB"),                        NULL,                   N_("Histogram on RGB"),         HCHAN_RGB },
1438   { "HistogramChanV",   NULL,                   N_("Histogram on _Value"),              NULL,                   N_("Histogram on Value"),       HCHAN_MAX }
1439 };
1440
1441 static GtkRadioActionEntry menu_histogram_mode[] = {
1442   { "HistogramModeLin", NULL,                   N_("Li_near Histogram"),                NULL,                   N_("Linear Histogram"),         0 },
1443   { "HistogramModeLog", NULL,                   N_("_Log Histogram"),                   NULL,                   N_("Log Histogram"),            1 },
1444 };
1445
1446 static GtkRadioActionEntry menu_stereo_mode_entries[] = {
1447   { "StereoAuto",       NULL,                   N_("_Auto"),                            NULL,                   N_("Stereo Auto"),              STEREO_PIXBUF_DEFAULT },
1448   { "StereoSBS",        NULL,                   N_("_Side by Side"),                    NULL,                   N_("Stereo Side by Side"),      STEREO_PIXBUF_SBS },
1449   { "StereoCross",      NULL,                   N_("_Cross"),                           NULL,                   N_("Stereo Cross"),             STEREO_PIXBUF_CROSS },
1450   { "StereoOff",        NULL,                   N_("_Off"),                             NULL,                   N_("Stereo Off"),               STEREO_PIXBUF_NONE }
1451 };
1452
1453
1454 #undef CB
1455
1456 static const gchar *menu_ui_description =
1457 "<ui>"
1458 "  <menubar name='MainMenu'>"
1459 "    <menu action='FileMenu'>"
1460 "      <menuitem action='NewWindow'/>"
1461 "      <menuitem action='NewCollection'/>"
1462 "      <menuitem action='OpenCollection'/>"
1463 "      <menuitem action='OpenRecent'/>"
1464 "      <placeholder name='OpenSection'/>"
1465 "      <separator/>"
1466 "      <menuitem action='Search'/>"
1467 "      <menuitem action='FindDupes'/>"
1468 "      <placeholder name='SearchSection'/>"
1469 "      <separator/>"
1470 "      <menuitem action='Print'/>"
1471 "      <placeholder name='PrintSection'/>"
1472 "      <separator/>"
1473 "      <menuitem action='NewFolder'/>"
1474 "      <menuitem action='Copy'/>"
1475 "      <menuitem action='Move'/>"
1476 "      <menuitem action='Rename'/>"
1477 "      <menuitem action='Delete'/>"
1478 "      <placeholder name='FileOpsSection'/>"
1479 "      <separator/>"
1480 "      <placeholder name='QuitSection'/>"
1481 "      <menuitem action='CloseWindow'/>"
1482 "      <menuitem action='Quit'/>"
1483 "      <separator/>"
1484 "    </menu>"
1485 "    <menu action='GoMenu'>"
1486 "      <menuitem action='FirstImage'/>"
1487 "      <menuitem action='PrevImage'/>"
1488 "      <menuitem action='NextImage'/>"
1489 "      <menuitem action='LastImage'/>"
1490 "      <separator/>"
1491 "      <menuitem action='Back'/>"
1492 "      <menuitem action='Home'/>"
1493 "      <separator/>"
1494 "    </menu>"
1495 "    <menu action='SelectMenu'>"
1496 "      <menuitem action='SelectAll'/>"
1497 "      <menuitem action='SelectNone'/>"
1498 "      <menuitem action='SelectInvert'/>"
1499 "      <placeholder name='SelectSection'/>"
1500 "      <separator/>"
1501 "      <menuitem action='CopyPath'/>"
1502 "      <placeholder name='ClipboardSection'/>"
1503 "      <separator/>"
1504 "      <menuitem action='ShowMarks'/>"
1505 "      <placeholder name='MarksSection'/>"
1506 "      <separator/>"
1507 "    </menu>"
1508 "    <menu action='EditMenu'>"
1509 "      <menu action='ExternalMenu'>"
1510 "      </menu>"
1511 "      <placeholder name='EditSection'/>"
1512 "      <separator/>"
1513 "      <menu action='OrientationMenu'>"
1514 "        <menuitem action='RotateCW'/>"
1515 "        <menuitem action='RotateCCW'/>"
1516 "        <menuitem action='Rotate180'/>"
1517 "        <menuitem action='Mirror'/>"
1518 "        <menuitem action='Flip'/>"
1519 "        <menuitem action='AlterNone'/>"
1520 "      </menu>"
1521 "      <menuitem action='SaveMetadata'/>"
1522 "      <placeholder name='PropertiesSection'/>"
1523 "      <separator/>"
1524 "        <menu action='PreferencesMenu'>"
1525 "        <menuitem action='Preferences'/>"
1526 "        <menuitem action='Editors'/>"
1527 "        <menuitem action='LayoutConfig'/>"
1528 "        <menuitem action='Maintenance'/>"
1529 "      </menu>"
1530 "      <placeholder name='PreferencesSection'/>"
1531 "      <separator/>"
1532 "      <menuitem action='Wallpaper'/>"
1533 "      <separator/>"
1534 "    </menu>"
1535 "    <menu action='ViewMenu'>"
1536 "      <menuitem action='ViewInNewWindow'/>"
1537 "      <menuitem action='PanView'/>"
1538 "      <menuitem action='ExifWin'/>"
1539 "      <placeholder name='WindowSection'/>"
1540 "      <separator/>"
1541 "      <menu action='FileDirMenu'>"
1542 "        <menuitem action='FolderList'/>"
1543 "        <menuitem action='FolderTree'/>"
1544 "        <placeholder name='FolderSection'/>"
1545 "        <separator/>"
1546 "        <menuitem action='ViewList'/>"
1547 "        <menuitem action='ViewIcons'/>"
1548 "        <menuitem action='Thumbnails'/>"
1549 "        <placeholder name='ListSection'/>"
1550 "        <separator/>"
1551 "        <menuitem action='FloatTools'/>"
1552 "        <menuitem action='HideTools'/>"
1553 "        <menuitem action='HideToolbar'/>"
1554 "      </menu>"
1555 "      <placeholder name='DirSection'/>"
1556 "      <separator/>"
1557 "      <menu action='ZoomMenu'>"
1558 "        <menu action='ConnectZoomMenu'>"
1559 "          <menuitem action='ConnectZoomIn'/>"
1560 "          <menuitem action='ConnectZoomOut'/>"
1561 "          <menuitem action='ConnectZoomFit'/>"
1562 "          <menuitem action='ConnectZoomFillHor'/>"
1563 "          <menuitem action='ConnectZoomFillVert'/>"
1564 "          <menuitem action='ConnectZoom100'/>"
1565 "          <menuitem action='ConnectZoom200'/>"
1566 "          <menuitem action='ConnectZoom300'/>"
1567 "          <menuitem action='ConnectZoom400'/>"
1568 "          <menuitem action='ConnectZoom50'/>"
1569 "          <menuitem action='ConnectZoom33'/>"
1570 "          <menuitem action='ConnectZoom25'/>"
1571 "        </menu>"
1572 "        <menuitem action='ZoomIn'/>"
1573 "        <menuitem action='ZoomOut'/>"
1574 "        <menuitem action='ZoomFit'/>"
1575 "        <menuitem action='ZoomFillHor'/>"
1576 "        <menuitem action='ZoomFillVert'/>"
1577 "        <menuitem action='Zoom100'/>"
1578 "        <menuitem action='Zoom200'/>"
1579 "        <menuitem action='Zoom300'/>"
1580 "        <menuitem action='Zoom400'/>"
1581 "        <menuitem action='Zoom50'/>"
1582 "        <menuitem action='Zoom33'/>"
1583 "        <menuitem action='Zoom25'/>"
1584 "      </menu>"
1585 "      <menu action='SplitMenu'>"
1586 "        <menuitem action='SplitHorizontal'/>"
1587 "        <menuitem action='SplitVertical'/>"
1588 "        <menuitem action='SplitQuad'/>"
1589 "        <menuitem action='SplitSingle'/>"
1590 "      </menu>"
1591 "      <menu action='StereoMenu'>"
1592 "        <menuitem action='StereoAuto'/>"
1593 "        <menuitem action='StereoSBS'/>"
1594 "        <menuitem action='StereoCross'/>"
1595 "        <menuitem action='StereoOff'/>"
1596 "        <separator/>"
1597 "        <menuitem action='StereoCycle'/>"
1598 "      </menu>"
1599 "      <menu action='ColorMenu'>"
1600 "        <menuitem action='UseColorProfiles'/>"
1601 "        <menuitem action='UseImageProfile'/>"
1602 "        <menuitem action='ColorProfile0'/>"
1603 "        <menuitem action='ColorProfile1'/>"
1604 "        <menuitem action='ColorProfile2'/>"
1605 "        <menuitem action='ColorProfile3'/>"
1606 "        <menuitem action='ColorProfile4'/>"
1607 "        <menuitem action='ColorProfile5'/>"
1608 "        <separator/>"
1609 "        <menuitem action='Grayscale'/>"
1610 "      </menu>"
1611 "      <menu action='OverlayMenu'>"
1612 "        <menuitem action='ImageOverlay'/>"
1613 "        <menuitem action='ImageHistogram'/>"
1614 "        <menuitem action='ImageOverlayCycle'/>"
1615 "        <separator/>"
1616 "        <menuitem action='HistogramChanR'/>"
1617 "        <menuitem action='HistogramChanG'/>"
1618 "        <menuitem action='HistogramChanB'/>"
1619 "        <menuitem action='HistogramChanRGB'/>"
1620 "        <menuitem action='HistogramChanV'/>"
1621 "        <menuitem action='HistogramChanCycle'/>"
1622 "        <separator/>"
1623 "        <menuitem action='HistogramModeLin'/>"
1624 "        <menuitem action='HistogramModeLog'/>"
1625 "        <menuitem action='HistogramModeCycle'/>"
1626 "      </menu>"
1627 "      <menuitem action='FullScreen'/>"
1628 "      <placeholder name='ViewSection'/>"
1629 "      <separator/>"
1630 "      <menuitem action='SBar'/>"
1631 "      <menuitem action='SBarSort'/>"
1632 "      <menuitem action='ShowInfoPixel'/>"
1633 "      <placeholder name='ToolsSection'/>"
1634 "      <separator/>"
1635 "      <menuitem action='SlideShow'/>"
1636 "      <menuitem action='SlideShowPause'/>"
1637 "      <menuitem action='Refresh'/>"
1638 "      <placeholder name='SlideShowSection'/>"
1639 "      <separator/>"
1640 "    </menu>"
1641 "    <menu action='HelpMenu'>"
1642 "      <separator/>"
1643 "      <menuitem action='HelpContents'/>"
1644 "      <menuitem action='HelpShortcuts'/>"
1645 "      <menuitem action='HelpNotes'/>"
1646 "      <placeholder name='HelpSection'/>"
1647 "      <separator/>"
1648 "      <menuitem action='About'/>"
1649 "      <separator/>"
1650 "      <menuitem action='LogWindow'/>"
1651 "      <separator/>"
1652 "    </menu>"
1653 "  </menubar>"
1654 "  <toolbar name='ToolBar'>"
1655 "  </toolbar>"
1656 "  <toolbar name='StatusBar'>"
1657 "  </toolbar>"
1658 "<accelerator action='PrevImageAlt1'/>"
1659 "<accelerator action='PrevImageAlt2'/>"
1660 "<accelerator action='NextImageAlt1'/>"
1661 "<accelerator action='NextImageAlt2'/>"
1662 "<accelerator action='DeleteAlt1'/>"
1663 "<accelerator action='DeleteAlt2'/>"
1664 "<accelerator action='FullScreenAlt1'/>"
1665 "<accelerator action='FullScreenAlt2'/>"
1666 "<accelerator action='Escape'/>"
1667 "<accelerator action='EscapeAlt1'/>"
1668
1669 "<accelerator action='ZoomInAlt1'/>"
1670 "<accelerator action='ZoomOutAlt1'/>"
1671 "<accelerator action='Zoom100Alt1'/>"
1672 "<accelerator action='ZoomFitAlt1'/>"
1673
1674 "<accelerator action='ConnectZoomInAlt1'/>"
1675 "<accelerator action='ConnectZoomOutAlt1'/>"
1676 "<accelerator action='ConnectZoom100Alt1'/>"
1677 "<accelerator action='ConnectZoomFitAlt1'/>"
1678 "</ui>";
1679
1680 static gchar *menu_translate(const gchar *path, gpointer data)
1681 {
1682         return (gchar *)(_(path));
1683 }
1684
1685 static void layout_actions_setup_mark(LayoutWindow *lw, gint mark, gchar *name_tmpl,
1686                                       gchar *label_tmpl, gchar *accel_tmpl, gchar *tooltip_tmpl, GCallback cb)
1687 {
1688         gchar name[50];
1689         gchar label[100];
1690         gchar accel[50];
1691         gchar tooltip[100];
1692         GtkActionEntry entry = { name, NULL, label, accel, tooltip, cb };
1693         GtkAction *action;
1694
1695         g_snprintf(name, sizeof(name), name_tmpl, mark);
1696         g_snprintf(label, sizeof(label), label_tmpl, mark);
1697                 
1698         if (accel_tmpl)
1699                 g_snprintf(accel, sizeof(accel), accel_tmpl, mark % 10);
1700         else
1701                 entry.accelerator = NULL;
1702
1703         if (tooltip_tmpl)
1704                 g_snprintf(tooltip, sizeof(tooltip), tooltip_tmpl, mark);
1705         else
1706                 entry.tooltip = NULL;
1707                 
1708         gtk_action_group_add_actions(lw->action_group, &entry, 1, lw);
1709         action = gtk_action_group_get_action(lw->action_group, name);
1710         g_object_set_data(G_OBJECT(action), "mark_num", GINT_TO_POINTER(mark));
1711 }
1712
1713 static void layout_actions_setup_marks(LayoutWindow *lw)
1714 {
1715         gint mark;
1716         GError *error;
1717         GString *desc = g_string_new(
1718                                 "<ui>"
1719                                 "  <menubar name='MainMenu'>"
1720                                 "    <menu action='SelectMenu'>");
1721
1722         for (mark = 1; mark <= FILEDATA_MARKS_SIZE; mark++)
1723                 {
1724                 layout_actions_setup_mark(lw, mark, "Mark%d",           _("Mark _%d"), NULL, NULL, NULL);
1725                 layout_actions_setup_mark(lw, mark, "SetMark%d",        _("_Set mark %d"),                      NULL,           _("Set mark %d"), G_CALLBACK(layout_menu_set_mark_sel_cb));
1726                 layout_actions_setup_mark(lw, mark, "ResetMark%d",      _("_Reset mark %d"),                    NULL,           _("Reset mark %d"), G_CALLBACK(layout_menu_res_mark_sel_cb));
1727                 layout_actions_setup_mark(lw, mark, "ToggleMark%d",     _("_Toggle mark %d"),                   "%d",           _("Toggle mark %d"), G_CALLBACK(layout_menu_toggle_mark_sel_cb));
1728                 layout_actions_setup_mark(lw, mark, "ToggleMark%dAlt1", _("_Toggle mark %d"),                   "KP_%d",        _("Toggle mark %d"), G_CALLBACK(layout_menu_toggle_mark_sel_cb));
1729                 layout_actions_setup_mark(lw, mark, "SelectMark%d",     _("Se_lect mark %d"),                   "<control>%d",  _("Select mark %d"), G_CALLBACK(layout_menu_sel_mark_cb));
1730                 layout_actions_setup_mark(lw, mark, "SelectMark%dAlt1", _("_Select mark %d"),                   "<control>KP_%d", _("Select mark %d"), G_CALLBACK(layout_menu_sel_mark_cb));
1731                 layout_actions_setup_mark(lw, mark, "AddMark%d",        _("_Add mark %d"),                      NULL,           _("Add mark %d"), G_CALLBACK(layout_menu_sel_mark_or_cb));
1732                 layout_actions_setup_mark(lw, mark, "IntMark%d",        _("_Intersection with mark %d"),        NULL,           _("Intersection with mark %d"), G_CALLBACK(layout_menu_sel_mark_and_cb));
1733                 layout_actions_setup_mark(lw, mark, "UnselMark%d",      _("_Unselect mark %d"),                 NULL,           _("Unselect mark %d"), G_CALLBACK(layout_menu_sel_mark_minus_cb));
1734                 layout_actions_setup_mark(lw, mark, "FilterMark%d",     _("_Filter mark %d"),                   NULL,           _("Filter mark %d"), G_CALLBACK(layout_menu_mark_filter_toggle_cb));
1735
1736                 g_string_append_printf(desc,
1737                                 "      <menu action='Mark%d'>"
1738                                 "        <menuitem action='ToggleMark%d'/>"
1739                                 "        <menuitem action='SetMark%d'/>"
1740                                 "        <menuitem action='ResetMark%d'/>"
1741                                 "        <separator/>"
1742                                 "        <menuitem action='SelectMark%d'/>"
1743                                 "        <menuitem action='AddMark%d'/>"
1744                                 "        <menuitem action='IntMark%d'/>"
1745                                 "        <menuitem action='UnselMark%d'/>"
1746                                 "        <separator/>"
1747                                 "        <menuitem action='FilterMark%d'/>"
1748                                 "      </menu>",
1749                                 mark, mark, mark, mark, mark, mark, mark, mark, mark);
1750                 }
1751
1752         g_string_append(desc,
1753                                 "    </menu>"
1754                                 "  </menubar>");
1755         for (mark = 1; mark <= FILEDATA_MARKS_SIZE; mark++)
1756                 {
1757                 g_string_append_printf(desc,
1758                                 "<accelerator action='ToggleMark%dAlt1'/>"
1759                                 "<accelerator action='SelectMark%dAlt1'/>",
1760                                 mark, mark);
1761                 }
1762         g_string_append(desc,   "</ui>" );
1763
1764         error = NULL;
1765         if (!gtk_ui_manager_add_ui_from_string(lw->ui_manager, desc->str, -1, &error))
1766                 {
1767                 g_message("building menus failed: %s", error->message);
1768                 g_error_free(error);
1769                 exit(EXIT_FAILURE);
1770                 }
1771         g_string_free(desc, TRUE);
1772 }
1773
1774 static GList *layout_actions_editor_menu_path(EditorDescription *editor)
1775 {
1776         gchar **split = g_strsplit(editor->menu_path, "/", 0);
1777         gint i = 0;
1778         GList *ret = NULL;
1779         
1780         if (split[0] == NULL) 
1781                 {
1782                 g_strfreev(split);
1783                 return NULL;
1784                 }
1785         
1786         while (split[i])
1787                 {
1788                 ret = g_list_prepend(ret, g_strdup(split[i]));
1789                 i++;
1790                 }
1791         
1792         g_strfreev(split);
1793         
1794         ret = g_list_prepend(ret, g_strdup(editor->key));
1795         
1796         return g_list_reverse(ret);
1797 }
1798
1799 static void layout_actions_editor_add(GString *desc, GList *path, GList *old_path)
1800 {
1801         gint to_open, to_close, i;
1802         while (path && old_path && strcmp((gchar *)path->data, (gchar *)old_path->data) == 0)
1803                 {
1804                 path = path->next;
1805                 old_path = old_path->next;
1806                 }
1807         to_open = g_list_length(path) - 1;
1808         to_close = g_list_length(old_path) - 1;
1809         
1810         if (to_close > 0)
1811                 {
1812                 old_path = g_list_last(old_path);
1813                 old_path = old_path->prev;
1814                 }
1815         
1816         for (i =  0; i < to_close; i++)
1817                 {
1818                 gchar *name = old_path->data;
1819                 if (g_str_has_suffix(name, "Section"))
1820                         {
1821                         g_string_append(desc,   "      </placeholder>");
1822                         }
1823                 else if (g_str_has_suffix(name, "Menu"))
1824                         {
1825                         g_string_append(desc,   "    </menu>");
1826                         }
1827                 else
1828                         {
1829                         g_warning("invalid menu path item %s", name);
1830                         }
1831                 old_path = old_path->prev;
1832                 }
1833
1834         for (i =  0; i < to_open; i++)
1835                 {
1836                 gchar *name = path->data;
1837                 if (g_str_has_suffix(name, "Section"))
1838                         {
1839                         g_string_append_printf(desc,    "      <placeholder name='%s'>", name);
1840                         }
1841                 else if (g_str_has_suffix(name, "Menu"))
1842                         {
1843                         g_string_append_printf(desc,    "    <menu action='%s'>", name);
1844                         }
1845                 else
1846                         {
1847                         g_warning("invalid menu path item %s", name);
1848                         }
1849                 path = path->next;
1850                 }
1851         
1852         if (path)
1853                 g_string_append_printf(desc, "      <menuitem action='%s'/>", (gchar *)path->data);
1854 }
1855
1856 static void layout_actions_setup_editors(LayoutWindow *lw)
1857 {
1858         GError *error;
1859         GList *editors_list;
1860         GList *work;
1861         GList *old_path;
1862         GString *desc;
1863         
1864         if (lw->ui_editors_id)
1865                 {
1866                 gtk_ui_manager_remove_ui(lw->ui_manager, lw->ui_editors_id);
1867                 }
1868
1869         if (lw->action_group_editors)
1870                 {
1871                 gtk_ui_manager_remove_action_group(lw->ui_manager, lw->action_group_editors);
1872                 g_object_unref(lw->action_group_editors);
1873                 }
1874         lw->action_group_editors = gtk_action_group_new("MenuActionsExternal");
1875         gtk_ui_manager_insert_action_group(lw->ui_manager, lw->action_group_editors, 1);
1876
1877         /* lw->action_group_editors contains translated entries, no translate func is required */
1878         desc = g_string_new(
1879                                 "<ui>"
1880                                 "  <menubar name='MainMenu'>");
1881
1882         editors_list = editor_list_get();
1883         
1884         old_path = NULL;
1885         work = editors_list;
1886         while (work)
1887                 {
1888                 GList *path;
1889                 EditorDescription *editor = work->data;
1890                 GtkActionEntry entry = { editor->key, 
1891                                          NULL,
1892                                          editor->name,
1893                                          editor->hotkey, 
1894                                          editor->comment ? editor->comment : editor->name,
1895                                          G_CALLBACK(layout_menu_edit_cb) };
1896                 
1897                 if (editor->icon)
1898                         {
1899                         entry.stock_id = editor->key;
1900                         }
1901                 gtk_action_group_add_actions(lw->action_group_editors, &entry, 1, lw);
1902                 
1903                 path = layout_actions_editor_menu_path(editor);
1904                 layout_actions_editor_add(desc, path, old_path);
1905                 
1906                 string_list_free(old_path);
1907                 old_path = path;
1908                 work = work->next;
1909                 }
1910
1911         layout_actions_editor_add(desc, NULL, old_path);
1912         string_list_free(old_path);
1913
1914         g_string_append(desc,   "  </menubar>"
1915                                 "</ui>" );
1916
1917         error = NULL;
1918         
1919         lw->ui_editors_id = gtk_ui_manager_add_ui_from_string(lw->ui_manager, desc->str, -1, &error);
1920         if (!lw->ui_editors_id)
1921                 {
1922                 g_message("building menus failed: %s", error->message);
1923                 g_error_free(error);
1924                 exit(EXIT_FAILURE);
1925                 }
1926         g_string_free(desc, TRUE);
1927         g_list_free(editors_list);
1928 }
1929
1930 void layout_actions_setup(LayoutWindow *lw)
1931 {
1932         GError *error;
1933         gint i;
1934
1935         DEBUG_1("%s layout_actions_setup: start", get_exec_time());
1936         if (lw->ui_manager) return;
1937
1938         lw->action_group = gtk_action_group_new("MenuActions");
1939         gtk_action_group_set_translate_func(lw->action_group, menu_translate, NULL, NULL);
1940
1941         gtk_action_group_add_actions(lw->action_group,
1942                                      menu_entries, G_N_ELEMENTS(menu_entries), lw);
1943         gtk_action_group_add_toggle_actions(lw->action_group,
1944                                             menu_toggle_entries, G_N_ELEMENTS(menu_toggle_entries), lw);
1945         gtk_action_group_add_radio_actions(lw->action_group,
1946                                            menu_radio_entries, G_N_ELEMENTS(menu_radio_entries),
1947                                            0, G_CALLBACK(layout_menu_list_cb), lw);
1948         gtk_action_group_add_radio_actions(lw->action_group,
1949                                            menu_split_radio_entries, G_N_ELEMENTS(menu_split_radio_entries),
1950                                            0, G_CALLBACK(layout_menu_split_cb), lw);
1951         gtk_action_group_add_radio_actions(lw->action_group,
1952                                            menu_view_dir_radio_entries, VIEW_DIR_TYPES_COUNT,
1953                                            0, G_CALLBACK(layout_menu_view_dir_as_cb), lw);
1954         gtk_action_group_add_radio_actions(lw->action_group,
1955                                            menu_color_radio_entries, COLOR_PROFILE_FILE + COLOR_PROFILE_INPUTS,
1956                                            0, G_CALLBACK(layout_color_menu_input_cb), lw);
1957         gtk_action_group_add_radio_actions(lw->action_group,
1958                                            menu_histogram_channel, G_N_ELEMENTS(menu_histogram_channel),
1959                                            0, G_CALLBACK(layout_menu_histogram_channel_cb), lw);
1960         gtk_action_group_add_radio_actions(lw->action_group,
1961                                            menu_histogram_mode, G_N_ELEMENTS(menu_histogram_mode),
1962                                            0, G_CALLBACK(layout_menu_histogram_mode_cb), lw);
1963         gtk_action_group_add_radio_actions(lw->action_group,
1964                                            menu_stereo_mode_entries, G_N_ELEMENTS(menu_stereo_mode_entries),
1965                                            0, G_CALLBACK(layout_menu_stereo_mode_cb), lw);
1966
1967
1968         lw->ui_manager = gtk_ui_manager_new();
1969         gtk_ui_manager_set_add_tearoffs(lw->ui_manager, TRUE);
1970         gtk_ui_manager_insert_action_group(lw->ui_manager, lw->action_group, 0);
1971
1972         DEBUG_1("%s layout_actions_setup: add menu", get_exec_time());
1973         error = NULL;
1974         if (!gtk_ui_manager_add_ui_from_string(lw->ui_manager, menu_ui_description, -1, &error))
1975                 {
1976                 g_message("building menus failed: %s", error->message);
1977                 g_error_free(error);
1978                 exit(EXIT_FAILURE);
1979                 }
1980         
1981         DEBUG_1("%s layout_actions_setup: add toolbar", get_exec_time());
1982         for (i = 0; i < TOOLBAR_COUNT; i++)
1983                 {
1984                 layout_toolbar_clear(lw, i);
1985                 layout_toolbar_add_default(lw, i);
1986                 }
1987         
1988
1989         DEBUG_1("%s layout_actions_setup: marks", get_exec_time());
1990         layout_actions_setup_marks(lw);
1991
1992         DEBUG_1("%s layout_actions_setup: editors", get_exec_time());
1993         layout_actions_setup_editors(lw);
1994
1995         DEBUG_1("%s layout_actions_setup: status_update_write", get_exec_time());
1996         layout_util_status_update_write(lw);
1997         
1998         DEBUG_1("%s layout_actions_setup: actions_add_window", get_exec_time());
1999         layout_actions_add_window(lw, lw->window);
2000         DEBUG_1("%s layout_actions_setup: end", get_exec_time());
2001 }
2002
2003 static gint layout_editors_reload_idle_id = -1;
2004 static GList *layout_editors_desktop_files = NULL;
2005
2006 static gboolean layout_editors_reload_idle_cb(gpointer data)
2007 {
2008         if (!layout_editors_desktop_files)
2009                 {
2010                 DEBUG_1("%s layout_editors_reload_idle_cb: get_desktop_files", get_exec_time());
2011                 layout_editors_desktop_files = editor_get_desktop_files();
2012                 return TRUE;
2013                 }
2014         
2015         editor_read_desktop_file(layout_editors_desktop_files->data);
2016         g_free(layout_editors_desktop_files->data);
2017         layout_editors_desktop_files = g_list_delete_link(layout_editors_desktop_files, layout_editors_desktop_files);
2018         
2019         
2020         if (!layout_editors_desktop_files)
2021                 {
2022                 GList *work;
2023                 DEBUG_1("%s layout_editors_reload_idle_cb: setup_editors", get_exec_time());
2024                 editor_table_finish();
2025
2026                 work = layout_window_list;
2027                 while (work)
2028                         {
2029                         LayoutWindow *lw = work->data;
2030                         work = work->next;
2031                         layout_actions_setup_editors(lw);
2032                         }
2033
2034                 DEBUG_1("%s layout_editors_reload_idle_cb: setup_editors done", get_exec_time());
2035                 
2036                 layout_editors_reload_idle_id = -1;
2037                 return FALSE;
2038                 }
2039         return TRUE;
2040 }
2041
2042 void layout_editors_reload_start(void)
2043 {
2044         GList *work;
2045
2046         DEBUG_1("%s layout_editors_reload_start", get_exec_time());
2047
2048         if (layout_editors_reload_idle_id != -1)
2049                 {
2050                 g_source_remove(layout_editors_reload_idle_id);
2051                 string_list_free(layout_editors_desktop_files);
2052                 }
2053
2054         work = layout_window_list;
2055
2056         editor_table_clear();
2057         layout_editors_reload_idle_id = g_idle_add(layout_editors_reload_idle_cb, NULL);
2058 }
2059         
2060 void layout_editors_reload_finish(void)
2061 {
2062         if (layout_editors_reload_idle_id != -1)
2063                 {
2064                 DEBUG_1("%s layout_editors_reload_finish", get_exec_time());
2065                 g_source_remove(layout_editors_reload_idle_id);
2066                 while (layout_editors_reload_idle_id != -1)
2067                         {
2068                         layout_editors_reload_idle_cb(NULL);
2069                         }
2070                 }
2071 }
2072
2073 void layout_actions_add_window(LayoutWindow *lw, GtkWidget *window)
2074 {
2075         GtkAccelGroup *group;
2076
2077         if (!lw->ui_manager) return;
2078
2079         group = gtk_ui_manager_get_accel_group(lw->ui_manager);
2080         gtk_window_add_accel_group(GTK_WINDOW(window), group);
2081 }
2082
2083 GtkWidget *layout_actions_menu_bar(LayoutWindow *lw)
2084 {
2085         if (lw->menu_bar) return lw->menu_bar;
2086         lw->menu_bar = gtk_ui_manager_get_widget(lw->ui_manager, "/MainMenu");
2087         g_object_ref(lw->menu_bar);
2088         return lw->menu_bar;
2089 }
2090
2091 GtkWidget *layout_actions_toolbar(LayoutWindow *lw, ToolbarType type)
2092 {
2093         if (lw->toolbar[type]) return lw->toolbar[type];
2094         switch (type)
2095                 {
2096                 case TOOLBAR_MAIN:
2097                         lw->toolbar[type] = gtk_ui_manager_get_widget(lw->ui_manager, "/ToolBar");
2098                         gtk_toolbar_set_icon_size(GTK_TOOLBAR(lw->toolbar[type]), GTK_ICON_SIZE_SMALL_TOOLBAR);
2099                         gtk_toolbar_set_style(GTK_TOOLBAR(lw->toolbar[type]), GTK_TOOLBAR_ICONS);
2100                         break;
2101                 case TOOLBAR_STATUS:
2102                         lw->toolbar[type] = gtk_ui_manager_get_widget(lw->ui_manager, "/StatusBar");
2103                         gtk_toolbar_set_icon_size(GTK_TOOLBAR(lw->toolbar[type]), GTK_ICON_SIZE_MENU);
2104                         gtk_toolbar_set_style(GTK_TOOLBAR(lw->toolbar[type]), GTK_TOOLBAR_ICONS);
2105                         gtk_toolbar_set_show_arrow(GTK_TOOLBAR(lw->toolbar[type]), FALSE);
2106                         break;
2107                 default:
2108                         break;
2109                 }
2110         g_object_ref(lw->toolbar[type]);
2111         return lw->toolbar[type];
2112 }
2113
2114 void layout_toolbar_clear(LayoutWindow *lw, ToolbarType type)
2115 {
2116         if (lw->toolbar_merge_id[type]) 
2117                 {
2118                 gtk_ui_manager_remove_ui(lw->ui_manager, lw->toolbar_merge_id[type]);
2119                 gtk_ui_manager_ensure_update(lw->ui_manager);
2120                 }
2121         string_list_free(lw->toolbar_actions[type]);
2122         lw->toolbar_actions[type] = NULL;
2123         
2124         lw->toolbar_merge_id[type] = gtk_ui_manager_new_merge_id(lw->ui_manager);
2125 }
2126         
2127
2128 void layout_toolbar_add(LayoutWindow *lw, ToolbarType type, const gchar *action)
2129 {
2130         const gchar *path = NULL;
2131         if (!action || !lw->ui_manager) return;
2132         
2133         if (g_list_find_custom(lw->toolbar_actions[type], action, (GCompareFunc)strcmp)) return;
2134
2135         switch (type)
2136                 {
2137                 case TOOLBAR_MAIN:
2138                         path = "/ToolBar";
2139                         break;
2140                 case TOOLBAR_STATUS:
2141                         path = "/StatusBar";
2142                         break;
2143                 default:
2144                         break;
2145                 }
2146         
2147         
2148         if (g_str_has_suffix(action, ".desktop"))
2149                 {
2150                 /* this may be called before the external editors are read
2151                    create a dummy action for now */
2152                   
2153                 if (!lw->action_group_editors)
2154                         {
2155                         lw->action_group_editors = gtk_action_group_new("MenuActionsExternal");
2156                         gtk_ui_manager_insert_action_group(lw->ui_manager, lw->action_group_editors, 1);
2157                         }
2158                 if (!gtk_action_group_get_action(lw->action_group_editors, action))
2159                         {
2160                         GtkActionEntry entry = { action, 
2161                                                  GTK_STOCK_MISSING_IMAGE,
2162                                                  action,
2163                                                  NULL, 
2164                                                  NULL,
2165                                                  NULL };
2166                         DEBUG_1("Creating temporary action %s", action);
2167                         gtk_action_group_add_actions(lw->action_group_editors, &entry, 1, lw);
2168                         }
2169                 }
2170         gtk_ui_manager_add_ui(lw->ui_manager, lw->toolbar_merge_id[type], path, action, action, GTK_UI_MANAGER_TOOLITEM, FALSE); 
2171         lw->toolbar_actions[type] = g_list_append(lw->toolbar_actions[type], g_strdup(action));
2172 }
2173
2174
2175 void layout_toolbar_add_default(LayoutWindow *lw, ToolbarType type)
2176 {
2177         switch (type)
2178                 {
2179                 case TOOLBAR_MAIN:
2180                         layout_toolbar_add(lw, type, "Thumbnails");
2181                         layout_toolbar_add(lw, type, "Back");
2182                         layout_toolbar_add(lw, type, "Home");
2183                         layout_toolbar_add(lw, type, "Refresh");
2184                         layout_toolbar_add(lw, type, "ZoomIn");
2185                         layout_toolbar_add(lw, type, "ZoomOut");
2186                         layout_toolbar_add(lw, type, "ZoomFit");
2187                         layout_toolbar_add(lw, type, "Zoom100");
2188                         layout_toolbar_add(lw, type, "Preferences");
2189                         layout_toolbar_add(lw, type, "FloatTools");
2190                         break;
2191                 case TOOLBAR_STATUS:
2192                         layout_toolbar_add(lw, type, "ShowInfoPixel");
2193                         layout_toolbar_add(lw, type, "UseColorProfiles");
2194                         layout_toolbar_add(lw, type, "SaveMetadata");
2195                         break;
2196                 default:
2197                         break;
2198                 }
2199 }
2200
2201 void layout_toolbar_write_config(LayoutWindow *lw, ToolbarType type, GString *outstr, gint indent)
2202 {
2203         const gchar *name = NULL;
2204         GList *work = lw->toolbar_actions[type];
2205
2206         switch (type)
2207                 {
2208                 case TOOLBAR_MAIN:
2209                         name = "toolbar";
2210                         break;
2211                 case TOOLBAR_STATUS:
2212                         name = "statusbar";
2213                         break;
2214                 default:
2215                         break;
2216                 }
2217
2218         WRITE_NL(); WRITE_STRING("<%s>", name);
2219         indent++;
2220         WRITE_NL(); WRITE_STRING("<clear/>");
2221         while (work)
2222                 {
2223                 gchar *action = work->data;
2224                 work = work->next;
2225                 WRITE_NL(); WRITE_STRING("<toolitem ");
2226                 write_char_option(outstr, indent + 1, "action", action);
2227                 WRITE_STRING("/>");
2228                 }
2229         indent--;
2230         WRITE_NL(); WRITE_STRING("</%s>", name);
2231 }
2232
2233 void layout_toolbar_add_from_config(LayoutWindow *lw, ToolbarType type, const gchar **attribute_names, const gchar **attribute_values)
2234 {
2235         gchar *action = NULL;
2236         
2237         while (*attribute_names)
2238                 {
2239                 const gchar *option = *attribute_names++;
2240                 const gchar *value = *attribute_values++;
2241
2242                 if (READ_CHAR_FULL("action", action)) continue;
2243
2244                 log_printf("unknown attribute %s = %s\n", option, value);
2245                 }
2246
2247         layout_toolbar_add(lw, type, action);
2248         g_free(action); 
2249 }
2250
2251 /*
2252  *-----------------------------------------------------------------------------
2253  * misc
2254  *-----------------------------------------------------------------------------
2255  */
2256
2257 void layout_util_status_update_write(LayoutWindow *lw)
2258 {
2259         GtkAction *action;
2260         gint n = metadata_queue_length();
2261         action = gtk_action_group_get_action(lw->action_group, "SaveMetadata");
2262         gtk_action_set_sensitive(action, n > 0);
2263         if (n > 0)
2264                 {
2265                 gchar *buf = g_strdup_printf(_("Number of files with unsaved metadata: %d"), n);
2266                 g_object_set(G_OBJECT(action), "tooltip", buf, NULL);
2267                 g_free(buf);
2268                 }
2269         else
2270                 {
2271                 g_object_set(G_OBJECT(action), "tooltip", _("No unsaved metadata"), NULL);
2272                 }
2273 }
2274
2275 void layout_util_status_update_write_all(void)
2276 {
2277         GList *work;
2278
2279         work = layout_window_list;
2280         while (work)
2281                 {
2282                 LayoutWindow *lw = work->data;
2283                 work = work->next;
2284
2285                 layout_util_status_update_write(lw);
2286                 }
2287 }
2288
2289 static gchar *layout_color_name_parse(const gchar *name)
2290 {
2291         if (!name || !*name) return g_strdup(_("Empty"));
2292         return g_strdelimit(g_strdup(name), "_", '-');
2293 }
2294
2295 void layout_util_sync_color(LayoutWindow *lw)
2296 {
2297         GtkAction *action;
2298         gint input = 0;
2299         gboolean use_color;
2300         gboolean use_image = FALSE;
2301         gint i;
2302         gchar action_name[15];
2303         gchar *image_profile;
2304         gchar *screen_profile;
2305
2306
2307         if (!lw->action_group) return;
2308         if (!layout_image_color_profile_get(lw, &input, &use_image)) return;
2309         
2310         use_color = layout_image_color_profile_get_use(lw);
2311
2312         action = gtk_action_group_get_action(lw->action_group, "UseColorProfiles");
2313 #ifdef HAVE_LCMS
2314         gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), use_color);
2315         if (layout_image_color_profile_get_status(lw, &image_profile, &screen_profile))
2316                 {
2317                 gchar *buf;
2318                 buf = g_strdup_printf(_("Image profile: %s\nScreen profile: %s"), image_profile, screen_profile);
2319                 g_object_set(G_OBJECT(action), "tooltip", buf, NULL);
2320                 g_free(image_profile);
2321                 g_free(screen_profile);
2322                 g_free(buf);
2323                 }
2324         else
2325                 {
2326                 g_object_set(G_OBJECT(action), "tooltip", _("Click to enable color management"), NULL);
2327                 }
2328 #else
2329         gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), FALSE);
2330         gtk_action_set_sensitive(action, FALSE);
2331         g_object_set(G_OBJECT(action), "tooltip", _("Color profiles not supported"), NULL);
2332 #endif
2333
2334         action = gtk_action_group_get_action(lw->action_group, "UseImageProfile");
2335         gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), use_image);
2336         gtk_action_set_sensitive(action, use_color);
2337
2338         for (i = 0; i < COLOR_PROFILE_FILE + COLOR_PROFILE_INPUTS; i++)
2339                 {
2340                 sprintf(action_name, "ColorProfile%d", i);
2341                 action = gtk_action_group_get_action(lw->action_group, action_name);
2342                 
2343                 if (i >= COLOR_PROFILE_FILE)
2344                         {
2345                         const gchar *name = options->color_profile.input_name[i - COLOR_PROFILE_FILE];
2346                         const gchar *file = options->color_profile.input_file[i - COLOR_PROFILE_FILE];
2347                         gchar *end;
2348                         gchar *buf;
2349
2350                         if (!name || !name[0]) name = filename_from_path(file);
2351
2352                         end = layout_color_name_parse(name);
2353                         buf = g_strdup_printf(_("Input _%d: %s"), i, end);
2354                         g_free(end);
2355
2356                         g_object_set(G_OBJECT(action), "label", buf, NULL);
2357                         g_free(buf);
2358
2359                         gtk_action_set_visible(action, file && file[0]);
2360                         }
2361
2362                 gtk_action_set_sensitive(action, !use_image);
2363                 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), (i == input));
2364                 }
2365
2366         action = gtk_action_group_get_action(lw->action_group, "Grayscale");
2367         gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), layout_image_get_desaturate(lw));
2368 }
2369
2370 static void layout_util_sync_views(LayoutWindow *lw)
2371 {
2372         GtkAction *action;
2373         OsdShowFlags osd_flags = image_osd_get(lw->image);
2374
2375         if (!lw->action_group) return;
2376
2377         action = gtk_action_group_get_action(lw->action_group, "FolderTree");
2378         radio_action_set_current_value(GTK_RADIO_ACTION(action), lw->options.dir_view_type);
2379
2380         action = gtk_action_group_get_action(lw->action_group, "SplitSingle");
2381         radio_action_set_current_value(GTK_RADIO_ACTION(action), lw->split_mode);
2382
2383         action = gtk_action_group_get_action(lw->action_group, "ViewIcons");
2384         radio_action_set_current_value(GTK_RADIO_ACTION(action), lw->options.file_view_type);
2385
2386         action = gtk_action_group_get_action(lw->action_group, "FloatTools");
2387         gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), lw->options.tools_float);
2388
2389         action = gtk_action_group_get_action(lw->action_group, "SBar");
2390         gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), layout_bar_enabled(lw));
2391
2392         action = gtk_action_group_get_action(lw->action_group, "SBarSort");
2393         gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), layout_bar_sort_enabled(lw));
2394
2395         action = gtk_action_group_get_action(lw->action_group, "HideToolbar");
2396         gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), lw->options.toolbar_hidden);
2397         
2398         action = gtk_action_group_get_action(lw->action_group, "ShowInfoPixel");
2399         gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), lw->options.show_info_pixel);
2400
2401         action = gtk_action_group_get_action(lw->action_group, "ShowMarks");
2402         gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), lw->options.show_marks);
2403
2404         action = gtk_action_group_get_action(lw->action_group, "SlideShow");
2405         gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), layout_image_slideshow_active(lw));
2406
2407         action = gtk_action_group_get_action(lw->action_group, "ImageOverlay");
2408         gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), osd_flags != OSD_SHOW_NOTHING);
2409
2410         action = gtk_action_group_get_action(lw->action_group, "ImageHistogram");
2411         gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), osd_flags & OSD_SHOW_HISTOGRAM);
2412
2413         if (osd_flags & OSD_SHOW_HISTOGRAM)
2414                 {
2415                 action = gtk_action_group_get_action(lw->action_group, "HistogramChanR");
2416                 radio_action_set_current_value(GTK_RADIO_ACTION(action), image_osd_histogram_get_channel(lw->image));
2417
2418                 action = gtk_action_group_get_action(lw->action_group, "HistogramModeLin");
2419                 radio_action_set_current_value(GTK_RADIO_ACTION(action), image_osd_histogram_get_mode(lw->image));
2420                 }
2421
2422         action = gtk_action_group_get_action(lw->action_group, "ConnectZoomMenu");
2423         gtk_action_set_sensitive(action, lw->split_mode != SPLIT_NONE);
2424
2425         action = gtk_action_group_get_action(lw->action_group, "StereoAuto");
2426         radio_action_set_current_value(GTK_RADIO_ACTION(action), layout_image_stereo_pixbuf_get(lw));
2427
2428         layout_util_sync_color(lw);
2429 }
2430
2431 void layout_util_sync_thumb(LayoutWindow *lw)
2432 {
2433         GtkAction *action;
2434
2435         if (!lw->action_group) return;
2436
2437         action = gtk_action_group_get_action(lw->action_group, "Thumbnails");
2438         gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), lw->options.show_thumbnails);
2439         g_object_set(action, "sensitive", (lw->options.file_view_type == FILEVIEW_LIST), NULL);
2440 }
2441
2442 void layout_util_sync(LayoutWindow *lw)
2443 {
2444         layout_util_sync_views(lw);
2445         layout_util_sync_thumb(lw);
2446         layout_menu_recent_update(lw);
2447 //      layout_menu_edit_update(lw);
2448 }
2449
2450
2451 /*
2452  *-----------------------------------------------------------------------------
2453  * sidebars
2454  *-----------------------------------------------------------------------------
2455  */
2456
2457 static gboolean layout_bar_enabled(LayoutWindow *lw)
2458 {
2459 #if GTK_CHECK_VERSION(2,20,0)
2460         return lw->bar && gtk_widget_get_visible(lw->bar);
2461 #else
2462         return lw->bar && GTK_WIDGET_VISIBLE(lw->bar);
2463 #endif
2464 }
2465
2466 static void layout_bar_destroyed(GtkWidget *widget, gpointer data)
2467 {
2468         LayoutWindow *lw = data;
2469
2470         lw->bar = NULL;
2471 /* 
2472     do not call layout_util_sync_views(lw) here
2473     this is called either when whole layout is destroyed - no need for update
2474     or when the bar is replaced - sync is called by upper function at the end of whole operation
2475
2476 */
2477 }
2478
2479 static void layout_bar_set_default(LayoutWindow *lw)
2480 {
2481         GtkWidget *bar;
2482         
2483         if (!lw->utility_box) return;
2484
2485         bar = bar_new(lw);
2486         
2487         layout_bar_set(lw, bar);
2488         
2489         bar_populate_default(bar);
2490 }
2491
2492 static void layout_bar_close(LayoutWindow *lw)
2493 {
2494         if (lw->bar)
2495                 {
2496                 bar_close(lw->bar);
2497                 lw->bar = NULL;
2498                 }
2499 }
2500
2501
2502 void layout_bar_set(LayoutWindow *lw, GtkWidget *bar)
2503 {
2504         if (!lw->utility_box) return;
2505
2506         layout_bar_close(lw); /* if any */
2507
2508         if (!bar) return;
2509         lw->bar = bar;
2510
2511         g_signal_connect(G_OBJECT(lw->bar), "destroy",
2512                          G_CALLBACK(layout_bar_destroyed), lw);
2513
2514
2515 //      gtk_box_pack_start(GTK_BOX(lw->utility_box), lw->bar, FALSE, FALSE, 0);
2516         gtk_paned_pack2(GTK_PANED(lw->utility_paned), lw->bar, FALSE, TRUE); 
2517
2518         bar_set_fd(lw->bar, layout_image_get_fd(lw));
2519 }
2520
2521
2522 void layout_bar_toggle(LayoutWindow *lw)
2523 {
2524         if (layout_bar_enabled(lw))
2525                 {
2526                 gtk_widget_hide(lw->bar);
2527                 }
2528         else
2529                 {
2530                 if (!lw->bar)
2531                         {
2532                         layout_bar_set_default(lw);
2533                         }
2534                 gtk_widget_show(lw->bar);
2535                 bar_set_fd(lw->bar, layout_image_get_fd(lw));
2536                 }
2537         layout_util_sync_views(lw);
2538 }
2539
2540 static void layout_bar_new_image(LayoutWindow *lw)
2541 {
2542         if (!layout_bar_enabled(lw)) return;
2543
2544         bar_set_fd(lw->bar, layout_image_get_fd(lw));
2545 }
2546
2547 static void layout_bar_new_selection(LayoutWindow *lw, gint count)
2548 {
2549         if (!layout_bar_enabled(lw)) return;
2550
2551         bar_notify_selection(lw->bar, count);
2552 }
2553
2554 static gboolean layout_bar_sort_enabled(LayoutWindow *lw)
2555 {
2556 #if GTK_CHECK_VERSION(2,20,0)
2557         return lw->bar_sort && gtk_widget_get_visible(lw->bar_sort);
2558 #else
2559         return lw->bar_sort && GTK_WIDGET_VISIBLE(lw->bar_sort);
2560 #endif
2561 }
2562
2563
2564 static void layout_bar_sort_destroyed(GtkWidget *widget, gpointer data)
2565 {
2566         LayoutWindow *lw = data;
2567
2568         lw->bar_sort = NULL;
2569
2570 /* 
2571     do not call layout_util_sync_views(lw) here
2572     this is called either when whole layout is destroyed - no need for update
2573     or when the bar is replaced - sync is called by upper function at the end of whole operation
2574
2575 */
2576 }
2577
2578 static void layout_bar_sort_set_default(LayoutWindow *lw)
2579 {
2580         GtkWidget *bar;
2581         
2582         if (!lw->utility_box) return;
2583
2584         bar = bar_sort_new_default(lw);
2585         
2586         layout_bar_sort_set(lw, bar);
2587 }
2588
2589 static void layout_bar_sort_close(LayoutWindow *lw)
2590 {
2591         if (lw->bar_sort)
2592                 {
2593                 bar_sort_close(lw->bar_sort);
2594                 lw->bar_sort = NULL;
2595                 }
2596 }
2597
2598 void layout_bar_sort_set(LayoutWindow *lw, GtkWidget *bar)
2599 {
2600         if (!lw->utility_box) return;
2601
2602         layout_bar_sort_close(lw); /* if any */
2603
2604         if (!bar) return;
2605         lw->bar_sort = bar;
2606
2607         g_signal_connect(G_OBJECT(lw->bar_sort), "destroy",
2608                          G_CALLBACK(layout_bar_sort_destroyed), lw);
2609
2610         gtk_box_pack_end(GTK_BOX(lw->utility_box), lw->bar_sort, FALSE, FALSE, 0);
2611 }
2612
2613 void layout_bar_sort_toggle(LayoutWindow *lw)
2614 {
2615         if (layout_bar_sort_enabled(lw))
2616                 {
2617                 gtk_widget_hide(lw->bar_sort);
2618                 }
2619         else
2620                 {
2621                 if (!lw->bar_sort)
2622                         {
2623                         layout_bar_sort_set_default(lw);
2624                         }
2625                 gtk_widget_show(lw->bar_sort);
2626                 }
2627         layout_util_sync_views(lw);
2628 }
2629
2630 void layout_bars_new_image(LayoutWindow *lw)
2631 {
2632         layout_bar_new_image(lw);
2633
2634         if (lw->exif_window) advanced_exif_set_fd(lw->exif_window, layout_image_get_fd(lw));
2635
2636         /* this should be called here to handle the metadata edited in bars */
2637         if (options->metadata.confirm_on_image_change)
2638                 metadata_write_queue_confirm(FALSE, NULL, NULL);
2639 }
2640
2641 void layout_bars_new_selection(LayoutWindow *lw, gint count)
2642 {
2643         layout_bar_new_selection(lw, count);
2644 }
2645
2646 GtkWidget *layout_bars_prepare(LayoutWindow *lw, GtkWidget *image)
2647 {
2648         if (lw->utility_box) return lw->utility_box;
2649         lw->utility_box = gtk_hbox_new(FALSE, PREF_PAD_GAP);
2650         lw->utility_paned = gtk_hpaned_new();
2651         gtk_box_pack_start(GTK_BOX(lw->utility_box), lw->utility_paned, TRUE, TRUE, 0);
2652
2653         gtk_paned_pack1(GTK_PANED(lw->utility_paned), image, TRUE, FALSE); 
2654         gtk_widget_show(lw->utility_paned);
2655         
2656         gtk_widget_show(image);
2657
2658         g_object_ref(lw->utility_box);
2659         return lw->utility_box;
2660 }
2661
2662 void layout_bars_close(LayoutWindow *lw)
2663 {
2664         layout_bar_sort_close(lw);
2665         layout_bar_close(lw);
2666 }
2667
2668 static void layout_exif_window_destroy(GtkWidget *widget, gpointer data)
2669 {
2670         LayoutWindow *lw = data;
2671         lw->exif_window = NULL;
2672 }
2673
2674 void layout_exif_window_new(LayoutWindow *lw)
2675 {
2676         if (lw->exif_window) return; 
2677         
2678         lw->exif_window = advanced_exif_new();
2679         if (!lw->exif_window) return;
2680         g_signal_connect(G_OBJECT(lw->exif_window), "destroy",
2681                          G_CALLBACK(layout_exif_window_destroy), lw);
2682         advanced_exif_set_fd(lw->exif_window, layout_image_get_fd(lw));
2683 }
2684
2685 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */