create toolbar from ui_manager
[geeqie.git] / src / layout_util.c
1 /*
2  * Geeqie
3  * (C) 2004 John Ellis
4  * Copyright (C) 2008 - 2009 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 "dupe.h"
25 #include "editors.h"
26 #include "filedata.h"
27 #include "history_list.h"
28 #include "image-overlay.h"
29 #include "img-view.h"
30 #include "layout_image.h"
31 #include "logwindow.h"
32 #include "misc.h"
33 #include "pan-view.h"
34 #include "pixbuf_util.h"
35 #include "preferences.h"
36 #include "print.h"
37 #include "search.h"
38 #include "ui_fileops.h"
39 #include "ui_menu.h"
40 #include "ui_misc.h"
41 #include "ui_tabcomp.h"
42 #include "utilops.h"
43 #include "view_dir.h"
44 #include "window.h"
45 #include "metadata.h"
46
47 #include <gdk/gdkkeysyms.h> /* for keyboard values */
48
49
50 #define MENU_EDIT_ACTION_OFFSET 16
51
52 static gboolean layout_bar_enabled(LayoutWindow *lw);
53 static gboolean layout_bar_sort_enabled(LayoutWindow *lw);
54
55 /*
56  *-----------------------------------------------------------------------------
57  * keyboard handler
58  *-----------------------------------------------------------------------------
59  */
60
61 static guint tree_key_overrides[] = {
62         GDK_Page_Up,    GDK_KP_Page_Up,
63         GDK_Page_Down,  GDK_KP_Page_Down,
64         GDK_Home,       GDK_KP_Home,
65         GDK_End,        GDK_KP_End
66 };
67
68 static gboolean layout_key_match(guint keyval)
69 {
70         guint i;
71
72         for (i = 0; i < sizeof(tree_key_overrides) / sizeof(guint); i++)
73                 {
74                 if (keyval == tree_key_overrides[i]) return TRUE;
75                 }
76
77         return FALSE;
78 }
79
80 gint layout_key_press_cb(GtkWidget *widget, GdkEventKey *event, gpointer data)
81 {
82         LayoutWindow *lw = data;
83         gint stop_signal = FALSE;
84         gint x = 0;
85         gint y = 0;
86
87         if (lw->path_entry && GTK_WIDGET_HAS_FOCUS(lw->path_entry))
88                 {
89                 if (event->keyval == GDK_Escape && lw->dir_fd)
90                         {
91                         gtk_entry_set_text(GTK_ENTRY(lw->path_entry), lw->dir_fd->path);
92                         }
93
94                 /* the gtkaccelgroup of the window is stealing presses before they get to the entry (and more),
95                  * so when the some widgets have focus, give them priority (HACK)
96                  */
97                 if (gtk_widget_event(lw->path_entry, (GdkEvent *)event))
98                         {
99                         return TRUE;
100                         }
101                 }
102         if (lw->vd && lw->options.dir_view_type == DIRVIEW_TREE && GTK_WIDGET_HAS_FOCUS(lw->vd->view) &&
103             !layout_key_match(event->keyval) &&
104             gtk_widget_event(lw->vd->view, (GdkEvent *)event))
105                 {
106                 return TRUE;
107                 }
108         if (lw->bar &&
109             bar_event(lw->bar, (GdkEvent *)event))
110                 {
111                 return TRUE;
112                 }
113
114 /*
115         if (event->type == GDK_KEY_PRESS && lw->full_screen &&
116             gtk_accel_groups_activate(G_OBJECT(lw->window), event->keyval, event->state))
117                 return TRUE;
118 */
119
120         if (lw->image &&
121             (GTK_WIDGET_HAS_FOCUS(lw->image->widget) || (lw->tools && widget == lw->window) || lw->full_screen) )
122                 {
123                 stop_signal = TRUE;
124                 switch (event->keyval)
125                         {
126                         case GDK_Left: case GDK_KP_Left:
127                                 x -= 1;
128                                 break;
129                         case GDK_Right: case GDK_KP_Right:
130                                 x += 1;
131                                 break;
132                         case GDK_Up: case GDK_KP_Up:
133                                 y -= 1;
134                                 break;
135                         case GDK_Down: case GDK_KP_Down:
136                                 y += 1;
137                                 break;
138                         default:
139                                 stop_signal = FALSE;
140                                 break;
141                         }
142
143                 if (!stop_signal &&
144                     !(event->state & GDK_CONTROL_MASK))
145                         {
146                         stop_signal = TRUE;
147                         switch (event->keyval)
148                                 {
149                                 case GDK_Menu:
150                                         layout_image_menu_popup(lw);
151                                         break;
152                                 default:
153                                         stop_signal = FALSE;
154                                         break;
155                                 }
156                         }
157                 }
158
159         if (x != 0 || y!= 0)
160                 {
161                 keyboard_scroll_calc(&x, &y, event);
162                 layout_image_scroll(lw, x, y, (event->state & GDK_SHIFT_MASK));
163                 }
164
165         return stop_signal;
166 }
167
168 void layout_keyboard_init(LayoutWindow *lw, GtkWidget *window)
169 {
170         g_signal_connect(G_OBJECT(window), "key_press_event",
171                          G_CALLBACK(layout_key_press_cb), lw);
172 }
173
174 /*
175  *-----------------------------------------------------------------------------
176  * menu callbacks
177  *-----------------------------------------------------------------------------
178  */
179
180
181 static GtkWidget *layout_window(LayoutWindow *lw)
182 {
183         return lw->full_screen ? lw->full_screen->window : lw->window;
184 }
185
186 static void layout_exit_fullscreen(LayoutWindow *lw)
187 {
188         if (!lw->full_screen) return;
189         layout_image_full_screen_stop(lw);
190 }
191
192 static void layout_menu_new_window_cb(GtkAction *action, gpointer data)
193 {
194         LayoutWindow *lw = data;
195         LayoutWindow *nw;
196
197         layout_exit_fullscreen(lw);
198
199         nw = layout_new(NULL, NULL);
200         layout_sort_set(nw, options->file_sort.method, options->file_sort.ascending);
201         layout_set_fd(nw, lw->dir_fd);
202 }
203
204 static void layout_menu_new_cb(GtkAction *action, gpointer data)
205 {
206         LayoutWindow *lw = data;
207
208         layout_exit_fullscreen(lw);
209         collection_window_new(NULL);
210 }
211
212 static void layout_menu_open_cb(GtkAction *action, gpointer data)
213 {
214         LayoutWindow *lw = data;
215
216         layout_exit_fullscreen(lw);
217         collection_dialog_load(NULL);
218 }
219
220 static void layout_menu_search_cb(GtkAction *action, gpointer data)
221 {
222         LayoutWindow *lw = data;
223
224         layout_exit_fullscreen(lw);
225         search_new(lw->dir_fd, layout_image_get_fd(lw));
226 }
227
228 static void layout_menu_dupes_cb(GtkAction *action, gpointer data)
229 {
230         LayoutWindow *lw = data;
231
232         layout_exit_fullscreen(lw);
233         dupe_window_new(DUPE_MATCH_NAME);
234 }
235
236 static void layout_menu_pan_cb(GtkAction *action, gpointer data)
237 {
238         LayoutWindow *lw = data;
239
240         layout_exit_fullscreen(lw);
241         pan_window_new(lw->dir_fd);
242 }
243
244 static void layout_menu_print_cb(GtkAction *action, gpointer data)
245 {
246         LayoutWindow *lw = data;
247
248         print_window_new(layout_image_get_fd(lw), layout_selection_list(lw), layout_list(lw), layout_window(lw));
249 }
250
251 static void layout_menu_dir_cb(GtkAction *action, gpointer data)
252 {
253         LayoutWindow *lw = data;
254
255         file_util_create_dir(lw->dir_fd, layout_window(lw), NULL, NULL);
256 }
257
258 static void layout_menu_copy_cb(GtkAction *action, gpointer data)
259 {
260         LayoutWindow *lw = data;
261
262         file_util_copy(NULL, layout_selection_list(lw), NULL, layout_window(lw));
263 }
264
265 static void layout_menu_copy_path_cb(GtkAction *action, gpointer data)
266 {
267         LayoutWindow *lw = data;
268
269         file_util_copy_path_list_to_clipboard(layout_selection_list(lw));
270 }
271
272 static void layout_menu_move_cb(GtkAction *action, gpointer data)
273 {
274         LayoutWindow *lw = data;
275
276         file_util_move(NULL, layout_selection_list(lw), NULL, layout_window(lw));
277 }
278
279 static void layout_menu_rename_cb(GtkAction *action, gpointer data)
280 {
281         LayoutWindow *lw = data;
282
283         file_util_rename(NULL, layout_selection_list(lw), layout_window(lw));
284 }
285
286 static void layout_menu_delete_cb(GtkAction *action, gpointer data)
287 {
288         LayoutWindow *lw = data;
289
290         file_util_delete(NULL, layout_selection_list(lw), layout_window(lw));
291 }
292
293 static void layout_menu_close_cb(GtkAction *action, gpointer data)
294 {
295         LayoutWindow *lw = data;
296
297         layout_exit_fullscreen(lw);
298         layout_close(lw);
299 }
300
301 static void layout_menu_exit_cb(GtkAction *action, gpointer data)
302 {
303         exit_program();
304 }
305
306 static void layout_menu_alter_90_cb(GtkAction *action, gpointer data)
307 {
308         LayoutWindow *lw = data;
309
310         layout_image_alter(lw, ALTER_ROTATE_90);
311 }
312
313 static void layout_menu_alter_90cc_cb(GtkAction *action, gpointer data)
314 {
315         LayoutWindow *lw = data;
316
317         layout_image_alter(lw, ALTER_ROTATE_90_CC);
318 }
319
320 static void layout_menu_alter_180_cb(GtkAction *action, gpointer data)
321 {
322         LayoutWindow *lw = data;
323
324         layout_image_alter(lw, ALTER_ROTATE_180);
325 }
326
327 static void layout_menu_alter_mirror_cb(GtkAction *action, gpointer data)
328 {
329         LayoutWindow *lw = data;
330
331         layout_image_alter(lw, ALTER_MIRROR);
332 }
333
334 static void layout_menu_alter_flip_cb(GtkAction *action, gpointer data)
335 {
336         LayoutWindow *lw = data;
337
338         layout_image_alter(lw, ALTER_FLIP);
339 }
340
341 static void layout_menu_alter_desaturate_cb(GtkAction *action, gpointer data)
342 {
343         LayoutWindow *lw = data;
344
345         layout_image_alter(lw, ALTER_DESATURATE);
346 }
347
348 static void layout_menu_alter_none_cb(GtkAction *action, gpointer data)
349 {
350         LayoutWindow *lw = data;
351
352         layout_image_alter(lw, ALTER_NONE);
353 }
354
355 static void layout_menu_config_cb(GtkAction *action, gpointer data)
356 {
357         LayoutWindow *lw = data;
358
359         layout_exit_fullscreen(lw);
360         show_config_window();
361 }
362
363 static void layout_menu_remove_thumb_cb(GtkAction *action, gpointer data)
364 {
365         LayoutWindow *lw = data;
366
367         layout_exit_fullscreen(lw);
368         cache_manager_show();
369 }
370
371 static void layout_menu_wallpaper_cb(GtkAction *action, gpointer data)
372 {
373         LayoutWindow *lw = data;
374
375         layout_image_to_root(lw);
376 }
377
378 /* single window zoom */
379 static void layout_menu_zoom_in_cb(GtkAction *action, gpointer data)
380 {
381         LayoutWindow *lw = data;
382
383         layout_image_zoom_adjust(lw, get_zoom_increment(), FALSE);
384 }
385
386 static void layout_menu_zoom_out_cb(GtkAction *action, gpointer data)
387 {
388         LayoutWindow *lw = data;
389
390         layout_image_zoom_adjust(lw, -get_zoom_increment(), FALSE);
391 }
392
393 static void layout_menu_zoom_1_1_cb(GtkAction *action, gpointer data)
394 {
395         LayoutWindow *lw = data;
396
397         layout_image_zoom_set(lw, 1.0, FALSE);
398 }
399
400 static void layout_menu_zoom_fit_cb(GtkAction *action, gpointer data)
401 {
402         LayoutWindow *lw = data;
403
404         layout_image_zoom_set(lw, 0.0, FALSE);
405 }
406
407 static void layout_menu_zoom_fit_hor_cb(GtkAction *action, gpointer data)
408 {
409         LayoutWindow *lw = data;
410
411         layout_image_zoom_set_fill_geometry(lw, FALSE, FALSE);
412 }
413
414 static void layout_menu_zoom_fit_vert_cb(GtkAction *action, gpointer data)
415 {
416         LayoutWindow *lw = data;
417
418         layout_image_zoom_set_fill_geometry(lw, TRUE, FALSE);
419 }
420
421 static void layout_menu_zoom_2_1_cb(GtkAction *action, gpointer data)
422 {
423         LayoutWindow *lw = data;
424
425         layout_image_zoom_set(lw, 2.0, FALSE);
426 }
427
428 static void layout_menu_zoom_3_1_cb(GtkAction *action, gpointer data)
429 {
430         LayoutWindow *lw = data;
431
432         layout_image_zoom_set(lw, 3.0, FALSE);
433 }
434 static void layout_menu_zoom_4_1_cb(GtkAction *action, gpointer data)
435 {
436         LayoutWindow *lw = data;
437
438         layout_image_zoom_set(lw, 4.0, FALSE);
439 }
440
441 static void layout_menu_zoom_1_2_cb(GtkAction *action, gpointer data)
442 {
443         LayoutWindow *lw = data;
444
445         layout_image_zoom_set(lw, -2.0, FALSE);
446 }
447
448 static void layout_menu_zoom_1_3_cb(GtkAction *action, gpointer data)
449 {
450         LayoutWindow *lw = data;
451
452         layout_image_zoom_set(lw, -3.0, FALSE);
453 }
454
455 static void layout_menu_zoom_1_4_cb(GtkAction *action, gpointer data)
456 {
457         LayoutWindow *lw = data;
458
459         layout_image_zoom_set(lw, -4.0, FALSE);
460 }
461
462 /* connected zoom */
463 static void layout_menu_connect_zoom_in_cb(GtkAction *action, gpointer data)
464 {
465         LayoutWindow *lw = data;
466
467         layout_image_zoom_adjust(lw, get_zoom_increment(), TRUE);
468 }
469
470 static void layout_menu_connect_zoom_out_cb(GtkAction *action, gpointer data)
471 {
472         LayoutWindow *lw = data;
473
474         layout_image_zoom_adjust(lw, -get_zoom_increment(), TRUE);
475 }
476
477 static void layout_menu_connect_zoom_1_1_cb(GtkAction *action, gpointer data)
478 {
479         LayoutWindow *lw = data;
480
481         layout_image_zoom_set(lw, 1.0, TRUE);
482 }
483
484 static void layout_menu_connect_zoom_fit_cb(GtkAction *action, gpointer data)
485 {
486         LayoutWindow *lw = data;
487
488         layout_image_zoom_set(lw, 0.0, TRUE);
489 }
490
491 static void layout_menu_connect_zoom_fit_hor_cb(GtkAction *action, gpointer data)
492 {
493         LayoutWindow *lw = data;
494
495         layout_image_zoom_set_fill_geometry(lw, FALSE, TRUE);
496 }
497
498 static void layout_menu_connect_zoom_fit_vert_cb(GtkAction *action, gpointer data)
499 {
500         LayoutWindow *lw = data;
501
502         layout_image_zoom_set_fill_geometry(lw, TRUE, TRUE);
503 }
504
505 static void layout_menu_connect_zoom_2_1_cb(GtkAction *action, gpointer data)
506 {
507         LayoutWindow *lw = data;
508
509         layout_image_zoom_set(lw, 2.0, TRUE);
510 }
511
512 static void layout_menu_connect_zoom_3_1_cb(GtkAction *action, gpointer data)
513 {
514         LayoutWindow *lw = data;
515
516         layout_image_zoom_set(lw, 3.0, TRUE);
517 }
518 static void layout_menu_connect_zoom_4_1_cb(GtkAction *action, gpointer data)
519 {
520         LayoutWindow *lw = data;
521
522         layout_image_zoom_set(lw, 4.0, TRUE);
523 }
524
525 static void layout_menu_connect_zoom_1_2_cb(GtkAction *action, gpointer data)
526 {
527         LayoutWindow *lw = data;
528
529         layout_image_zoom_set(lw, -2.0, TRUE);
530 }
531
532 static void layout_menu_connect_zoom_1_3_cb(GtkAction *action, gpointer data)
533 {
534         LayoutWindow *lw = data;
535
536         layout_image_zoom_set(lw, -3.0, TRUE);
537 }
538
539 static void layout_menu_connect_zoom_1_4_cb(GtkAction *action, gpointer data)
540 {
541         LayoutWindow *lw = data;
542
543         layout_image_zoom_set(lw, -4.0, TRUE);
544 }
545
546
547 static void layout_menu_split_cb(GtkRadioAction *action, GtkRadioAction *current, gpointer data)
548 {
549         LayoutWindow *lw = data;
550         ImageSplitMode mode;
551
552         layout_exit_fullscreen(lw);
553
554         mode = gtk_radio_action_get_current_value(action);
555         if (mode == lw->split_mode) mode = 0; /* toggle back */
556
557         layout_split_change(lw, mode);
558 }
559
560
561 static void layout_menu_thumb_cb(GtkToggleAction *action, gpointer data)
562 {
563         LayoutWindow *lw = data;
564
565         layout_thumb_set(lw, gtk_toggle_action_get_active(action));
566 }
567
568
569 static void layout_menu_list_cb(GtkRadioAction *action, GtkRadioAction *current, gpointer data)
570 {
571         LayoutWindow *lw = data;
572         
573         layout_exit_fullscreen(lw);
574         layout_views_set(lw, lw->options.dir_view_type, (gtk_radio_action_get_current_value(action) == 1) ? FILEVIEW_ICON : FILEVIEW_LIST);
575 }
576
577 static void layout_menu_view_dir_as_cb(GtkRadioAction *action, GtkRadioAction *current, gpointer data)
578 {
579         LayoutWindow *lw = data;
580
581         layout_exit_fullscreen(lw);
582         layout_views_set(lw, (DirViewType) gtk_radio_action_get_current_value(action), lw->file_view_type);
583 }
584
585 static void layout_menu_view_in_new_window_cb(GtkAction *action, gpointer data)
586 {
587         LayoutWindow *lw = data;
588
589         layout_exit_fullscreen(lw);
590         view_window_new(layout_image_get_fd(lw));
591 }
592
593 static void layout_menu_fullscreen_cb(GtkAction *action, gpointer data)
594 {
595         LayoutWindow *lw = data;
596
597         layout_image_full_screen_toggle(lw);
598 }
599
600 static void layout_menu_escape_cb(GtkAction *action, gpointer data)
601 {
602         LayoutWindow *lw = data;
603
604         layout_exit_fullscreen(lw);
605
606         /* FIXME:interrupting thumbs no longer allowed */
607 #if 0
608         interrupt_thumbs();
609 #endif
610 }
611
612 static void layout_menu_overlay_cb(GtkAction *action, gpointer data)
613 {
614         LayoutWindow *lw = data;
615
616         image_osd_toggle(lw->image);
617 }
618
619 static void layout_menu_histogram_chan_cb(GtkAction *action, gpointer data)
620 {
621         LayoutWindow *lw = data;
622
623         image_osd_histogram_chan_toggle(lw->image);
624 }
625
626 static void layout_menu_histogram_log_cb(GtkAction *action, gpointer data)
627 {
628         LayoutWindow *lw = data;
629
630         image_osd_histogram_log_toggle(lw->image);
631 }
632
633 static void layout_menu_refresh_cb(GtkAction *action, gpointer data)
634 {
635         LayoutWindow *lw = data;
636
637         layout_refresh(lw);
638 }
639
640 static void layout_menu_float_cb(GtkToggleAction *action, gpointer data)
641 {
642         LayoutWindow *lw = data;
643
644         if (lw->options.tools_float == gtk_toggle_action_get_active(action)) return;
645
646         layout_exit_fullscreen(lw);
647         layout_tools_float_toggle(lw);
648 }
649
650 static void layout_menu_hide_cb(GtkAction *action, gpointer data)
651 {
652         LayoutWindow *lw = data;
653
654         layout_exit_fullscreen(lw);
655         layout_tools_hide_toggle(lw);
656 }
657
658 static void layout_menu_toolbar_cb(GtkToggleAction *action, gpointer data)
659 {
660         LayoutWindow *lw = data;
661
662         if (lw->options.toolbar_hidden == gtk_toggle_action_get_active(action)) return;
663
664         layout_exit_fullscreen(lw);
665         layout_toolbar_toggle(lw);
666 }
667
668 /* NOTE: these callbacks are called also from layout_util_sync_views */
669 static void layout_menu_bar_cb(GtkToggleAction *action, gpointer data)
670 {
671         LayoutWindow *lw = data;
672
673         if (layout_bar_enabled(lw) == gtk_toggle_action_get_active(action)) return;
674
675         layout_exit_fullscreen(lw);
676         layout_bar_toggle(lw);
677 }
678
679 static void layout_menu_bar_exif_cb(GtkToggleAction *action, gpointer data)
680 {
681         LayoutWindow *lw = data;
682         
683         layout_exit_fullscreen(lw);
684
685         layout_exif_window_new(lw);
686 }
687
688 static void layout_menu_bar_sort_cb(GtkToggleAction *action, gpointer data)
689 {
690         LayoutWindow *lw = data;
691
692         if (layout_bar_sort_enabled(lw) == gtk_toggle_action_get_active(action)) return;
693
694         layout_exit_fullscreen(lw);
695         layout_bar_sort_toggle(lw);
696 }
697
698 static void layout_menu_slideshow_cb(GtkAction *action, gpointer data)
699 {
700         LayoutWindow *lw = data;
701
702         layout_image_slideshow_toggle(lw);
703 }
704
705 static void layout_menu_slideshow_pause_cb(GtkAction *action, gpointer data)
706 {
707         LayoutWindow *lw = data;
708
709         layout_image_slideshow_pause_toggle(lw);
710 }
711
712 static void layout_menu_help_cb(GtkAction *action, gpointer data)
713 {
714         LayoutWindow *lw = data;
715
716         layout_exit_fullscreen(lw);
717         help_window_show("html_contents");
718 }
719
720 static void layout_menu_help_keys_cb(GtkAction *action, gpointer data)
721 {
722         LayoutWindow *lw = data;
723
724         layout_exit_fullscreen(lw);
725         help_window_show("documentation");
726 }
727
728 static void layout_menu_notes_cb(GtkAction *action, gpointer data)
729 {
730         LayoutWindow *lw = data;
731         
732         layout_exit_fullscreen(lw);
733         help_window_show("release_notes");
734 }
735
736 static void layout_menu_about_cb(GtkAction *action, gpointer data)
737 {
738         LayoutWindow *lw = data;
739
740         layout_exit_fullscreen(lw);
741         show_about_window();
742 }
743
744 static void layout_menu_log_window_cb(GtkAction *action, gpointer data)
745 {
746         LayoutWindow *lw = data;
747
748         layout_exit_fullscreen(lw);
749         log_window_new();
750 }
751
752
753 /*
754  *-----------------------------------------------------------------------------
755  * select menu
756  *-----------------------------------------------------------------------------
757  */
758
759 static void layout_menu_select_all_cb(GtkAction *action, gpointer data)
760 {
761         LayoutWindow *lw = data;
762
763         layout_select_all(lw);
764 }
765
766 static void layout_menu_unselect_all_cb(GtkAction *action, gpointer data)
767 {
768         LayoutWindow *lw = data;
769
770         layout_select_none(lw);
771 }
772
773 static void layout_menu_invert_selection_cb(GtkAction *action, gpointer data)
774 {
775         LayoutWindow *lw = data;
776
777         layout_select_invert(lw);
778 }
779
780 static void layout_menu_marks_cb(GtkToggleAction *action, gpointer data)
781 {
782         LayoutWindow *lw = data;
783
784         layout_marks_set(lw, gtk_toggle_action_get_active(action));
785 }
786
787
788 static void layout_menu_set_mark_sel_cb(GtkAction *action, gpointer data)
789 {
790         LayoutWindow *lw = data;
791         gint mark = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(action), "mark_num"));
792         g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
793
794         layout_selection_to_mark(lw, mark, STM_MODE_SET);
795 }
796
797 static void layout_menu_res_mark_sel_cb(GtkAction *action, gpointer data)
798 {
799         LayoutWindow *lw = data;
800         gint mark = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(action), "mark_num"));
801         g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
802
803         layout_selection_to_mark(lw, mark, STM_MODE_RESET);
804 }
805
806 static void layout_menu_toggle_mark_sel_cb(GtkAction *action, gpointer data)
807 {
808         LayoutWindow *lw = data;
809         gint mark = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(action), "mark_num"));
810         g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
811
812         layout_selection_to_mark(lw, mark, STM_MODE_TOGGLE);
813 }
814
815 static void layout_menu_sel_mark_cb(GtkAction *action, gpointer data)
816 {
817         LayoutWindow *lw = data;
818         gint mark = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(action), "mark_num"));
819         g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
820
821         layout_mark_to_selection(lw, mark, MTS_MODE_SET);
822 }
823
824 static void layout_menu_sel_mark_or_cb(GtkAction *action, gpointer data)
825 {
826         LayoutWindow *lw = data;
827         gint mark = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(action), "mark_num"));
828         g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
829
830         layout_mark_to_selection(lw, mark, MTS_MODE_OR);
831 }
832
833 static void layout_menu_sel_mark_and_cb(GtkAction *action, gpointer data)
834 {
835         LayoutWindow *lw = data;
836         gint mark = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(action), "mark_num"));
837         g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
838
839         layout_mark_to_selection(lw, mark, MTS_MODE_AND);
840 }
841
842 static void layout_menu_sel_mark_minus_cb(GtkAction *action, gpointer data)
843 {
844         LayoutWindow *lw = data;
845         gint mark = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(action), "mark_num"));
846         g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
847
848         layout_mark_to_selection(lw, mark, MTS_MODE_MINUS);
849 }
850
851
852 /*
853  *-----------------------------------------------------------------------------
854  * go menu
855  *-----------------------------------------------------------------------------
856  */
857
858 static void layout_menu_image_first_cb(GtkAction *action, gpointer data)
859 {
860         LayoutWindow *lw = data;
861         layout_image_first(lw);
862 }
863
864 static void layout_menu_image_prev_cb(GtkAction *action, gpointer data)
865 {
866         LayoutWindow *lw = data;
867         layout_image_prev(lw);
868 }
869
870 static void layout_menu_image_next_cb(GtkAction *action, gpointer data)
871 {
872         LayoutWindow *lw = data;
873         layout_image_next(lw);
874 }
875
876 static void layout_menu_image_last_cb(GtkAction *action, gpointer data)
877 {
878         LayoutWindow *lw = data;
879         layout_image_last(lw);
880 }
881
882 static void layout_menu_back_cb(GtkAction *action, gpointer data)
883 {
884         LayoutWindow *lw = data;
885         FileData *dir_fd;
886         gchar *path = NULL;
887         GList *list = history_list_get_by_key("path_list");
888         gint n = 0;
889
890         while (list)
891                 {
892                 if (n == 1) {
893                         /* Previous path from history */
894                         path = (gchar *)list->data;
895                         break;
896                 }
897                 list = list->next;
898                 n++;
899                 }
900
901         if (!path) return;
902         
903         /* Open previous path */
904         dir_fd = file_data_new_simple(path);
905         layout_set_fd(lw, dir_fd);
906         file_data_unref(dir_fd);
907 }
908
909 static void layout_menu_home_cb(GtkAction *action, gpointer data)
910 {
911         const gchar *path;
912         
913         if (options->layout.home_path && *options->layout.home_path)
914                 path = options->layout.home_path;
915         else
916                 path = homedir();
917
918         if (path)
919                 {
920                 LayoutWindow *lw = data;
921                 FileData *dir_fd = file_data_new_simple(path);
922                 layout_set_fd(lw, dir_fd);
923                 file_data_unref(dir_fd);
924                 }
925 }
926
927
928 /*
929  *-----------------------------------------------------------------------------
930  * edit menu
931  *-----------------------------------------------------------------------------
932  */
933
934 static void layout_menu_edit_cb(GtkAction *action, gpointer data)
935 {
936         LayoutWindow *lw = data;
937         GList *list;
938         const gchar *key = gtk_action_get_name(action);
939         
940         if (!editor_window_flag_set(key))
941                 layout_exit_fullscreen(lw);
942
943         list = layout_selection_list(lw);
944         file_util_start_editor_from_filelist(key, list, lw->window);
945         filelist_free(list);
946 }
947
948 #if 0
949 static void layout_menu_edit_update(LayoutWindow *lw)
950 {
951         gint i;
952
953         /* main edit menu */
954
955         if (!lw->action_group) return;
956
957         for (i = 0; i < GQ_EDITOR_GENERIC_SLOTS; i++)
958                 {
959                 gchar *key;
960                 GtkAction *action;
961                 const gchar *name;
962         
963                 key = g_strdup_printf("Editor%d", i);
964
965                 action = gtk_action_group_get_action(lw->action_group, key);
966                 g_object_set_data(G_OBJECT(action), "edit_index", GINT_TO_POINTER(i));
967
968                 name = editor_get_name(i);
969                 if (name)
970                         {
971                         gchar *text = g_strdup_printf(_("_%d %s..."), i, name);
972
973                         g_object_set(action, "label", text,
974                                              "sensitive", TRUE, NULL);
975                         g_free(text);
976                         }
977                 else
978                         {
979                         gchar *text;
980
981                         text = g_strdup_printf(_("_%d empty"), i);
982                         g_object_set(action, "label", text, "sensitive", FALSE, NULL);
983                         g_free(text);
984                         }
985
986                 g_free(key);
987                 }
988 }
989
990 void layout_edit_update_all(void)
991 {
992         GList *work;
993
994         work = layout_window_list;
995         while (work)
996                 {
997                 LayoutWindow *lw = work->data;
998                 work = work->next;
999
1000                 layout_menu_edit_update(lw);
1001                 }
1002 }
1003
1004 #endif
1005
1006 /*
1007  *-----------------------------------------------------------------------------
1008  * recent menu
1009  *-----------------------------------------------------------------------------
1010  */
1011
1012 static void layout_menu_recent_cb(GtkWidget *widget, gpointer data)
1013 {
1014         gint n;
1015         gchar *path;
1016
1017         n = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "recent_index"));
1018
1019         path = g_list_nth_data(history_list_get_by_key("recent"), n);
1020
1021         if (!path) return;
1022
1023         /* make a copy of it */
1024         path = g_strdup(path);
1025         collection_window_new(path);
1026         g_free(path);
1027 }
1028
1029 static void layout_menu_recent_update(LayoutWindow *lw)
1030 {
1031         GtkWidget *menu;
1032         GtkWidget *recent;
1033         GtkWidget *item;
1034         GList *list;
1035         gint n;
1036
1037         if (!lw->ui_manager) return;
1038
1039         list = history_list_get_by_key("recent");
1040         n = 0;
1041
1042         menu = gtk_menu_new();
1043
1044         while (list)
1045                 {
1046                 const gchar *filename = filename_from_path((gchar *)list->data);
1047                 gchar *name;
1048                 gboolean free_name = FALSE;
1049
1050                 if (file_extension_match(filename, GQ_COLLECTION_EXT))
1051                         {
1052                         name = remove_extension_from_path(filename);
1053                         free_name = TRUE;
1054                         }
1055                 else
1056                         {
1057                         name = (gchar *) filename;
1058                         }
1059
1060                 item = menu_item_add_simple(menu, name, G_CALLBACK(layout_menu_recent_cb), lw);
1061                 if (free_name) g_free(name);
1062                 g_object_set_data(G_OBJECT(item), "recent_index", GINT_TO_POINTER(n));
1063                 list = list->next;
1064                 n++;
1065                 }
1066
1067         if (n == 0)
1068                 {
1069                 menu_item_add(menu, _("Empty"), NULL, NULL);
1070                 }
1071
1072         recent = gtk_ui_manager_get_widget(lw->ui_manager, "/MainMenu/FileMenu/OpenRecent");
1073         gtk_menu_item_set_submenu(GTK_MENU_ITEM(recent), menu);
1074         gtk_widget_set_sensitive(recent, (n != 0));
1075 }
1076
1077 void layout_recent_update_all(void)
1078 {
1079         GList *work;
1080
1081         work = layout_window_list;
1082         while (work)
1083                 {
1084                 LayoutWindow *lw = work->data;
1085                 work = work->next;
1086
1087                 layout_menu_recent_update(lw);
1088                 }
1089 }
1090
1091 void layout_recent_add_path(const gchar *path)
1092 {
1093         if (!path) return;
1094
1095         history_list_add_to_key("recent", path, options->open_recent_list_maxsize);
1096
1097         layout_recent_update_all();
1098 }
1099
1100 /*
1101  *-----------------------------------------------------------------------------
1102  * copy path
1103  *-----------------------------------------------------------------------------
1104  */
1105
1106 static void layout_copy_path_update(LayoutWindow *lw)
1107 {
1108         GtkWidget *item = gtk_ui_manager_get_widget(lw->ui_manager, "/MainMenu/FileMenu/CopyPath");
1109
1110         if (!item) return;
1111         
1112         if (options->show_copy_path)
1113                 gtk_widget_show(item);
1114         else
1115                 gtk_widget_hide(item);
1116 }
1117
1118 void layout_copy_path_update_all(void)
1119 {
1120         GList *work;
1121
1122         work = layout_window_list;
1123         while (work)
1124                 {
1125                 LayoutWindow *lw = work->data;
1126                 work = work->next;
1127
1128                 layout_copy_path_update(lw);
1129                 }
1130 }
1131
1132 /*
1133  *-----------------------------------------------------------------------------
1134  * menu
1135  *-----------------------------------------------------------------------------
1136  */
1137
1138 #define CB G_CALLBACK
1139
1140 static GtkActionEntry menu_entries[] = {
1141   { "FileMenu",         NULL,           N_("_File"),                    NULL,           NULL,   NULL },
1142   { "GoMenu",           NULL,           N_("_Go"),                      NULL,           NULL,   NULL },
1143   { "EditMenu",         NULL,           N_("_Edit"),                    NULL,           NULL,   NULL },
1144   { "SelectMenu",       NULL,           N_("_Select"),                  NULL,           NULL,   NULL },
1145   { "AdjustMenu",       NULL,           N_("_Adjust"),                  NULL,           NULL,   NULL },
1146   { "ExternalMenu",     NULL,           N_("E_xternal Editors"),        NULL,           NULL,   NULL },
1147   { "ViewMenu",         NULL,           N_("_View"),                    NULL,           NULL,   NULL },
1148   { "DirMenu",          NULL,           N_("_View Directory as"),       NULL,           NULL,   NULL },
1149   { "ZoomMenu",         NULL,           N_("_Zoom"),                    NULL,           NULL,   NULL },
1150   { "ConnectZoomMenu",  NULL,           N_("_Connected Zoom"),          NULL,           NULL,   NULL },
1151   { "SplitMenu",        NULL,           N_("_Split"),                   NULL,           NULL,   NULL },
1152   { "HelpMenu",         NULL,           N_("_Help"),                    NULL,           NULL,   NULL },
1153
1154   { "FirstImage",       GTK_STOCK_GOTO_TOP,     N_("_First Image"),     "Home",         NULL,   CB(layout_menu_image_first_cb) },
1155   { "PrevImage",        GTK_STOCK_GO_UP,        N_("_Previous Image"),  "BackSpace",    NULL,   CB(layout_menu_image_prev_cb) },
1156   { "PrevImageAlt1",    GTK_STOCK_GO_UP,        N_("_Previous Image"),  "Page_Up",      NULL,   CB(layout_menu_image_prev_cb) },
1157   { "PrevImageAlt2",    GTK_STOCK_GO_UP,        N_("_Previous Image"),  "KP_Page_Up",   NULL,   CB(layout_menu_image_prev_cb) },
1158   { "NextImage",        GTK_STOCK_GO_DOWN,      N_("_Next Image"),      "space",        NULL,   CB(layout_menu_image_next_cb) },
1159   { "NextImageAlt1",    GTK_STOCK_GO_DOWN,      N_("_Next Image"),      "Page_Down",    NULL,   CB(layout_menu_image_next_cb) },
1160   { "NextImageAlt2",    GTK_STOCK_GO_DOWN,      N_("_Next Image"),      "KP_Page_Down", NULL,   CB(layout_menu_image_next_cb) },
1161   { "LastImage",        GTK_STOCK_GOTO_BOTTOM,  N_("_Last Image"),      "End",          NULL,   CB(layout_menu_image_last_cb) },
1162   { "Back",             GTK_STOCK_GO_BACK,      N_("_Back"),            NULL,           N_("Back"),     CB(layout_menu_back_cb) },
1163   { "Home",             GTK_STOCK_HOME,         N_("_Home"),            NULL,           N_("Home"),     CB(layout_menu_home_cb) },
1164
1165
1166   { "NewWindow",        GTK_STOCK_NEW,  N_("New _window"),      NULL,           NULL,   CB(layout_menu_new_window_cb) },
1167   { "NewCollection",    GTK_STOCK_INDEX,N_("_New collection"),  "C",            NULL,   CB(layout_menu_new_cb) },
1168   { "OpenCollection",   GTK_STOCK_OPEN, N_("_Open collection..."),"O",          NULL,   CB(layout_menu_open_cb) },
1169   { "OpenRecent",       NULL,           N_("Open _recent"),     NULL,           NULL,   NULL },
1170   { "Search",           GTK_STOCK_FIND, N_("_Search..."),       "F3",           NULL,   CB(layout_menu_search_cb) },
1171   { "FindDupes",        GTK_STOCK_FIND, N_("_Find duplicates..."),"D",          NULL,   CB(layout_menu_dupes_cb) },
1172   { "PanView",          NULL,           N_("Pan _view"),        "<control>J",   NULL,   CB(layout_menu_pan_cb) },
1173   { "Print",            GTK_STOCK_PRINT,N_("_Print..."),        "<shift>P",     NULL,   CB(layout_menu_print_cb) },
1174   { "NewFolder",        NULL,           N_("N_ew folder..."),   "<control>F",   NULL,   CB(layout_menu_dir_cb) },
1175   { "Copy",             NULL,           N_("_Copy..."),         "<control>C",   NULL,   CB(layout_menu_copy_cb) },
1176   { "Move",             NULL,           N_("_Move..."),         "<control>M",   NULL,   CB(layout_menu_move_cb) },
1177   { "Rename",           NULL,           N_("_Rename..."),       "<control>R",   NULL,   CB(layout_menu_rename_cb) },
1178   { "Delete",   GTK_STOCK_DELETE,       N_("_Delete..."),       "<control>D",   NULL,   CB(layout_menu_delete_cb) },
1179   { "DeleteAlt1",GTK_STOCK_DELETE,      N_("_Delete..."),       "Delete",       NULL,   CB(layout_menu_delete_cb) },
1180   { "DeleteAlt2",GTK_STOCK_DELETE,      N_("_Delete..."),       "KP_Delete",    NULL,   CB(layout_menu_delete_cb) },
1181   { "CopyPath",         NULL,           N_("_Copy path to clipboard"),  NULL,           NULL,   CB(layout_menu_copy_path_cb) },
1182   { "CloseWindow",      GTK_STOCK_CLOSE,N_("C_lose window"),    "<control>W",   NULL,   CB(layout_menu_close_cb) },
1183   { "Quit",             GTK_STOCK_QUIT, N_("_Quit"),            "<control>Q",   NULL,   CB(layout_menu_exit_cb) },
1184
1185   { "RotateCW",         NULL,   N_("_Rotate clockwise"),        "bracketright", NULL,   CB(layout_menu_alter_90_cb) },
1186   { "RotateCCW",        NULL,   N_("Rotate _counterclockwise"), "bracketleft",  NULL,   CB(layout_menu_alter_90cc_cb) },
1187   { "Rotate180",        NULL,           N_("Rotate 1_80"),      "<shift>R",     NULL,   CB(layout_menu_alter_180_cb) },
1188   { "Mirror",           NULL,           N_("_Mirror"),          "<shift>M",     NULL,   CB(layout_menu_alter_mirror_cb) },
1189   { "Flip",             NULL,           N_("_Flip"),            "<shift>F",     NULL,   CB(layout_menu_alter_flip_cb) },
1190   { "Grayscale",        NULL,           N_("Toggle _grayscale"),"<shift>G",     NULL,   CB(layout_menu_alter_desaturate_cb) },
1191   { "AlterNone",        NULL,           N_("_Original state"),  "<shift>O",     NULL,   CB(layout_menu_alter_none_cb) },
1192
1193   { "SelectAll",        NULL,           N_("Select _all"),      "<control>A",   NULL,   CB(layout_menu_select_all_cb) },
1194   { "SelectNone",       NULL,           N_("Select _none"), "<control><shift>A",NULL,   CB(layout_menu_unselect_all_cb) },
1195   { "SelectInvert",     NULL,           N_("_Invert Selection"), "<control><shift>I",   NULL,   CB(layout_menu_invert_selection_cb) },
1196
1197   { "Preferences",GTK_STOCK_PREFERENCES,N_("P_references..."),  "<control>O",   NULL,   CB(layout_menu_config_cb) },
1198   { "Maintenance",      NULL,           N_("_Thumbnail maintenance..."),NULL,   NULL,   CB(layout_menu_remove_thumb_cb) },
1199   { "Wallpaper",        NULL,           N_("Set as _wallpaper"),NULL,           NULL,   CB(layout_menu_wallpaper_cb) },
1200
1201   { "ZoomIn",   GTK_STOCK_ZOOM_IN,      N_("Zoom _in"),         "equal",        N_("Zoom in"),  CB(layout_menu_zoom_in_cb) },
1202   { "ZoomInAlt1",GTK_STOCK_ZOOM_IN,     N_("Zoom _in"),         "KP_Add",       N_("Zoom in"),  CB(layout_menu_zoom_in_cb) },
1203   { "ZoomOut",  GTK_STOCK_ZOOM_OUT,     N_("Zoom _out"),        "minus",        N_("Zoom out"), CB(layout_menu_zoom_out_cb) },
1204   { "ZoomOutAlt1",GTK_STOCK_ZOOM_OUT,   N_("Zoom _out"),        "KP_Subtract",  N_("Zoom out"), CB(layout_menu_zoom_out_cb) },
1205   { "Zoom100",  GTK_STOCK_ZOOM_100,     N_("Zoom _1:1"),        "Z",            N_("Zoom 1:1"), CB(layout_menu_zoom_1_1_cb) },
1206   { "Zoom100Alt1",GTK_STOCK_ZOOM_100,   N_("Zoom _1:1"),        "KP_Divide",    N_("Zoom 1:1"), CB(layout_menu_zoom_1_1_cb) },
1207   { "ZoomFit",  GTK_STOCK_ZOOM_FIT,     N_("_Zoom to fit"),     "X",            N_("Zoom to fit"),      CB(layout_menu_zoom_fit_cb) },
1208   { "ZoomFitAlt1",GTK_STOCK_ZOOM_FIT,   N_("_Zoom to fit"),     "KP_Multiply",  N_("Zoom to fit"),      CB(layout_menu_zoom_fit_cb) },
1209   { "ZoomFillHor",      NULL,           N_("Fit _Horizontally"),"H",            NULL,   CB(layout_menu_zoom_fit_hor_cb) },
1210   { "ZoomFillVert",     NULL,           N_("Fit _Vertically"),  "W",            NULL,   CB(layout_menu_zoom_fit_vert_cb) },
1211   { "Zoom200",          NULL,           N_("Zoom _2:1"),        NULL,           NULL,   CB(layout_menu_zoom_2_1_cb) },
1212   { "Zoom300",          NULL,           N_("Zoom _3:1"),        NULL,           NULL,   CB(layout_menu_zoom_3_1_cb) },
1213   { "Zoom400",          NULL,           N_("Zoom _4:1"),        NULL,           NULL,   CB(layout_menu_zoom_4_1_cb) },
1214   { "Zoom50",           NULL,           N_("Zoom 1:2"),         NULL,           NULL,   CB(layout_menu_zoom_1_2_cb) },
1215   { "Zoom33",           NULL,           N_("Zoom 1:3"),         NULL,           NULL,   CB(layout_menu_zoom_1_3_cb) },
1216   { "Zoom25",           NULL,           N_("Zoom 1:4"),         NULL,           NULL,   CB(layout_menu_zoom_1_4_cb) },
1217
1218   { "ConnectZoomIn",    GTK_STOCK_ZOOM_IN,      N_("Zoom _in"),         "plus",                 NULL,   CB(layout_menu_connect_zoom_in_cb) },
1219   { "ConnectZoomInAlt1",GTK_STOCK_ZOOM_IN,      N_("Zoom _in"),         "<shift>KP_Add",        NULL,   CB(layout_menu_connect_zoom_in_cb) },
1220   { "ConnectZoomOut",   GTK_STOCK_ZOOM_OUT,     N_("Zoom _out"),        "underscore",           NULL,   CB(layout_menu_connect_zoom_out_cb) },
1221   { "ConnectZoomOutAlt1",GTK_STOCK_ZOOM_OUT,    N_("Zoom _out"),        "<shift>KP_Subtract",   NULL,   CB(layout_menu_connect_zoom_out_cb) },
1222   { "ConnectZoom100",   GTK_STOCK_ZOOM_100,     N_("Zoom _1:1"),        "<shift>Z",             NULL,   CB(layout_menu_connect_zoom_1_1_cb) },
1223   { "ConnectZoom100Alt1",GTK_STOCK_ZOOM_100,    N_("Zoom _1:1"),        "<shift>KP_Divide",     NULL,   CB(layout_menu_connect_zoom_1_1_cb) },
1224   { "ConnectZoomFit",   GTK_STOCK_ZOOM_FIT,     N_("_Zoom to fit"),     "<shift>X",             NULL,   CB(layout_menu_connect_zoom_fit_cb) },
1225   { "ConnectZoomFitAlt1",GTK_STOCK_ZOOM_FIT,    N_("_Zoom to fit"),     "<shift>KP_Multiply",   NULL,   CB(layout_menu_connect_zoom_fit_cb) },
1226   { "ConnectZoomFillHor",       NULL,           N_("Fit _Horizontally"),"<shift>H",             NULL,   CB(layout_menu_connect_zoom_fit_hor_cb) },
1227   { "ConnectZoomFillVert",      NULL,           N_("Fit _Vertically"),  "<shift>W",             NULL,   CB(layout_menu_connect_zoom_fit_vert_cb) },
1228   { "ConnectZoom200",           NULL,           N_("Zoom _2:1"),        NULL,                   NULL,   CB(layout_menu_connect_zoom_2_1_cb) },
1229   { "ConnectZoom300",           NULL,           N_("Zoom _3:1"),        NULL,                   NULL,   CB(layout_menu_connect_zoom_3_1_cb) },
1230   { "ConnectZoom400",           NULL,           N_("Zoom _4:1"),        NULL,                   NULL,   CB(layout_menu_connect_zoom_4_1_cb) },
1231   { "ConnectZoom50",            NULL,           N_("Zoom 1:2"),         NULL,                   NULL,   CB(layout_menu_connect_zoom_1_2_cb) },
1232   { "ConnectZoom33",            NULL,           N_("Zoom 1:3"),         NULL,                   NULL,   CB(layout_menu_connect_zoom_1_3_cb) },
1233   { "ConnectZoom25",            NULL,           N_("Zoom 1:4"),         NULL,                   NULL,   CB(layout_menu_connect_zoom_1_4_cb) },
1234
1235
1236   { "ViewInNewWindow",  NULL,           N_("_View in new window"),      "<control>V",           NULL,   CB(layout_menu_view_in_new_window_cb) },
1237
1238   { "FullScreen",       NULL,           N_("F_ull screen"),     "F",            NULL,   CB(layout_menu_fullscreen_cb) },
1239   { "FullScreenAlt1",   NULL,           N_("F_ull screen"),     "V",            NULL,   CB(layout_menu_fullscreen_cb) },
1240   { "FullScreenAlt2",   NULL,           N_("F_ull screen"),     "F11",          NULL,   CB(layout_menu_fullscreen_cb) },
1241   { "Escape",           NULL,           N_("Escape"),           "Escape",       NULL,   CB(layout_menu_escape_cb) },
1242   { "EscapeAlt1",       NULL,           N_("Escape"),           "Q",            NULL,   CB(layout_menu_escape_cb) },
1243   { "ImageOverlay",     NULL,           N_("_Image Overlay"),   "I",            NULL,   CB(layout_menu_overlay_cb) },
1244   { "HistogramChan",    NULL,   N_("Histogram _channels"),      "K",            NULL,   CB(layout_menu_histogram_chan_cb) },
1245   { "HistogramLog",     NULL,   N_("Histogram _log mode"),      "J",            NULL,   CB(layout_menu_histogram_log_cb) },
1246   { "HideTools",        NULL,           N_("_Hide file list"),  "<control>H",   NULL,   CB(layout_menu_hide_cb) },
1247   { "SlideShowPause",   NULL,           N_("_Pause slideshow"), "P",            NULL,   CB(layout_menu_slideshow_pause_cb) },
1248   { "Refresh",  GTK_STOCK_REFRESH,      N_("_Refresh"),         "R",            NULL,   CB(layout_menu_refresh_cb) },
1249
1250   { "HelpContents",     GTK_STOCK_HELP, N_("_Contents"),        "F1",           NULL,   CB(layout_menu_help_cb) },
1251   { "HelpShortcuts",    NULL,           N_("_Keyboard shortcuts"),NULL,         NULL,   CB(layout_menu_help_keys_cb) },
1252   { "HelpNotes",        NULL,           N_("_Release notes"),   NULL,           NULL,   CB(layout_menu_notes_cb) },
1253   { "About",            NULL,           N_("_About"),           NULL,           NULL,   CB(layout_menu_about_cb) },
1254   { "LogWindow",        NULL,           N_("_Log Window"),      NULL,           NULL,   CB(layout_menu_log_window_cb) }
1255 };
1256
1257 static GtkToggleActionEntry menu_toggle_entries[] = {
1258   { "Thumbnails",       PIXBUF_INLINE_ICON_THUMB,               N_("Show _Thumbnails"), "T",            N_("Show Thumbnails"),  CB(layout_menu_thumb_cb),        FALSE },
1259   { "ShowMarks",        NULL,           N_("Show _Marks"),      "M",            NULL,   CB(layout_menu_marks_cb),        FALSE  },
1260   { "FloatTools",       PIXBUF_INLINE_ICON_FLOAT,               N_("_Float file list"), "L",            NULL,   CB(layout_menu_float_cb),        FALSE  },
1261   { "HideToolbar",      NULL,           N_("Hide tool_bar"),    NULL,           NULL,   CB(layout_menu_toolbar_cb),      FALSE  },
1262   { "SBar",             NULL,           N_("_Info"),            "<control>K",   NULL,   CB(layout_menu_bar_cb),          FALSE  },
1263   { "ExifWin",          NULL,           N_("E_xif window"),     "<control>E",   NULL,   CB(layout_menu_bar_exif_cb),     FALSE  },
1264   { "SBarSort",         NULL,           N_("Sort _manager"),    "<control>S",   NULL,   CB(layout_menu_bar_sort_cb),     FALSE  },
1265   { "SlideShow",        NULL,           N_("Toggle _slideshow"),"S",            NULL,   CB(layout_menu_slideshow_cb),    FALSE  },
1266 };
1267
1268 static GtkRadioActionEntry menu_radio_entries[] = {
1269   { "ViewList",         NULL,           N_("View Images as _List"),             "<control>L",   NULL,   0 },
1270   { "ViewIcons",        NULL,           N_("View Images as I_cons"),            "<control>I",   NULL,   1 }
1271 };
1272
1273 static GtkRadioActionEntry menu_split_radio_entries[] = {
1274   { "SplitHorizontal",  NULL,           N_("Horizontal"),       "E",            NULL,   SPLIT_HOR },
1275   { "SplitVertical",    NULL,           N_("Vertical"),         "U",            NULL,   SPLIT_VERT },
1276   { "SplitQuad",        NULL,           N_("Quad"),             NULL,           NULL,   SPLIT_QUAD },
1277   { "SplitSingle",      NULL,           N_("Single"),           "Y",            NULL,   SPLIT_NONE }
1278 };
1279
1280
1281 #undef CB
1282
1283 static const gchar *menu_ui_description =
1284 "<ui>"
1285 "  <menubar name='MainMenu'>"
1286 "    <menu action='FileMenu'>"
1287 "      <menuitem action='NewWindow'/>"
1288 "      <menuitem action='NewCollection'/>"
1289 "      <menuitem action='OpenCollection'/>"
1290 "      <menuitem action='OpenRecent'/>"
1291 "      <placeholder name='OpenSection'/>"
1292 "      <separator/>"
1293 "      <menuitem action='Search'/>"
1294 "      <menuitem action='FindDupes'/>"
1295 "      <placeholder name='SearchSection'/>"
1296 "      <separator/>"
1297 "      <menuitem action='Print'/>"
1298 "      <placeholder name='PrintSection'/>"
1299 "      <separator/>"
1300 "      <menuitem action='NewFolder'/>"
1301 "      <menuitem action='Copy'/>"
1302 "      <menuitem action='Move'/>"
1303 "      <menuitem action='Rename'/>"
1304 "      <menuitem action='Delete'/>"
1305 "      <placeholder name='FileOpsSection'/>"
1306 "      <separator/>"
1307 "      <placeholder name='QuitSection'/>"
1308 "      <menuitem action='CloseWindow'/>"
1309 "      <menuitem action='Quit'/>"
1310 "      <separator/>"
1311 "    </menu>"
1312 "    <menu action='GoMenu'>"
1313 "      <menuitem action='FirstImage'/>"
1314 "      <menuitem action='PrevImage'/>"
1315 "      <menuitem action='NextImage'/>"
1316 "      <menuitem action='LastImage'/>"
1317 "      <separator/>"
1318 "      <menuitem action='Back'/>"
1319 "      <menuitem action='Home'/>"
1320 "      <separator/>"
1321 "    </menu>"
1322 "    <menu action='SelectMenu'>"
1323 "      <menuitem action='SelectAll'/>"
1324 "      <menuitem action='SelectNone'/>"
1325 "      <menuitem action='SelectInvert'/>"
1326 "      <placeholder name='SelectSection'/>"
1327 "      <separator/>"
1328 "      <menuitem action='CopyPath'/>"
1329 "      <placeholder name='ClipboardSection'/>"
1330 "      <separator/>"
1331 "      <menuitem action='ShowMarks'/>"
1332 "      <placeholder name='MarksSection'/>"
1333 "      <separator/>"
1334 "    </menu>"
1335 "    <menu action='EditMenu'>"
1336 "      <menu action='ExternalMenu'>"
1337 "      </menu>"
1338 "      <placeholder name='EditSection'/>"
1339 "      <separator/>"
1340 "      <menu action='AdjustMenu'>"
1341 "        <menuitem action='RotateCW'/>"
1342 "        <menuitem action='RotateCCW'/>"
1343 "        <menuitem action='Rotate180'/>"
1344 "        <menuitem action='Mirror'/>"
1345 "        <menuitem action='Flip'/>"
1346 "        <menuitem action='Grayscale'/>"
1347 "        <menuitem action='AlterNone'/>"
1348 "      </menu>"
1349 "      <placeholder name='PropertiesSection'/>"
1350 "      <separator/>"
1351 "      <menuitem action='Preferences'/>"
1352 "      <menuitem action='Maintenance'/>"
1353 "      <placeholder name='PreferencesSection'/>"
1354 "      <separator/>"
1355 "      <menuitem action='Wallpaper'/>"
1356 "      <separator/>"
1357 "    </menu>"
1358 "    <menu action='ViewMenu'>"
1359 "      <menuitem action='ViewInNewWindow'/>"
1360 "      <menuitem action='PanView'/>"
1361 "      <placeholder name='WindowSection'/>"
1362 "      <separator/>"
1363 "      <menu action='ZoomMenu'>"
1364 "        <menuitem action='ZoomIn'/>"
1365 "        <menuitem action='ZoomOut'/>"
1366 "        <menuitem action='ZoomFit'/>"
1367 "        <menuitem action='ZoomFillHor'/>"
1368 "        <menuitem action='ZoomFillVert'/>"
1369 "        <menuitem action='Zoom100'/>"
1370 "        <menuitem action='Zoom200'/>"
1371 "        <menuitem action='Zoom300'/>"
1372 "        <menuitem action='Zoom400'/>"
1373 "        <menuitem action='Zoom50'/>"
1374 "        <menuitem action='Zoom33'/>"
1375 "        <menuitem action='Zoom25'/>"
1376 "      </menu>"
1377 "      <menu action='ConnectZoomMenu'>"
1378 "        <menuitem action='ConnectZoomIn'/>"
1379 "        <menuitem action='ConnectZoomOut'/>"
1380 "        <menuitem action='ConnectZoomFit'/>"
1381 "        <menuitem action='ConnectZoomFillHor'/>"
1382 "        <menuitem action='ConnectZoomFillVert'/>"
1383 "        <menuitem action='ConnectZoom100'/>"
1384 "        <menuitem action='ConnectZoom200'/>"
1385 "        <menuitem action='ConnectZoom300'/>"
1386 "        <menuitem action='ConnectZoom400'/>"
1387 "        <menuitem action='ConnectZoom50'/>"
1388 "        <menuitem action='ConnectZoom33'/>"
1389 "        <menuitem action='ConnectZoom25'/>"
1390 "      </menu>"
1391 "      <placeholder name='ZoomSection'/>"
1392 "      <separator/>"
1393 "      <menu action='SplitMenu'>"
1394 "        <menuitem action='SplitHorizontal'/>"
1395 "        <menuitem action='SplitVertical'/>"
1396 "        <menuitem action='SplitQuad'/>"
1397 "        <menuitem action='SplitSingle'/>"
1398 "      </menu>"
1399 "      <separator/>"
1400 "      <menuitem action='ViewList'/>"
1401 "      <menuitem action='ViewIcons'/>"
1402 "      <menuitem action='Thumbnails'/>"
1403 "      <placeholder name='ListSection'/>"
1404 "      <separator/>"
1405 "      <menu action='DirMenu'>"
1406 "        <menuitem action='FolderList'/>"
1407 "        <menuitem action='FolderTree'/>"
1408 "      </menu>"
1409 "      <placeholder name='DirSection'/>"
1410 "      <separator/>"
1411 "      <menuitem action='ImageOverlay'/>"
1412 "      <menuitem action='HistogramChan'/>"
1413 "      <menuitem action='HistogramLog'/>"
1414 "      <menuitem action='FullScreen'/>"
1415 "      <placeholder name='OverlaySection'/>"
1416 "      <separator/>"
1417 "      <menuitem action='FloatTools'/>"
1418 "      <menuitem action='HideTools'/>"
1419 "      <menuitem action='HideToolbar'/>"
1420 "      <placeholder name='ToolsSection'/>"
1421 "      <separator/>"
1422 "      <menuitem action='SBar'/>"
1423 "      <menuitem action='ExifWin'/>"
1424 "      <menuitem action='SBarSort'/>"
1425 "      <placeholder name='SideBarSection'/>"
1426 "      <separator/>"
1427 "      <menuitem action='SlideShow'/>"
1428 "      <menuitem action='SlideShowPause'/>"
1429 "      <menuitem action='Refresh'/>"
1430 "      <placeholder name='SlideShowSection'/>"
1431 "      <separator/>"
1432 "    </menu>"
1433 "    <menu action='HelpMenu'>"
1434 "      <separator/>"
1435 "      <menuitem action='HelpContents'/>"
1436 "      <menuitem action='HelpShortcuts'/>"
1437 "      <menuitem action='HelpNotes'/>"
1438 "      <placeholder name='HelpSection'/>"
1439 "      <separator/>"
1440 "      <menuitem action='About'/>"
1441 "      <separator/>"
1442 "      <menuitem action='LogWindow'/>"
1443 "      <separator/>"
1444 "    </menu>"
1445 "  </menubar>"
1446 "  <toolbar name='ToolBar'>"
1447 "    <toolitem action='Thumbnails'/>"
1448 "    <toolitem action='Back'/>"
1449 "    <toolitem action='Home'/>"
1450 "    <toolitem action='Refresh'/>"
1451 "    <toolitem action='ZoomIn'/>"
1452 "    <toolitem action='ZoomOut'/>"
1453 "    <toolitem action='ZoomFit'/>"
1454 "    <toolitem action='ZoomFit'/>"
1455 "    <toolitem action='Zoom100'/>"
1456 "    <toolitem action='Preferences'/>"
1457 "    <toolitem action='FloatTools'/>"
1458 "  </toolbar>"
1459 "<accelerator action='PrevImageAlt1'/>"
1460 "<accelerator action='PrevImageAlt2'/>"
1461 "<accelerator action='NextImageAlt1'/>"
1462 "<accelerator action='NextImageAlt2'/>"
1463 "<accelerator action='DeleteAlt1'/>"
1464 "<accelerator action='DeleteAlt2'/>"
1465 "<accelerator action='FullScreenAlt1'/>"
1466 "<accelerator action='FullScreenAlt2'/>"
1467 "<accelerator action='Escape'/>"
1468 "<accelerator action='EscapeAlt1'/>"
1469
1470 "<accelerator action='ZoomInAlt1'/>"
1471 "<accelerator action='ZoomOutAlt1'/>"
1472 "<accelerator action='Zoom100Alt1'/>"
1473 "<accelerator action='ZoomFitAlt1'/>"
1474
1475 "<accelerator action='ConnectZoomInAlt1'/>"
1476 "<accelerator action='ConnectZoomOutAlt1'/>"
1477 "<accelerator action='ConnectZoom100Alt1'/>"
1478 "<accelerator action='ConnectZoomFitAlt1'/>"
1479 "</ui>";
1480
1481
1482 static gchar *menu_translate(const gchar *path, gpointer data)
1483 {
1484         return (gchar *)(_(path));
1485 }
1486
1487 static void layout_actions_setup_mark(LayoutWindow *lw, gint mark, gchar *name_tmpl, gchar *label_tmpl, gchar *accel_tmpl,  GCallback cb)
1488 {
1489         gchar name[50];
1490         gchar label[100];
1491         gchar accel[50];
1492         GtkActionEntry entry = { name, NULL, label, accel, NULL, cb };
1493         GtkAction *action;
1494
1495         g_snprintf(name, sizeof(name), name_tmpl, mark);
1496         g_snprintf(label, sizeof(label), label_tmpl, mark);
1497         if (accel_tmpl)
1498                 g_snprintf(accel, sizeof(accel), accel_tmpl, mark % 10);
1499         else
1500                 accel[0] = 0;
1501         gtk_action_group_add_actions(lw->action_group, &entry, 1, lw);
1502         action = gtk_action_group_get_action(lw->action_group, name);
1503         g_object_set_data(G_OBJECT(action), "mark_num", GINT_TO_POINTER(mark));
1504 }
1505
1506 static void layout_actions_setup_marks(LayoutWindow *lw)
1507 {
1508         gint mark;
1509         GError *error;
1510         GString *desc = g_string_new(
1511                                 "<ui>"
1512                                 "  <menubar name='MainMenu'>"
1513                                 "    <menu action='SelectMenu'>");
1514
1515         for (mark = 1; mark <= FILEDATA_MARKS_SIZE; mark++)
1516                 {
1517                 layout_actions_setup_mark(lw, mark, "Mark%d",           _("Mark _%d"), NULL, NULL);
1518                 layout_actions_setup_mark(lw, mark, "SetMark%d",        _("_Set mark %d"),                      NULL, G_CALLBACK(layout_menu_set_mark_sel_cb));
1519                 layout_actions_setup_mark(lw, mark, "ResetMark%d",      _("_Reset mark %d"),                    NULL, G_CALLBACK(layout_menu_res_mark_sel_cb));
1520                 layout_actions_setup_mark(lw, mark, "ToggleMark%d",     _("_Toggle mark %d"),                   "%d", G_CALLBACK(layout_menu_toggle_mark_sel_cb));
1521                 layout_actions_setup_mark(lw, mark, "ToggleMark%dAlt1", _("_Toggle mark %d"),                   "KP_%d", G_CALLBACK(layout_menu_toggle_mark_sel_cb));
1522                 layout_actions_setup_mark(lw, mark, "SelectMark%d",     _("_Select mark %d"),                   "<control>%d", G_CALLBACK(layout_menu_sel_mark_cb));
1523                 layout_actions_setup_mark(lw, mark, "SelectMark%dAlt1", _("_Select mark %d"),                   "<control>KP_%d", G_CALLBACK(layout_menu_sel_mark_cb));
1524                 layout_actions_setup_mark(lw, mark, "AddMark%d",        _("_Add mark %d"),                      NULL, G_CALLBACK(layout_menu_sel_mark_or_cb));
1525                 layout_actions_setup_mark(lw, mark, "IntMark%d",        _("_Intersection with mark %d"),        NULL, G_CALLBACK(layout_menu_sel_mark_and_cb));
1526                 layout_actions_setup_mark(lw, mark, "UnselMark%d",      _("_Unselect mark %d"),                 NULL, G_CALLBACK(layout_menu_sel_mark_minus_cb));
1527
1528                 g_string_append_printf(desc,
1529                                 "      <menu action='Mark%d'>"
1530                                 "        <menuitem action='ToggleMark%d'/>"
1531                                 "        <menuitem action='SetMark%d'/>"
1532                                 "        <menuitem action='ResetMark%d'/>"
1533                                 "        <separator/>"
1534                                 "        <menuitem action='SelectMark%d'/>"
1535                                 "        <menuitem action='AddMark%d'/>"
1536                                 "        <menuitem action='IntMark%d'/>"
1537                                 "        <menuitem action='UnselMark%d'/>"
1538                                 "      </menu>",
1539                                 mark, mark, mark, mark, mark, mark, mark, mark);
1540                 }
1541
1542         g_string_append(desc,
1543                                 "    </menu>"
1544                                 "  </menubar>");
1545         for (mark = 1; mark <= FILEDATA_MARKS_SIZE; mark++)
1546                 {
1547                 g_string_append_printf(desc,
1548                                 "<accelerator action='ToggleMark%dAlt1'/>"
1549                                 "<accelerator action='SelectMark%dAlt1'/>",
1550                                 mark, mark);
1551                 }
1552         g_string_append(desc,   "</ui>" );
1553
1554         error = NULL;
1555         if (!gtk_ui_manager_add_ui_from_string(lw->ui_manager, desc->str, -1, &error))
1556                 {
1557                 g_message("building menus failed: %s", error->message);
1558                 g_error_free(error);
1559                 exit(EXIT_FAILURE);
1560                 }
1561         g_string_free(desc, TRUE);
1562 }
1563
1564 static GList *layout_actions_editor_menu_path(EditorDescription *editor)
1565 {
1566         gchar **split = g_strsplit(editor->menu_path, "/", 0);
1567         gint i = 0;
1568         GList *ret = NULL;
1569         
1570         if (split[0] == NULL) 
1571                 {
1572                 g_strfreev(split);
1573                 return NULL;
1574                 }
1575         
1576         while(split[i])
1577                 {
1578                 ret = g_list_prepend(ret, g_strdup(split[i]));
1579                 i++;
1580                 }
1581         
1582         g_strfreev(split);
1583         
1584         ret = g_list_prepend(ret, g_strdup(editor->key));
1585         
1586         return g_list_reverse(ret);
1587 }
1588
1589 static void layout_actions_editor_add(GString *desc, GList *path, GList *old_path)
1590 {
1591         gint to_open, to_close, i;
1592         while (path && old_path && strcmp((gchar *)path->data, (gchar *)old_path->data) == 0)
1593                 {
1594                 path = path->next;
1595                 old_path = old_path->next;
1596                 }
1597         to_open = g_list_length(path) - 1;
1598         to_close = g_list_length(old_path) - 1;
1599         
1600         if (to_close > 0)
1601                 {
1602                 old_path = g_list_last(old_path);
1603                 old_path = old_path->prev;
1604                 }
1605         
1606         for (i =  0; i < to_close; i++)
1607                 {
1608                 gchar *name = old_path->data;
1609                 if (g_str_has_suffix(name, "Section"))
1610                         {
1611                         g_string_append(desc,   "      </placeholder>");
1612                         }
1613                 else if (g_str_has_suffix(name, "Menu"))
1614                         {
1615                         g_string_append(desc,   "    </menu>");
1616                         }
1617                 else
1618                         {
1619                         g_warning("invalid menu path item %s", name);
1620                         }
1621                 old_path = old_path->prev;
1622                 }
1623
1624         for (i =  0; i < to_open; i++)
1625                 {
1626                 gchar *name = path->data;
1627                 if (g_str_has_suffix(name, "Section"))
1628                         {
1629                         g_string_append_printf(desc,    "      <placeholder name='%s'>", name);
1630                         }
1631                 else if (g_str_has_suffix(name, "Menu"))
1632                         {
1633                         g_string_append_printf(desc,    "    <menu action='%s'>", name);
1634                         }
1635                 else
1636                         {
1637                         g_warning("invalid menu path item %s", name);
1638                         }
1639                 path = path->next;
1640                 }
1641         
1642         if (path)
1643                 g_string_append_printf(desc, "      <menuitem action='%s'/>", (gchar *)path->data);
1644 }
1645
1646 static void layout_actions_setup_editors(LayoutWindow *lw)
1647 {
1648         GError *error;
1649         GList *editors_list;
1650         GList *work;
1651         GList *old_path;
1652         GString *desc = g_string_new(
1653                                 "<ui>"
1654                                 "  <menubar name='MainMenu'>");
1655
1656         editors_list = editor_list_get();
1657         
1658         old_path = NULL;
1659         work = editors_list;
1660         while(work)
1661                 {
1662                 GList *path;
1663                 EditorDescription *editor = work->data;
1664                 GtkActionEntry entry = { editor->key, NULL, editor->name, editor->hotkey, NULL, G_CALLBACK(layout_menu_edit_cb) };
1665                 gtk_action_group_add_actions(lw->action_group_external, &entry, 1, lw);
1666                 
1667                 path = layout_actions_editor_menu_path(editor);
1668                 layout_actions_editor_add(desc, path, old_path);
1669                 
1670                 string_list_free(old_path);
1671                 old_path = path;
1672                 work = work->next;
1673                 }
1674
1675         layout_actions_editor_add(desc, NULL, old_path);
1676         string_list_free(old_path);
1677
1678         g_string_append(desc,   "  </menubar>"
1679                                 "</ui>" );
1680
1681         error = NULL;
1682         if (!gtk_ui_manager_add_ui_from_string(lw->ui_manager, desc->str, -1, &error))
1683                 {
1684                 g_message("building menus failed: %s", error->message);
1685                 g_error_free(error);
1686                 exit(EXIT_FAILURE);
1687                 }
1688         g_string_free(desc, TRUE);
1689         g_list_free(editors_list);
1690 }
1691
1692 void layout_actions_setup(LayoutWindow *lw)
1693 {
1694         GError *error;
1695
1696         if (lw->ui_manager) return;
1697
1698         lw->action_group = gtk_action_group_new("MenuActions");
1699         gtk_action_group_set_translate_func(lw->action_group, menu_translate, NULL, NULL);
1700         lw->action_group_external = gtk_action_group_new("MenuActionsExternal");
1701         /* lw->action_group_external contains translated entries, no translate func is required */
1702
1703         gtk_action_group_add_actions(lw->action_group,
1704                                      menu_entries, G_N_ELEMENTS(menu_entries), lw);
1705         gtk_action_group_add_toggle_actions(lw->action_group,
1706                                             menu_toggle_entries, G_N_ELEMENTS(menu_toggle_entries), lw);
1707         gtk_action_group_add_radio_actions(lw->action_group,
1708                                            menu_radio_entries, G_N_ELEMENTS(menu_radio_entries),
1709                                            0, G_CALLBACK(layout_menu_list_cb), lw);
1710         gtk_action_group_add_radio_actions(lw->action_group,
1711                                            menu_split_radio_entries, G_N_ELEMENTS(menu_split_radio_entries),
1712                                            0, G_CALLBACK(layout_menu_split_cb), lw);
1713         gtk_action_group_add_radio_actions(lw->action_group,
1714                                            menu_view_dir_radio_entries, VIEW_DIR_TYPES_COUNT,
1715                                            0, G_CALLBACK(layout_menu_view_dir_as_cb), lw);
1716
1717         lw->ui_manager = gtk_ui_manager_new();
1718         gtk_ui_manager_set_add_tearoffs(lw->ui_manager, TRUE);
1719         gtk_ui_manager_insert_action_group(lw->ui_manager, lw->action_group, 0);
1720         gtk_ui_manager_insert_action_group(lw->ui_manager, lw->action_group_external, 1);
1721
1722         error = NULL;
1723         if (!gtk_ui_manager_add_ui_from_string(lw->ui_manager, menu_ui_description, -1, &error))
1724                 {
1725                 g_message("building menus failed: %s", error->message);
1726                 g_error_free(error);
1727                 exit(EXIT_FAILURE);
1728                 }
1729         
1730         layout_actions_setup_marks(lw);
1731         layout_actions_setup_editors(lw);
1732         layout_copy_path_update(lw);
1733 }
1734
1735 void layout_actions_add_window(LayoutWindow *lw, GtkWidget *window)
1736 {
1737         GtkAccelGroup *group;
1738
1739         if (!lw->ui_manager) return;
1740
1741         group = gtk_ui_manager_get_accel_group(lw->ui_manager);
1742         gtk_window_add_accel_group(GTK_WINDOW(window), group);
1743 }
1744
1745 GtkWidget *layout_actions_menu_bar(LayoutWindow *lw)
1746 {
1747         return gtk_ui_manager_get_widget(lw->ui_manager, "/MainMenu");
1748 }
1749
1750 GtkWidget *layout_button_bar(LayoutWindow *lw)
1751 {
1752         GtkWidget *bar = gtk_ui_manager_get_widget(lw->ui_manager, "/ToolBar");
1753         gtk_toolbar_set_icon_size(GTK_TOOLBAR(bar), GTK_ICON_SIZE_SMALL_TOOLBAR);
1754         gtk_toolbar_set_style(GTK_TOOLBAR(bar), GTK_TOOLBAR_ICONS);
1755         return bar;
1756 }
1757
1758 /*
1759  *-----------------------------------------------------------------------------
1760  * misc
1761  *-----------------------------------------------------------------------------
1762  */
1763
1764 static void layout_util_sync_views(LayoutWindow *lw)
1765 {
1766         GtkAction *action;
1767
1768         if (!lw->action_group) return;
1769
1770         action = gtk_action_group_get_action(lw->action_group, "FolderTree");
1771         radio_action_set_current_value(GTK_RADIO_ACTION(action), lw->options.dir_view_type);
1772
1773         action = gtk_action_group_get_action(lw->action_group, "ViewIcons");
1774         gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), lw->file_view_type);
1775
1776         action = gtk_action_group_get_action(lw->action_group, "FloatTools");
1777         gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), lw->options.tools_float);
1778
1779         action = gtk_action_group_get_action(lw->action_group, "SBar");
1780         gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), layout_bar_enabled(lw));
1781
1782         action = gtk_action_group_get_action(lw->action_group, "SBarSort");
1783         gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), layout_bar_sort_enabled(lw));
1784
1785         action = gtk_action_group_get_action(lw->action_group, "HideToolbar");
1786         gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), lw->options.toolbar_hidden);
1787
1788         action = gtk_action_group_get_action(lw->action_group, "ShowMarks");
1789         gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), lw->options.show_marks);
1790
1791         action = gtk_action_group_get_action(lw->action_group, "SlideShow");
1792         gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), layout_image_slideshow_active(lw));
1793
1794         action = gtk_action_group_get_action(lw->action_group, "ExifWin");
1795         gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), !!lw->exif_window);
1796
1797 }
1798
1799 void layout_util_sync_thumb(LayoutWindow *lw)
1800 {
1801         GtkAction *action;
1802
1803         if (!lw->action_group) return;
1804
1805         action = gtk_action_group_get_action(lw->action_group, "Thumbnails");
1806         gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), lw->options.show_thumbnails);
1807         g_object_set(action, "sensitive", (lw->file_view_type == FILEVIEW_LIST), NULL);
1808 }
1809
1810 void layout_util_sync(LayoutWindow *lw)
1811 {
1812         layout_util_sync_views(lw);
1813         layout_util_sync_thumb(lw);
1814         layout_menu_recent_update(lw);
1815 //      layout_menu_edit_update(lw);
1816 }
1817
1818 /*
1819  *-----------------------------------------------------------------------------
1820  * icons (since all the toolbar icons are included here, best place as any)
1821  *-----------------------------------------------------------------------------
1822  */
1823
1824 PixmapFolders *folder_icons_new(void)
1825 {
1826         PixmapFolders *pf;
1827
1828         pf = g_new0(PixmapFolders, 1);
1829
1830         pf->close = pixbuf_inline(PIXBUF_INLINE_FOLDER_CLOSED);
1831         pf->open = pixbuf_inline(PIXBUF_INLINE_FOLDER_OPEN);
1832         pf->deny = pixbuf_inline(PIXBUF_INLINE_FOLDER_LOCKED);
1833         pf->parent = pixbuf_inline(PIXBUF_INLINE_FOLDER_UP);
1834
1835         return pf;
1836 }
1837
1838 void folder_icons_free(PixmapFolders *pf)
1839 {
1840         if (!pf) return;
1841
1842         g_object_unref(pf->close);
1843         g_object_unref(pf->open);
1844         g_object_unref(pf->deny);
1845         g_object_unref(pf->parent);
1846
1847         g_free(pf);
1848 }
1849
1850 /*
1851  *-----------------------------------------------------------------------------
1852  * sidebars
1853  *-----------------------------------------------------------------------------
1854  */
1855
1856 static gboolean layout_bar_enabled(LayoutWindow *lw)
1857 {
1858         return lw->bar && GTK_WIDGET_VISIBLE(lw->bar);
1859 }
1860
1861 static void layout_bar_destroyed(GtkWidget *widget, gpointer data)
1862 {
1863         LayoutWindow *lw = data;
1864
1865         lw->bar = NULL;
1866 /* 
1867     do not call layout_util_sync_views(lw) here
1868     this is called either when whole layout is destroyed - no need for update
1869     or when the bar is replaced - sync is called by upper function at the end of whole operation
1870
1871 */
1872 }
1873
1874 static GList *layout_bar_list_cb(gpointer data)
1875 {
1876         LayoutWindow *lw = data;
1877
1878         return layout_selection_list(lw);
1879 }
1880
1881 static void layout_bar_set_default(LayoutWindow *lw)
1882 {
1883         GtkWidget *bar;
1884         
1885         if (!lw->utility_box) return;
1886
1887         bar = bar_new_default(lw->utility_box);
1888         
1889         layout_bar_set(lw, bar);
1890 }
1891
1892 static void layout_bar_close(LayoutWindow *lw)
1893 {
1894         if (lw->bar)
1895                 {
1896                 bar_close(lw->bar);
1897                 lw->bar = NULL;
1898                 }
1899 }
1900
1901
1902 void layout_bar_set(LayoutWindow *lw, GtkWidget *bar)
1903 {
1904         if (!lw->utility_box) return;
1905
1906         layout_bar_close(lw); /* if any */
1907
1908         if (!bar) return;
1909         lw->bar = bar;
1910
1911         bar_set_selection_func(lw->bar, layout_bar_list_cb, lw);
1912         g_signal_connect(G_OBJECT(lw->bar), "destroy",
1913                          G_CALLBACK(layout_bar_destroyed), lw);
1914
1915
1916         gtk_box_pack_start(GTK_BOX(lw->utility_box), lw->bar, FALSE, FALSE, 0);
1917
1918         bar_set_fd(lw->bar, layout_image_get_fd(lw));
1919 }
1920
1921
1922 void layout_bar_toggle(LayoutWindow *lw)
1923 {
1924         if (layout_bar_enabled(lw))
1925                 {
1926                 gtk_widget_hide(lw->bar);
1927                 }
1928         else
1929                 {
1930                 if (!lw->bar)
1931                         {
1932                         layout_bar_set_default(lw);
1933                         }
1934                 gtk_widget_show(lw->bar);
1935                 }
1936         layout_util_sync_views(lw);
1937 }
1938
1939 static void layout_bar_new_image(LayoutWindow *lw)
1940 {
1941         if (!layout_bar_enabled(lw)) return;
1942
1943         bar_set_fd(lw->bar, layout_image_get_fd(lw));
1944 }
1945
1946 static void layout_bar_new_selection(LayoutWindow *lw, gint count)
1947 {
1948         if (!layout_bar_enabled(lw)) return;
1949
1950 //      bar_info_selection(lw->bar_info, count - 1);
1951 }
1952
1953 static gboolean layout_bar_sort_enabled(LayoutWindow *lw)
1954 {
1955         return lw->bar_sort && GTK_WIDGET_VISIBLE(lw->bar_sort);
1956 }
1957
1958
1959 static void layout_bar_sort_destroyed(GtkWidget *widget, gpointer data)
1960 {
1961         LayoutWindow *lw = data;
1962
1963         lw->bar_sort = NULL;
1964
1965 /* 
1966     do not call layout_util_sync_views(lw) here
1967     this is called either when whole layout is destroyed - no need for update
1968     or when the bar is replaced - sync is called by upper function at the end of whole operation
1969
1970 */
1971 }
1972
1973 static void layout_bar_sort_set_default(LayoutWindow *lw)
1974 {
1975         GtkWidget *bar;
1976         
1977         if (!lw->utility_box) return;
1978
1979         bar = bar_sort_new_default(lw);
1980         
1981         layout_bar_sort_set(lw, bar);
1982 }
1983
1984 static void layout_bar_sort_close(LayoutWindow *lw)
1985 {
1986         if (lw->bar_sort)
1987                 {
1988                 bar_sort_close(lw->bar_sort);
1989                 lw->bar_sort = NULL;
1990                 }
1991 }
1992
1993 void layout_bar_sort_set(LayoutWindow *lw, GtkWidget *bar)
1994 {
1995         if (!lw->utility_box) return;
1996
1997         layout_bar_sort_close(lw); /* if any */
1998
1999         if (!bar) return;
2000         lw->bar_sort = bar;
2001
2002         g_signal_connect(G_OBJECT(lw->bar_sort), "destroy",
2003                          G_CALLBACK(layout_bar_sort_destroyed), lw);
2004
2005         gtk_box_pack_end(GTK_BOX(lw->utility_box), lw->bar_sort, FALSE, FALSE, 0);
2006 }
2007
2008 void layout_bar_sort_toggle(LayoutWindow *lw)
2009 {
2010         if (layout_bar_sort_enabled(lw))
2011                 {
2012                 gtk_widget_hide(lw->bar_sort);
2013                 }
2014         else
2015                 {
2016                 if (!lw->bar_sort)
2017                         {
2018                         layout_bar_sort_set_default(lw);
2019                         }
2020                 gtk_widget_show(lw->bar_sort);
2021                 }
2022         layout_util_sync_views(lw);
2023 }
2024
2025 void layout_bars_new_image(LayoutWindow *lw)
2026 {
2027         layout_bar_new_image(lw);
2028
2029         if (lw->exif_window) advanced_exif_set_fd(lw->exif_window, layout_image_get_fd(lw));
2030
2031         /* this should be called here to handle the metadata edited in bars */
2032         if (options->metadata.confirm_on_image_change)
2033                 metadata_write_queue_confirm(NULL, NULL);
2034 }
2035
2036 void layout_bars_new_selection(LayoutWindow *lw, gint count)
2037 {
2038         layout_bar_new_selection(lw, count);
2039 }
2040
2041 GtkWidget *layout_bars_prepare(LayoutWindow *lw, GtkWidget *image)
2042 {
2043         lw->utility_box = gtk_hbox_new(FALSE, PREF_PAD_GAP);
2044         gtk_box_pack_start(GTK_BOX(lw->utility_box), image, TRUE, TRUE, 0);
2045         gtk_widget_show(image);
2046
2047         return lw->utility_box;
2048 }
2049
2050 void layout_bars_close(LayoutWindow *lw)
2051 {
2052         layout_bar_sort_close(lw);
2053         layout_bar_close(lw);
2054 }
2055
2056 static void layout_exif_window_destroy(GtkWidget *widget, gpointer data)
2057 {
2058         LayoutWindow *lw = data;
2059         lw->exif_window = NULL;
2060 }
2061
2062 void layout_exif_window_new(LayoutWindow *lw)
2063 {
2064         if (!lw->exif_window) 
2065                 {
2066                 lw->exif_window = advanced_exif_new();
2067                 if (!lw->exif_window) return;
2068                 g_signal_connect(G_OBJECT(lw->exif_window), "destroy",
2069                                  G_CALLBACK(layout_exif_window_destroy), lw);
2070                 advanced_exif_set_fd(lw->exif_window, layout_image_get_fd(lw));
2071                 }
2072 }
2073
2074 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */