500624168e7c8bb4c626a4d9713f50418807aa6b
[geeqie.git] / src / layout.c
1 /*
2  * Copyright (C) 2006 John Ellis
3  * Copyright (C) 2008 - 2016 The Geeqie Team
4  *
5  * Author: John Ellis
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21
22 #include "main.h"
23 #include "layout.h"
24
25 #include "color-man.h"
26 #include "filedata.h"
27 #include "histogram.h"
28 #include "history_list.h"
29 #include "image.h"
30 #include "image-overlay.h"
31 #include "layout_config.h"
32 #include "layout_image.h"
33 #include "layout_util.h"
34 #include "logwindow.h"
35 #include "menu.h"
36 #include "pixbuf-renderer.h"
37 #include "pixbuf_util.h"
38 #include "utilops.h"
39 #include "view_dir.h"
40 #include "view_file.h"
41 #include "ui_fileops.h"
42 #include "ui_menu.h"
43 #include "ui_misc.h"
44 #include "ui_tabcomp.h"
45 #include "window.h"
46 #include "metadata.h"
47 #include "rcfile.h"
48 #include "bar.h"
49 #include "bar_sort.h"
50 #include "preferences.h"
51 #include "shortcuts.h"
52 #ifdef HAVE_LIRC
53 #include "lirc.h"
54 #endif
55
56 #define MAINWINDOW_DEF_WIDTH 700
57 #define MAINWINDOW_DEF_HEIGHT 500
58
59 #define MAIN_WINDOW_DIV_HPOS (MAINWINDOW_DEF_WIDTH / 2)
60 #define MAIN_WINDOW_DIV_VPOS (MAINWINDOW_DEF_HEIGHT / 2)
61
62 #define TOOLWINDOW_DEF_WIDTH 260
63 #define TOOLWINDOW_DEF_HEIGHT 450
64
65 #define PROGRESS_WIDTH 150
66 #define ZOOM_LABEL_WIDTH 64
67
68 #define PANE_DIVIDER_SIZE 10
69
70
71 GList *layout_window_list = NULL;
72 LayoutWindow *current_lw = NULL;
73
74 static void layout_list_scroll_to_subpart(LayoutWindow *lw, const gchar *needle);
75
76
77 /*
78  *-----------------------------------------------------------------------------
79  * misc
80  *-----------------------------------------------------------------------------
81  */
82
83 gboolean layout_valid(LayoutWindow **lw)
84 {
85         if (*lw == NULL)
86                 {
87                 if (current_lw) *lw = current_lw;
88                 else if (layout_window_list) *lw = layout_window_list->data;
89                 return (*lw != NULL);
90                 }
91         return (g_list_find(layout_window_list, *lw) != NULL);
92 }
93
94 LayoutWindow *layout_find_by_image(ImageWindow *imd)
95 {
96         GList *work;
97
98         work = layout_window_list;
99         while (work)
100                 {
101                 LayoutWindow *lw = work->data;
102                 work = work->next;
103
104                 if (lw->image == imd) return lw;
105                 }
106
107         return NULL;
108 }
109
110 LayoutWindow *layout_find_by_image_fd(ImageWindow *imd)
111 {
112         GList *work;
113
114         work = layout_window_list;
115         while (work)
116                 {
117                 LayoutWindow *lw = work->data;
118                 work = work->next;
119
120                 if (lw->image->image_fd == imd->image_fd)
121                         return lw;
122                 }
123
124         return NULL;
125 }
126
127 LayoutWindow *layout_find_by_layout_id(const gchar *id)
128 {
129         GList *work;
130
131         if (!id || !id[0]) return NULL;
132
133         if (strcmp(id, LAYOUT_ID_CURRENT) == 0)
134                 {
135                 if (current_lw) return current_lw;
136                 if (layout_window_list) return layout_window_list->data;
137                 return NULL;
138                 }
139
140         work = layout_window_list;
141         while (work)
142                 {
143                 LayoutWindow *lw = work->data;
144                 work = work->next;
145
146                 if (lw->options.id && strcmp(id, lw->options.id) == 0)
147                         return lw;
148                 }
149
150         return NULL;
151 }
152
153 static void layout_set_unique_id(LayoutWindow *lw)
154 {
155         char id[10];
156         gint i;
157         if (lw->options.id && lw->options.id[0]) return; /* id is already set */
158
159         g_free(lw->options.id);
160         lw->options.id = NULL;
161
162         if (!layout_find_by_layout_id("main"))
163                 {
164                 lw->options.id = g_strdup("main");
165                 return;
166                 }
167
168         i = 1;
169         while (TRUE)
170                 {
171                 g_snprintf(id, sizeof(id), "lw%d", i);
172                 if (!layout_find_by_layout_id(id))
173                         {
174                         lw->options.id = g_strdup(id);
175                         return;
176                         }
177                 i++;
178                 }
179 }
180
181 static gboolean layout_set_current_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data)
182 {
183         LayoutWindow *lw = data;
184         current_lw = lw;
185         return FALSE;
186 }
187
188 static void layout_box_folders_changed_cb(GtkWidget *widget, gpointer data)
189 {
190         LayoutWindow *lw;
191         GList *work;
192
193 /* FIXME: this is probably not the correct way to implement this */
194         work = layout_window_list;
195         while (work)
196                 {
197                 lw = work->data;
198                 lw->options.folder_window.vdivider_pos = gtk_paned_get_position(GTK_PANED(widget));
199                 work = work->next;
200                 }
201 }
202
203 /*
204  *-----------------------------------------------------------------------------
205  * menu, toolbar, and dir view
206  *-----------------------------------------------------------------------------
207  */
208
209 static void layout_path_entry_changed_cb(GtkWidget *widget, gpointer data)
210 {
211         LayoutWindow *lw = data;
212         gchar *buf;
213
214         if (gtk_combo_box_get_active(GTK_COMBO_BOX(widget)) < 0) return;
215
216         buf = g_strdup(gtk_entry_get_text(GTK_ENTRY(lw->path_entry)));
217         if (!lw->dir_fd || strcmp(buf, lw->dir_fd->path) != 0)
218                 {
219                 layout_set_path(lw, buf);
220                 }
221
222         g_free(buf);
223 }
224
225 static void layout_path_entry_tab_cb(const gchar *path, gpointer data)
226 {
227         LayoutWindow *lw = data;
228         gchar *buf;
229
230         buf = g_strdup(path);
231         parse_out_relatives(buf);
232
233         if (isdir(buf))
234                 {
235                 if ((!lw->dir_fd || strcmp(lw->dir_fd->path, buf) != 0) && layout_set_path(lw, buf))
236                         {
237                         gtk_widget_grab_focus(GTK_WIDGET(lw->path_entry));
238                         gint pos = -1;
239                         /* put the G_DIR_SEPARATOR back, if we are in tab completion for a dir and result was path change */
240                         gtk_editable_insert_text(GTK_EDITABLE(lw->path_entry), G_DIR_SEPARATOR_S, -1, &pos);
241                         gtk_editable_set_position(GTK_EDITABLE(lw->path_entry),
242                                                   strlen(gtk_entry_get_text(GTK_ENTRY(lw->path_entry))));
243                         }
244                 }
245         else if (lw->dir_fd)
246                 {
247                 gchar *base = remove_level_from_path(buf);
248
249                 if (strcmp(lw->dir_fd->path, base) == 0)
250                         {
251                         layout_list_scroll_to_subpart(lw, filename_from_path(buf));
252                         }
253                 g_free(base);
254                 }
255
256         g_free(buf);
257 }
258
259 static void layout_path_entry_cb(const gchar *path, gpointer data)
260 {
261         LayoutWindow *lw = data;
262         gchar *buf;
263
264         buf = g_strdup(path);
265         parse_out_relatives(buf);
266
267         layout_set_path(lw, buf);
268
269         g_free(buf);
270 }
271
272 static void layout_vd_select_cb(ViewDir *vd, FileData *fd, gpointer data)
273 {
274         LayoutWindow *lw = data;
275
276         layout_set_fd(lw, fd);
277 }
278
279 static void layout_path_entry_tab_append_cb(const gchar *path, gpointer data, gint n)
280 {
281         LayoutWindow *lw = data;
282
283         if (!lw || !lw->back_button) return;
284         if (!layout_valid(&lw)) return;
285
286         /* Enable back button if it makes sense */
287         gtk_widget_set_sensitive(lw->back_button, (n > 1));
288 }
289
290 static gboolean path_entry_tooltip_cb(GtkWidget *widget, gpointer data)
291 {
292         LayoutWindow *lw = data;
293         GList *box_child_list;
294         GtkComboBox *path_entry;
295         gchar *current_path;
296
297         box_child_list = gtk_container_get_children(GTK_CONTAINER(widget));
298         path_entry = box_child_list->data;
299         current_path = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(path_entry));
300         gtk_widget_set_tooltip_text(GTK_WIDGET(widget), current_path);
301
302         g_free(current_path);
303         g_list_free(box_child_list);
304
305         return FALSE;
306 }
307
308 static GtkWidget *layout_tool_setup(LayoutWindow *lw)
309 {
310         GtkWidget *box;
311         GtkWidget *box_folders;
312         GtkWidget *scd;
313         GtkWidget *menu_tool_bar;
314         GtkWidget *tabcomp;
315
316         box = gtk_vbox_new(FALSE, 0);
317
318         menu_tool_bar = layout_actions_menu_tool_bar(lw);
319         gtk_widget_show(menu_tool_bar);
320         gtk_box_pack_start(GTK_BOX(lw->main_box), lw->menu_tool_bar, FALSE, FALSE, 0);
321         if (lw->options.toolbar_hidden) gtk_widget_hide(lw->toolbar[TOOLBAR_MAIN]);
322
323         tabcomp = tab_completion_new_with_history(&lw->path_entry, NULL, "path_list", -1,
324                                                   layout_path_entry_cb, lw);
325         tab_completion_add_tab_func(lw->path_entry, layout_path_entry_tab_cb, lw);
326         tab_completion_add_append_func(lw->path_entry, layout_path_entry_tab_append_cb, lw);
327         gtk_box_pack_start(GTK_BOX(box), tabcomp, FALSE, FALSE, 0);
328         gtk_widget_show(tabcomp);
329         gtk_widget_set_has_tooltip(GTK_WIDGET(tabcomp), TRUE);
330         g_signal_connect(G_OBJECT(tabcomp), "query_tooltip", G_CALLBACK(path_entry_tooltip_cb), lw);
331
332 #if GTK_CHECK_VERSION(3,20,0)
333         g_signal_connect(G_OBJECT(gtk_widget_get_parent(gtk_widget_get_parent(lw->path_entry))), "changed",
334                          G_CALLBACK(layout_path_entry_changed_cb), lw);
335 #else
336         g_signal_connect(G_OBJECT(gtk_widget_get_parent(lw->path_entry)), "changed",
337                          G_CALLBACK(layout_path_entry_changed_cb), lw);
338 #endif
339
340         box_folders = GTK_WIDGET(gtk_hpaned_new());
341         gtk_box_pack_start(GTK_BOX(box), box_folders, TRUE, TRUE, 0);
342
343         lw->vd = vd_new(lw->options.dir_view_type, lw->dir_fd);
344         vd_set_layout(lw->vd, lw);
345         vd_set_select_func(lw->vd, layout_vd_select_cb, lw);
346
347         lw->dir_view = lw->vd->widget;
348         gtk_paned_add2(GTK_PANED(box_folders), lw->dir_view);
349         gtk_widget_show(lw->dir_view);
350
351         scd = shortcuts_new_default(lw);
352         gtk_paned_add1(GTK_PANED(box_folders), scd);
353         gtk_paned_set_position(GTK_PANED(box_folders), lw->options.folder_window.vdivider_pos);
354
355         gtk_widget_show(box_folders);
356
357         g_signal_connect(G_OBJECT(box_folders), "notify::position",
358                          G_CALLBACK(layout_box_folders_changed_cb), lw);
359
360         gtk_widget_show(box);
361
362         return box;
363 }
364
365 /*
366  *-----------------------------------------------------------------------------
367  * sort button (and menu)
368  *-----------------------------------------------------------------------------
369  */
370
371 static void layout_sort_menu_cb(GtkWidget *widget, gpointer data)
372 {
373         LayoutWindow *lw;
374         SortType type;
375
376         if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) return;
377
378         lw = submenu_item_get_data(widget);
379         if (!lw) return;
380
381         type = (SortType)GPOINTER_TO_INT(data);
382
383         if (type == SORT_EXIFTIME || type == SORT_EXIFTIMEDIGITIZED || type == SORT_RATING)
384                 {
385                 vf_read_metadata_in_idle(lw->vf);
386                 }
387         layout_sort_set(lw, type, lw->sort_ascend);
388 }
389
390 static void layout_sort_menu_ascend_cb(GtkWidget *widget, gpointer data)
391 {
392         LayoutWindow *lw = data;
393
394         layout_sort_set(lw, lw->sort_method, !lw->sort_ascend);
395 }
396
397 static void layout_sort_menu_hide_cb(GtkWidget *widget, gpointer data)
398 {
399         /* destroy the menu */
400         g_object_unref(widget);
401 }
402
403 static void layout_sort_button_press_cb(GtkWidget *widget, gpointer data)
404 {
405         LayoutWindow *lw = data;
406         GtkWidget *menu;
407         GdkEvent *event;
408         guint32 etime;
409
410         menu = submenu_add_sort(NULL, G_CALLBACK(layout_sort_menu_cb), lw, FALSE, FALSE, TRUE, lw->sort_method);
411
412         /* take ownership of menu */
413 #ifdef GTK_OBJECT_FLOATING
414         /* GTK+ < 2.10 */
415         g_object_ref(G_OBJECT(menu));
416         gtk_object_sink(GTK_OBJECT(menu));
417 #else
418         /* GTK+ >= 2.10 */
419         g_object_ref_sink(G_OBJECT(menu));
420 #endif
421
422         /* ascending option */
423         menu_item_add_divider(menu);
424         menu_item_add_check(menu, _("Ascending"), lw->sort_ascend, G_CALLBACK(layout_sort_menu_ascend_cb), lw);
425
426         g_signal_connect(G_OBJECT(menu), "selection_done",
427                          G_CALLBACK(layout_sort_menu_hide_cb), NULL);
428
429         event = gtk_get_current_event();
430         if (event)
431                 {
432                 etime = gdk_event_get_time(event);
433                 gdk_event_free(event);
434                 }
435         else
436                 {
437                 etime = 0;
438                 }
439
440         gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 0, etime);
441 }
442
443 static GtkWidget *layout_sort_button(LayoutWindow *lw)
444 {
445         GtkWidget *button;
446
447         button = gtk_button_new_with_label(sort_type_get_text(lw->sort_method));
448         g_signal_connect(G_OBJECT(button), "clicked",
449                          G_CALLBACK(layout_sort_button_press_cb), lw);
450         gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
451
452         return button;
453 }
454
455 static void layout_zoom_menu_cb(GtkWidget *widget, gpointer data)
456 {
457         ZoomMode mode;
458
459         if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) return;
460
461         mode = (ZoomMode)GPOINTER_TO_INT(data);
462         options->image.zoom_mode = mode;
463 }
464
465 static void layout_scroll_menu_cb(GtkWidget *widget, gpointer data)
466 {
467         guint scroll_type;
468
469         if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) return;
470
471         scroll_type = GPOINTER_TO_UINT(data);
472         options->image.scroll_reset_method = scroll_type;
473         image_options_sync();
474 }
475
476 static void layout_zoom_menu_hide_cb(GtkWidget *widget, gpointer data)
477 {
478         /* destroy the menu */
479         g_object_unref(widget);
480 }
481
482 static void layout_zoom_button_press_cb(GtkWidget *widget, gpointer data)
483 {
484         LayoutWindow *lw = data;
485         GtkWidget *menu;
486         GdkEvent *event;
487         guint32 etime;
488
489         menu = submenu_add_zoom(NULL, G_CALLBACK(layout_zoom_menu_cb),
490                         lw, FALSE, FALSE, TRUE, options->image.zoom_mode);
491
492         /* take ownership of menu */
493 #ifdef GTK_OBJECT_FLOATING
494         /* GTK+ < 2.10 */
495         g_object_ref(G_OBJECT(menu));
496         gtk_object_sink(GTK_OBJECT(menu));
497 #else
498         /* GTK+ >= 2.10 */
499         g_object_ref_sink(G_OBJECT(menu));
500 #endif
501
502         menu_item_add_divider(menu);
503
504         menu_item_add_radio(menu, _("Scroll to top left corner"),
505                         GUINT_TO_POINTER(SCROLL_RESET_TOPLEFT),
506                         options->image.scroll_reset_method == SCROLL_RESET_TOPLEFT,
507                         G_CALLBACK(layout_scroll_menu_cb),
508                         GUINT_TO_POINTER(SCROLL_RESET_TOPLEFT));
509         menu_item_add_radio(menu, _("Scroll to image center"),
510                         GUINT_TO_POINTER(SCROLL_RESET_CENTER),
511                         options->image.scroll_reset_method == SCROLL_RESET_CENTER,
512                         G_CALLBACK(layout_scroll_menu_cb),
513                         GUINT_TO_POINTER(SCROLL_RESET_CENTER));
514         menu_item_add_radio(menu, _("Keep the region from previous image"),
515                         GUINT_TO_POINTER(SCROLL_RESET_NOCHANGE),
516                         options->image.scroll_reset_method == SCROLL_RESET_NOCHANGE,
517                         G_CALLBACK(layout_scroll_menu_cb),
518                         GUINT_TO_POINTER(SCROLL_RESET_NOCHANGE));
519
520         g_signal_connect(G_OBJECT(menu), "selection_done",
521                          G_CALLBACK(layout_zoom_menu_hide_cb), NULL);
522
523         event = gtk_get_current_event();
524         if (event)
525                 {
526                 etime = gdk_event_get_time(event);
527                 gdk_event_free(event);
528                 }
529         else
530                 {
531                 etime = 0;
532                 }
533
534         gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 0, etime);
535 }
536
537 static GtkWidget *layout_zoom_button(LayoutWindow *lw, GtkWidget *box, gint size, gboolean expand)
538 {
539         GtkWidget *button;
540         GtkWidget *frame;
541
542
543         frame = gtk_frame_new(NULL);
544         if (size) gtk_widget_set_size_request(frame, size, -1);
545         gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
546
547         gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 0);
548
549         gtk_widget_show(frame);
550
551         button = gtk_button_new_with_label("1:1");
552         g_signal_connect(G_OBJECT(button), "clicked",
553                          G_CALLBACK(layout_zoom_button_press_cb), lw);
554         gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
555
556         gtk_container_add(GTK_CONTAINER(frame), button);
557         gtk_widget_show(button);
558
559         return button;
560 }
561
562 /*
563  *-----------------------------------------------------------------------------
564  * status bar
565  *-----------------------------------------------------------------------------
566  */
567
568
569 void layout_status_update_progress(LayoutWindow *lw, gdouble val, const gchar *text)
570 {
571         static gdouble thumb = 0;
572         static gdouble meta = 0;
573
574         if (!layout_valid(&lw)) return;
575         if (!lw->info_progress_bar) return;
576
577         /* Give priority to the loading meta data message
578          */
579         if(!g_strcmp0(text, "Loading thumbs..."))
580                 {
581                 thumb = val;
582                 if (meta)
583                         {
584                         return;
585                         }
586                 }
587         else
588                 {
589                 meta = val;
590                 }
591
592         gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(lw->info_progress_bar), val);
593         gtk_progress_bar_set_text(GTK_PROGRESS_BAR(lw->info_progress_bar),
594                                                                         val ? ((text) ? text : " ") : " ");
595 }
596
597 void layout_status_update_info(LayoutWindow *lw, const gchar *text)
598 {
599         gchar *buf = NULL;
600
601         if (!layout_valid(&lw)) return;
602
603         if (!text)
604                 {
605                 guint n;
606                 gint64 n_bytes = 0;
607
608                 n = layout_list_count(lw, &n_bytes);
609
610                 if (n)
611                         {
612                         guint s;
613                         gint64 s_bytes = 0;
614                         const gchar *ss;
615
616                         if (layout_image_slideshow_active(lw))
617                                 {
618                                 if (!layout_image_slideshow_paused(lw))
619                                         {
620                                         ss = _(" Slideshow");
621                                         }
622                                 else
623                                         {
624                                         ss = _(" Paused");
625                                         }
626                                 }
627                         else
628                                 {
629                                 ss = "";
630                                 }
631
632                         s = layout_selection_count(lw, &s_bytes);
633
634                         layout_bars_new_selection(lw, s);
635
636                         if (s > 0)
637                                 {
638                                 gchar *b = text_from_size_abrev(n_bytes);
639                                 gchar *sb = text_from_size_abrev(s_bytes);
640                                 buf = g_strdup_printf(_("%s, %d files (%s, %d)%s"), b, n, sb, s, ss);
641                                 g_free(b);
642                                 g_free(sb);
643                                 }
644                         else if (n > 0)
645                                 {
646                                 gchar *b = text_from_size_abrev(n_bytes);
647                                 buf = g_strdup_printf(_("%s, %d files%s"), b, n, ss);
648                                 g_free(b);
649                                 }
650                         else
651                                 {
652                                 buf = g_strdup_printf(_("%d files%s"), n, ss);
653                                 }
654
655                         text = buf;
656
657                         image_osd_update(lw->image);
658                         }
659                 else
660                         {
661                         text = "";
662                         }
663         }
664
665         if (lw->info_status) gtk_label_set_text(GTK_LABEL(lw->info_status), text);
666         g_free(buf);
667 }
668
669 void layout_status_update_image(LayoutWindow *lw)
670 {
671         guint64 n;
672
673         if (!layout_valid(&lw) || !lw->image) return;
674         if (!lw->info_zoom || !lw->info_details) return; /*called from layout_style_set */
675
676         n = layout_list_count(lw, NULL);
677
678         if (!n)
679                 {
680                 gtk_button_set_label(GTK_BUTTON(lw->info_zoom), "");
681                 gtk_label_set_text(GTK_LABEL(lw->info_details), "");
682                 }
683         else
684                 {
685                 gchar *text;
686                 gchar *b;
687
688                 text = image_zoom_get_as_text(lw->image);
689                 gtk_button_set_label(GTK_BUTTON(lw->info_zoom), text);
690                 g_free(text);
691
692                 b = image_get_fd(lw->image) ? text_from_size(image_get_fd(lw->image)->size) : g_strdup("0");
693
694                 if (lw->image->unknown)
695                         {
696                         if (image_get_path(lw->image) && !access_file(image_get_path(lw->image), R_OK))
697                                 {
698                                 text = g_strdup_printf(_("(no read permission) %s bytes"), b);
699                                 }
700                         else
701                                 {
702                                 text = g_strdup_printf(_("( ? x ? ) %s bytes"), b);
703                                 }
704                         }
705                 else
706                         {
707                         gint width, height;
708
709                         image_get_image_size(lw->image, &width, &height);
710                         text = g_strdup_printf(_("( %d x %d ) %s bytes"),
711                                                width, height, b);
712                         }
713
714                 g_signal_emit_by_name (lw->image->pr, "update-pixel");
715
716                 g_free(b);
717
718                 gtk_label_set_text(GTK_LABEL(lw->info_details), text);
719                 g_free(text);
720                 }
721         layout_util_sync_color(lw); /* update color button */
722 }
723
724 void layout_status_update_all(LayoutWindow *lw)
725 {
726         layout_status_update_progress(lw, 0.0, NULL);
727         layout_status_update_info(lw, NULL);
728         layout_status_update_image(lw);
729         layout_util_status_update_write(lw);
730 }
731
732 static GtkWidget *layout_status_label(gchar *text, GtkWidget *box, gboolean start, gint size, gboolean expand)
733 {
734         GtkWidget *label;
735         GtkWidget *frame;
736
737         frame = gtk_frame_new(NULL);
738         if (size) gtk_widget_set_size_request(frame, size, -1);
739         gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
740         if (start)
741                 {
742                 gtk_box_pack_start(GTK_BOX(box), frame, expand, expand, 0);
743                 }
744         else
745                 {
746                 gtk_box_pack_end(GTK_BOX(box), frame, expand, expand, 0);
747                 }
748         gtk_widget_show(frame);
749
750         label = gtk_label_new(text ? text : "");
751         gtk_container_add(GTK_CONTAINER(frame), label);
752         gtk_widget_show(label);
753
754         return label;
755 }
756
757 static void layout_status_setup(LayoutWindow *lw, GtkWidget *box, gboolean small_format)
758 {
759         GtkWidget *hbox;
760         GtkWidget *toolbar;
761         GtkWidget *toolbar_frame;
762
763         if (lw->info_box) return;
764
765         if (small_format)
766                 {
767                 lw->info_box = gtk_vbox_new(FALSE, 0);
768                 }
769         else
770                 {
771                 lw->info_box = gtk_hbox_new(FALSE, 0);
772                 }
773         gtk_box_pack_end(GTK_BOX(box), lw->info_box, FALSE, FALSE, 0);
774         gtk_widget_show(lw->info_box);
775
776         if (small_format)
777                 {
778                 hbox = gtk_hbox_new(FALSE, 0);
779                 gtk_box_pack_start(GTK_BOX(lw->info_box), hbox, FALSE, FALSE, 0);
780                 gtk_widget_show(hbox);
781                 }
782         else
783                 {
784                 hbox = lw->info_box;
785                 }
786         lw->info_progress_bar = gtk_progress_bar_new();
787         gtk_widget_set_size_request(lw->info_progress_bar, PROGRESS_WIDTH, -1);
788 #if GTK_CHECK_VERSION(3,0,0)
789         gtk_progress_bar_set_text(GTK_PROGRESS_BAR(lw->info_progress_bar), "");
790         gtk_progress_bar_set_show_text(GTK_PROGRESS_BAR(lw->info_progress_bar), TRUE);
791 #endif
792         gtk_box_pack_start(GTK_BOX(hbox), lw->info_progress_bar, FALSE, FALSE, 0);
793         gtk_widget_show(lw->info_progress_bar);
794
795         lw->info_sort = layout_sort_button(lw);
796         gtk_widget_set_tooltip_text(GTK_WIDGET(lw->info_sort), _("Select sort order"));
797         gtk_box_pack_start(GTK_BOX(hbox), lw->info_sort, FALSE, FALSE, 0);
798         gtk_widget_show(lw->info_sort);
799
800         lw->info_status = layout_status_label(NULL, lw->info_box, TRUE, 0, (!small_format));
801         gtk_widget_set_tooltip_text(GTK_WIDGET(lw->info_status), _("Folder contents (files selected)"));
802
803         if (small_format)
804                 {
805                 hbox = gtk_hbox_new(FALSE, 0);
806                 gtk_box_pack_start(GTK_BOX(lw->info_box), hbox, FALSE, FALSE, 0);
807                 gtk_widget_show(hbox);
808                 }
809         lw->info_details = layout_status_label(NULL, hbox, TRUE, 0, TRUE);
810         gtk_widget_set_tooltip_text(GTK_WIDGET(lw->info_details), _("(Image dimensions) Image size"));
811         toolbar = layout_actions_toolbar(lw, TOOLBAR_STATUS);
812
813         toolbar_frame = gtk_frame_new(NULL);
814         gtk_frame_set_shadow_type(GTK_FRAME(toolbar_frame), GTK_SHADOW_IN);
815         gtk_container_add(GTK_CONTAINER(toolbar_frame), toolbar);
816         gtk_widget_show(toolbar_frame);
817         gtk_widget_show(toolbar);
818         gtk_box_pack_end(GTK_BOX(hbox), toolbar_frame, FALSE, FALSE, 0);
819         lw->info_zoom = layout_zoom_button(lw, hbox, ZOOM_LABEL_WIDTH, TRUE);
820         gtk_widget_set_tooltip_text(GTK_WIDGET(lw->info_zoom), _("Select zoom and scroll mode"));
821         gtk_widget_show(lw->info_zoom);
822
823         if (small_format)
824                 {
825                 hbox = gtk_hbox_new(FALSE, 0);
826                 gtk_box_pack_start(GTK_BOX(lw->info_box), hbox, FALSE, FALSE, 0);
827                 gtk_widget_show(hbox);
828                 }
829         lw->info_pixel = layout_status_label(NULL, hbox, FALSE, 0, small_format); /* expand only in small format */
830         gtk_widget_set_tooltip_text(GTK_WIDGET(lw->info_pixel), _("[Pixel x,y coord]: (Pixel R,G,B value)"));
831         if (!lw->options.show_info_pixel) gtk_widget_hide(gtk_widget_get_parent(lw->info_pixel));
832 }
833
834 /*
835  *-----------------------------------------------------------------------------
836  * views
837  *-----------------------------------------------------------------------------
838  */
839
840 static GtkWidget *layout_tools_new(LayoutWindow *lw)
841 {
842         lw->dir_view = layout_tool_setup(lw);
843         return lw->dir_view;
844 }
845
846 static void layout_list_status_cb(ViewFile *vf, gpointer data)
847 {
848         LayoutWindow *lw = data;
849
850         layout_status_update_info(lw, NULL);
851 }
852
853 static void layout_list_thumb_cb(ViewFile *vf, gdouble val, const gchar *text, gpointer data)
854 {
855         LayoutWindow *lw = data;
856
857         layout_status_update_progress(lw, val, text);
858 }
859
860 static void layout_list_sync_thumb(LayoutWindow *lw)
861 {
862         if (lw->vf) vf_thumb_set(lw->vf, lw->options.show_thumbnails);
863 }
864
865 static void layout_list_sync_file_filter(LayoutWindow *lw)
866 {
867         if (lw->vf) vf_file_filter_set(lw->vf, lw->options.show_file_filter);
868 }
869
870 static GtkWidget *layout_list_new(LayoutWindow *lw)
871 {
872         lw->vf = vf_new(lw->options.file_view_type, NULL);
873         vf_set_layout(lw->vf, lw);
874
875         vf_set_status_func(lw->vf, layout_list_status_cb, lw);
876         vf_set_thumb_status_func(lw->vf, layout_list_thumb_cb, lw);
877
878         vf_marks_set(lw->vf, lw->options.show_marks);
879
880         layout_list_sync_thumb(lw);
881         layout_list_sync_file_filter(lw);
882
883         return lw->vf->widget;
884 }
885
886 static void layout_list_sync_marks(LayoutWindow *lw)
887 {
888         if (lw->vf) vf_marks_set(lw->vf, lw->options.show_marks);
889 }
890
891 static void layout_list_scroll_to_subpart(LayoutWindow *lw, const gchar *needle)
892 {
893         if (!lw) return;
894 }
895
896 GList *layout_list(LayoutWindow *lw)
897 {
898         if (!layout_valid(&lw)) return NULL;
899
900         if (lw->vf) return vf_get_list(lw->vf);
901
902         return NULL;
903 }
904
905 guint layout_list_count(LayoutWindow *lw, gint64 *bytes)
906 {
907         if (!layout_valid(&lw)) return 0;
908
909         if (lw->vf) return vf_count(lw->vf, bytes);
910
911         return 0;
912 }
913
914 FileData *layout_list_get_fd(LayoutWindow *lw, gint index)
915 {
916         if (!layout_valid(&lw)) return NULL;
917
918         if (lw->vf) return vf_index_get_data(lw->vf, index);
919
920         return NULL;
921 }
922
923 gint layout_list_get_index(LayoutWindow *lw, FileData *fd)
924 {
925         if (!layout_valid(&lw) || !fd) return -1;
926
927         if (lw->vf) return vf_index_by_fd(lw->vf, fd);
928
929         return -1;
930 }
931
932 void layout_list_sync_fd(LayoutWindow *lw, FileData *fd)
933 {
934         if (!layout_valid(&lw)) return;
935
936         if (lw->vf) vf_select_by_fd(lw->vf, fd);
937 }
938
939 static void layout_list_sync_sort(LayoutWindow *lw)
940 {
941         if (!layout_valid(&lw)) return;
942
943         if (lw->vf) vf_sort_set(lw->vf, lw->sort_method, lw->sort_ascend);
944 }
945
946 GList *layout_selection_list(LayoutWindow *lw)
947 {
948         if (!layout_valid(&lw)) return NULL;
949
950         if (layout_image_get_collection(lw, NULL))
951                 {
952                 FileData *fd;
953
954                 fd = layout_image_get_fd(lw);
955                 if (fd) return g_list_append(NULL, file_data_ref(fd));
956                 return NULL;
957                 }
958
959         if (lw->vf) return vf_selection_get_list(lw->vf);
960
961         return NULL;
962 }
963
964 GList *layout_selection_list_by_index(LayoutWindow *lw)
965 {
966         if (!layout_valid(&lw)) return NULL;
967
968         if (lw->vf) return vf_selection_get_list_by_index(lw->vf);
969
970         return NULL;
971 }
972
973 guint layout_selection_count(LayoutWindow *lw, gint64 *bytes)
974 {
975         if (!layout_valid(&lw)) return 0;
976
977         if (lw->vf) return vf_selection_count(lw->vf, bytes);
978
979         return 0;
980 }
981
982 void layout_select_all(LayoutWindow *lw)
983 {
984         if (!layout_valid(&lw)) return;
985
986         if (lw->vf) vf_select_all(lw->vf);
987 }
988
989 void layout_select_none(LayoutWindow *lw)
990 {
991         if (!layout_valid(&lw)) return;
992
993         if (lw->vf) vf_select_none(lw->vf);
994 }
995
996 void layout_select_invert(LayoutWindow *lw)
997 {
998         if (!layout_valid(&lw)) return;
999
1000         if (lw->vf) vf_select_invert(lw->vf);
1001 }
1002
1003 void layout_mark_to_selection(LayoutWindow *lw, gint mark, MarkToSelectionMode mode)
1004 {
1005         if (!layout_valid(&lw)) return;
1006
1007         if (lw->vf) vf_mark_to_selection(lw->vf, mark, mode);
1008 }
1009
1010 void layout_selection_to_mark(LayoutWindow *lw, gint mark, SelectionToMarkMode mode)
1011 {
1012         if (!layout_valid(&lw)) return;
1013
1014         if (lw->vf) vf_selection_to_mark(lw->vf, mark, mode);
1015
1016         layout_status_update_info(lw, NULL); /* osd in fullscreen mode */
1017 }
1018
1019 void layout_mark_filter_toggle(LayoutWindow *lw, gint mark)
1020 {
1021         if (!layout_valid(&lw)) return;
1022
1023         if (lw->vf) vf_mark_filter_toggle(lw->vf, mark);
1024 }
1025
1026
1027 /*
1028  *-----------------------------------------------------------------------------
1029  * access
1030  *-----------------------------------------------------------------------------
1031  */
1032
1033 const gchar *layout_get_path(LayoutWindow *lw)
1034 {
1035         if (!layout_valid(&lw)) return NULL;
1036         return lw->dir_fd ? lw->dir_fd->path : NULL;
1037 }
1038
1039 static void layout_sync_path(LayoutWindow *lw)
1040 {
1041         if (!lw->dir_fd) return;
1042
1043         if (lw->path_entry) gtk_entry_set_text(GTK_ENTRY(lw->path_entry), lw->dir_fd->path);
1044
1045         if (lw->vd) vd_set_fd(lw->vd, lw->dir_fd);
1046         if (lw->vf) vf_set_fd(lw->vf, lw->dir_fd);
1047 }
1048
1049 gboolean layout_set_path(LayoutWindow *lw, const gchar *path)
1050 {
1051         FileData *fd;
1052         gboolean ret;
1053
1054         if (!path) return FALSE;
1055
1056         fd = file_data_new_group(path);
1057         ret = layout_set_fd(lw, fd);
1058         file_data_unref(fd);
1059         return ret;
1060 }
1061
1062
1063 gboolean layout_set_fd(LayoutWindow *lw, FileData *fd)
1064 {
1065         gboolean have_file = FALSE;
1066         gboolean dir_changed = TRUE;
1067
1068         if (!layout_valid(&lw)) return FALSE;
1069
1070         if (!fd || !isname(fd->path)) return FALSE;
1071         if (lw->dir_fd && fd == lw->dir_fd)
1072                 {
1073                 return TRUE;
1074                 }
1075
1076         if (isdir(fd->path))
1077                 {
1078                 if (lw->dir_fd)
1079                         {
1080                         file_data_unregister_real_time_monitor(lw->dir_fd);
1081                         file_data_unref(lw->dir_fd);
1082                         }
1083                 lw->dir_fd = file_data_ref(fd);
1084                 file_data_register_real_time_monitor(fd);
1085                 }
1086         else
1087                 {
1088                 gchar *base;
1089
1090                 base = remove_level_from_path(fd->path);
1091                 if (lw->dir_fd && strcmp(lw->dir_fd->path, base) == 0)
1092                         {
1093                         g_free(base);
1094                         dir_changed = FALSE;
1095                         }
1096                 else if (isdir(base))
1097                         {
1098                         if (lw->dir_fd)
1099                                 {
1100                                 file_data_unregister_real_time_monitor(lw->dir_fd);
1101                                 file_data_unref(lw->dir_fd);
1102                                 }
1103                         lw->dir_fd = file_data_new_dir(base);
1104                         file_data_register_real_time_monitor(lw->dir_fd);
1105                         g_free(base);
1106                         }
1107                 else
1108                         {
1109                         g_free(base);
1110                         return FALSE;
1111                         }
1112                 if (isfile(fd->path)) have_file = TRUE;
1113                 }
1114
1115         if (lw->path_entry)
1116                 {
1117                 history_chain_append_end(lw->dir_fd->path);
1118                 tab_completion_append_to_history(lw->path_entry, lw->dir_fd->path);
1119                 }
1120         layout_sync_path(lw);
1121         layout_list_sync_sort(lw);
1122
1123         if (have_file)
1124                 {
1125                 gint row;
1126
1127                 row = layout_list_get_index(lw, fd);
1128                 if (row >= 0)
1129                         {
1130                         layout_image_set_index(lw, row);
1131                         }
1132                 else
1133                         {
1134                         layout_image_set_fd(lw, fd);
1135                         }
1136                 }
1137         else if (!options->lazy_image_sync)
1138                 {
1139                 layout_image_set_index(lw, 0);
1140                 }
1141
1142         if (options->metadata.confirm_on_dir_change && dir_changed)
1143                 metadata_write_queue_confirm(FALSE, NULL, NULL);
1144
1145         if (lw->vf && (options->read_metadata_in_idle || (lw->sort_method == SORT_EXIFTIME || lw->sort_method == SORT_EXIFTIMEDIGITIZED || lw->sort_method == SORT_RATING)))
1146                 {
1147                 vf_read_metadata_in_idle(lw->vf);
1148                 }
1149
1150         return TRUE;
1151 }
1152
1153 static void layout_refresh_lists(LayoutWindow *lw)
1154 {
1155         if (lw->vd) vd_refresh(lw->vd);
1156
1157         if (lw->vf)
1158                 {
1159                 vf_refresh(lw->vf);
1160                 vf_thumb_update(lw->vf);
1161                 }
1162 }
1163
1164 void layout_refresh(LayoutWindow *lw)
1165 {
1166         if (!layout_valid(&lw)) return;
1167
1168         DEBUG_1("layout refresh");
1169
1170         layout_refresh_lists(lw);
1171
1172         if (lw->image) layout_image_refresh(lw);
1173 }
1174
1175 void layout_thumb_set(LayoutWindow *lw, gboolean enable)
1176 {
1177         if (!layout_valid(&lw)) return;
1178
1179         if (lw->options.show_thumbnails == enable) return;
1180
1181         lw->options.show_thumbnails = enable;
1182
1183         layout_util_sync_thumb(lw);
1184         layout_list_sync_thumb(lw);
1185 }
1186
1187 void layout_file_filter_set(LayoutWindow *lw, gboolean enable)
1188 {
1189         if (!layout_valid(&lw)) return;
1190
1191         if (lw->options.show_file_filter == enable) return;
1192
1193         lw->options.show_file_filter = enable;
1194
1195         layout_util_sync_file_filter(lw);
1196         layout_list_sync_file_filter(lw);
1197 }
1198
1199 void layout_marks_set(LayoutWindow *lw, gboolean enable)
1200 {
1201         if (!layout_valid(&lw)) return;
1202
1203         if (lw->options.show_marks == enable) return;
1204
1205         lw->options.show_marks = enable;
1206
1207         layout_util_sync_marks(lw);
1208         layout_list_sync_marks(lw);
1209 }
1210
1211 gboolean layout_thumb_get(LayoutWindow *lw)
1212 {
1213         if (!layout_valid(&lw)) return FALSE;
1214
1215         return lw->options.show_thumbnails;
1216 }
1217
1218 gboolean layout_marks_get(LayoutWindow *lw)
1219 {
1220         if (!layout_valid(&lw)) return FALSE;
1221
1222         return lw->options.show_marks;
1223 }
1224
1225 void layout_sort_set(LayoutWindow *lw, SortType type, gboolean ascend)
1226 {
1227         if (!layout_valid(&lw)) return;
1228         if (lw->sort_method == type && lw->sort_ascend == ascend) return;
1229
1230         lw->sort_method = type;
1231         lw->sort_ascend = ascend;
1232
1233         if (lw->info_sort) gtk_label_set_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(lw->info_sort))),
1234                                               sort_type_get_text(type));
1235         layout_list_sync_sort(lw);
1236 }
1237
1238 gboolean layout_sort_get(LayoutWindow *lw, SortType *type, gboolean *ascend)
1239 {
1240         if (!layout_valid(&lw)) return FALSE;
1241
1242         if (type) *type = lw->sort_method;
1243         if (ascend) *ascend = lw->sort_ascend;
1244
1245         return TRUE;
1246 }
1247
1248 gboolean layout_geometry_get(LayoutWindow *lw, gint *x, gint *y, gint *w, gint *h)
1249 {
1250         GdkWindow *window;
1251         if (!layout_valid(&lw)) return FALSE;
1252
1253         window = gtk_widget_get_window(lw->window);
1254         gdk_window_get_root_origin(window, x, y);
1255         *w = gdk_window_get_width(window);
1256         *h = gdk_window_get_height(window);
1257
1258         return TRUE;
1259 }
1260
1261 gboolean layout_geometry_get_dividers(LayoutWindow *lw, gint *h, gint *v)
1262 {
1263         GtkAllocation h_allocation;
1264         GtkAllocation v_allocation;
1265
1266         if (!layout_valid(&lw)) return FALSE;
1267
1268         if (lw->h_pane)
1269                 {
1270                 GtkWidget *child = gtk_paned_get_child1(GTK_PANED(lw->h_pane));
1271                 gtk_widget_get_allocation(child, &h_allocation);
1272                 }
1273
1274         if (lw->v_pane)
1275                 {
1276                 GtkWidget *child = gtk_paned_get_child1(GTK_PANED(lw->v_pane));
1277                 gtk_widget_get_allocation(child, &v_allocation);
1278                 }
1279
1280         if (lw->h_pane && h_allocation.x >= 0)
1281                 {
1282                 *h = h_allocation.width;
1283                 }
1284         else if (h != &lw->options.main_window.hdivider_pos)
1285                 {
1286                 *h = lw->options.main_window.hdivider_pos;
1287                 }
1288
1289         if (lw->v_pane && v_allocation.x >= 0)
1290                 {
1291                 *v = v_allocation.height;
1292                 }
1293         else if (v != &lw->options.main_window.vdivider_pos)
1294                 {
1295                 *v = lw->options.main_window.vdivider_pos;
1296                 }
1297
1298         return TRUE;
1299 }
1300
1301 void layout_views_set(LayoutWindow *lw, DirViewType dir_view_type, FileViewType file_view_type)
1302 {
1303         if (!layout_valid(&lw)) return;
1304
1305         if (lw->options.dir_view_type == dir_view_type && lw->options.file_view_type == file_view_type) return;
1306
1307         lw->options.dir_view_type = dir_view_type;
1308         lw->options.file_view_type = file_view_type;
1309
1310         layout_style_set(lw, -1, NULL);
1311 }
1312
1313 gboolean layout_views_get(LayoutWindow *lw, DirViewType *dir_view_type, FileViewType *file_view_type)
1314 {
1315         if (!layout_valid(&lw)) return FALSE;
1316
1317         *dir_view_type = lw->options.dir_view_type;
1318         *file_view_type = lw->options.file_view_type;
1319
1320         return TRUE;
1321 }
1322
1323 /*
1324  *-----------------------------------------------------------------------------
1325  * location utils
1326  *-----------------------------------------------------------------------------
1327  */
1328
1329 static gboolean layout_location_single(LayoutLocation l)
1330 {
1331         return (l == LAYOUT_LEFT ||
1332                 l == LAYOUT_RIGHT ||
1333                 l == LAYOUT_TOP ||
1334                 l == LAYOUT_BOTTOM);
1335 }
1336
1337 static gboolean layout_location_vertical(LayoutLocation l)
1338 {
1339         return (l & LAYOUT_TOP ||
1340                 l & LAYOUT_BOTTOM);
1341 }
1342
1343 static gboolean layout_location_first(LayoutLocation l)
1344 {
1345         return (l & LAYOUT_TOP ||
1346                 l & LAYOUT_LEFT);
1347 }
1348
1349 static LayoutLocation layout_grid_compass(LayoutWindow *lw)
1350 {
1351         if (layout_location_single(lw->dir_location)) return lw->dir_location;
1352         if (layout_location_single(lw->file_location)) return lw->file_location;
1353         return lw->image_location;
1354 }
1355
1356 static void layout_location_compute(LayoutLocation l1, LayoutLocation l2,
1357                                     GtkWidget *s1, GtkWidget *s2,
1358                                     GtkWidget **d1, GtkWidget **d2)
1359 {
1360         LayoutLocation l;
1361
1362         l = l1 & l2;    /* get common compass direction */
1363         l = l1 - l;     /* remove it */
1364
1365         if (layout_location_first(l))
1366                 {
1367                 *d1 = s1;
1368                 *d2 = s2;
1369                 }
1370         else
1371                 {
1372                 *d1 = s2;
1373                 *d2 = s1;
1374                 }
1375 }
1376
1377 /*
1378  *-----------------------------------------------------------------------------
1379  * tools window (for floating/hidden)
1380  *-----------------------------------------------------------------------------
1381  */
1382
1383 gboolean layout_geometry_get_tools(LayoutWindow *lw, gint *x, gint *y, gint *w, gint *h, gint *divider_pos)
1384 {
1385         GdkWindow *window;
1386         GtkAllocation allocation;
1387         if (!layout_valid(&lw)) return FALSE;
1388
1389         if (!lw->tools || !gtk_widget_get_visible(lw->tools))
1390                 {
1391                 /* use the stored values (sort of breaks success return value) */
1392
1393                 *divider_pos = lw->options.float_window.vdivider_pos;
1394
1395                 return FALSE;
1396                 }
1397
1398         window = gtk_widget_get_window(lw->tools);
1399         gdk_window_get_root_origin(window, x, y);
1400         *w = gdk_window_get_width(window);
1401         *h = gdk_window_get_height(window);
1402         gtk_widget_get_allocation(gtk_paned_get_child1(GTK_PANED(lw->tools_pane)), &allocation);
1403
1404         if (gtk_orientable_get_orientation(GTK_ORIENTABLE(lw->tools_pane)) == GTK_ORIENTATION_VERTICAL)
1405                 {
1406                 *divider_pos = allocation.height;
1407                 }
1408         else
1409                 {
1410                 *divider_pos = allocation.width;
1411                 }
1412
1413         return TRUE;
1414 }
1415
1416 gboolean layout_geometry_get_log_window(LayoutWindow *lw, gint *x, gint *y,
1417                                                                                                                 gint *w, gint *h)
1418 {
1419         GdkWindow *window;
1420
1421         if (!layout_valid(&lw)) return FALSE;
1422
1423         if (!lw->log_window)
1424                 {
1425                 return FALSE;
1426                 }
1427
1428         window = gtk_widget_get_window(lw->log_window);
1429         gdk_window_get_root_origin(window, x, y);
1430         *w = gdk_window_get_width(window);
1431         *h = gdk_window_get_height(window);
1432
1433         return TRUE;
1434 }
1435
1436 static void layout_tools_geometry_sync(LayoutWindow *lw)
1437 {
1438         layout_geometry_get_tools(lw, &lw->options.float_window.x, &lw->options.float_window.y,
1439                                   &lw->options.float_window.w, &lw->options.float_window.h, &lw->options.float_window.vdivider_pos);
1440 }
1441
1442 static void layout_tools_hide(LayoutWindow *lw, gboolean hide)
1443 {
1444         if (!lw->tools) return;
1445
1446         if (hide)
1447                 {
1448                 if (gtk_widget_get_visible(lw->tools))
1449                         {
1450                         layout_tools_geometry_sync(lw);
1451                         gtk_widget_hide(lw->tools);
1452                         }
1453                 }
1454         else
1455                 {
1456                 if (!gtk_widget_get_visible(lw->tools))
1457                         {
1458                         gtk_widget_show(lw->tools);
1459                         if (lw->vf) vf_refresh(lw->vf);
1460                         }
1461                 }
1462
1463         lw->options.tools_hidden = hide;
1464 }
1465
1466 static gboolean layout_tools_delete_cb(GtkWidget *widget, GdkEventAny *event, gpointer data)
1467 {
1468         LayoutWindow *lw = data;
1469
1470         layout_tools_float_toggle(lw);
1471
1472         return TRUE;
1473 }
1474
1475 static void layout_tools_setup(LayoutWindow *lw, GtkWidget *tools, GtkWidget *files)
1476 {
1477         GtkWidget *vbox;
1478         GtkWidget *w1, *w2;
1479         gboolean vertical;
1480         gboolean new_window = FALSE;
1481
1482         vertical = (layout_location_single(lw->image_location) && !layout_location_vertical(lw->image_location)) ||
1483                    (!layout_location_single(lw->image_location) && layout_location_vertical(layout_grid_compass(lw)));
1484         /* for now, tools/dir are always first in order */
1485         w1 = tools;
1486         w2 = files;
1487
1488         if (!lw->tools)
1489                 {
1490                 GdkGeometry geometry;
1491                 GdkWindowHints hints;
1492
1493                 lw->tools = window_new(GTK_WINDOW_TOPLEVEL, "tools", PIXBUF_INLINE_ICON_TOOLS, NULL, _("Tools"));
1494                 g_signal_connect(G_OBJECT(lw->tools), "delete_event",
1495                                  G_CALLBACK(layout_tools_delete_cb), lw);
1496                 layout_keyboard_init(lw, lw->tools);
1497
1498                 if (options->save_window_positions)
1499                         {
1500                         hints = GDK_HINT_USER_POS;
1501                         }
1502                 else
1503                         {
1504                         hints = 0;
1505                         }
1506
1507                 geometry.min_width = DEFAULT_MINIMAL_WINDOW_SIZE;
1508                 geometry.min_height = DEFAULT_MINIMAL_WINDOW_SIZE;
1509                 geometry.base_width = TOOLWINDOW_DEF_WIDTH;
1510                 geometry.base_height = TOOLWINDOW_DEF_HEIGHT;
1511                 gtk_window_set_geometry_hints(GTK_WINDOW(lw->tools), NULL, &geometry,
1512                                               GDK_HINT_MIN_SIZE | GDK_HINT_BASE_SIZE | hints);
1513
1514
1515                 gtk_window_set_resizable(GTK_WINDOW(lw->tools), TRUE);
1516                 gtk_container_set_border_width(GTK_CONTAINER(lw->tools), 0);
1517                 gtk_container_remove(GTK_CONTAINER(lw->main_box), lw->menu_tool_bar);
1518
1519                 new_window = TRUE;
1520                 }
1521         else
1522                 {
1523                 layout_tools_geometry_sync(lw);
1524                 /* dump the contents */
1525                 gtk_widget_destroy(gtk_bin_get_child(GTK_BIN(lw->tools)));
1526                 }
1527
1528         layout_actions_add_window(lw, lw->tools);
1529
1530         vbox = gtk_vbox_new(FALSE, 0);
1531         gtk_container_add(GTK_CONTAINER(lw->tools), vbox);
1532         gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(lw->menu_tool_bar), FALSE, FALSE, 0);
1533         gtk_widget_show(vbox);
1534
1535         layout_status_setup(lw, vbox, TRUE);
1536
1537         if (vertical)
1538                 {
1539                 lw->tools_pane = gtk_vpaned_new();
1540                 }
1541         else
1542                 {
1543                 lw->tools_pane = gtk_hpaned_new();
1544                 }
1545         gtk_box_pack_start(GTK_BOX(vbox), lw->tools_pane, TRUE, TRUE, 0);
1546         gtk_widget_show(lw->tools_pane);
1547
1548         gtk_paned_pack1(GTK_PANED(lw->tools_pane), w1, FALSE, TRUE);
1549         gtk_paned_pack2(GTK_PANED(lw->tools_pane), w2, TRUE, TRUE);
1550
1551         gtk_widget_show(tools);
1552         gtk_widget_show(files);
1553
1554         if (new_window)
1555                 {
1556                 if (options->save_window_positions)
1557                         {
1558                         gtk_window_set_default_size(GTK_WINDOW(lw->tools), lw->options.float_window.w, lw->options.float_window.h);
1559                         gtk_window_move(GTK_WINDOW(lw->tools), lw->options.float_window.x, lw->options.float_window.y);
1560                         }
1561                 else
1562                         {
1563                         if (vertical)
1564                                 {
1565                                 gtk_window_set_default_size(GTK_WINDOW(lw->tools),
1566                                                             TOOLWINDOW_DEF_WIDTH, TOOLWINDOW_DEF_HEIGHT);
1567                                 }
1568                         else
1569                                 {
1570                                 gtk_window_set_default_size(GTK_WINDOW(lw->tools),
1571                                                             TOOLWINDOW_DEF_HEIGHT, TOOLWINDOW_DEF_WIDTH);
1572                                 }
1573                         }
1574                 }
1575
1576         if (!options->save_window_positions)
1577                 {
1578                 if (vertical)
1579                         {
1580                         lw->options.float_window.vdivider_pos = MAIN_WINDOW_DIV_VPOS;
1581                         }
1582                 else
1583                         {
1584                         lw->options.float_window.vdivider_pos = MAIN_WINDOW_DIV_HPOS;
1585                         }
1586                 }
1587
1588         gtk_paned_set_position(GTK_PANED(lw->tools_pane), lw->options.float_window.vdivider_pos);
1589 }
1590
1591 /*
1592  *-----------------------------------------------------------------------------
1593  * glue (layout arrangement)
1594  *-----------------------------------------------------------------------------
1595  */
1596
1597 static void layout_grid_compute(LayoutWindow *lw,
1598                                 GtkWidget *image, GtkWidget *tools, GtkWidget *files,
1599                                 GtkWidget **w1, GtkWidget **w2, GtkWidget **w3)
1600 {
1601         /* heh, this was fun */
1602
1603         if (layout_location_single(lw->dir_location))
1604                 {
1605                 if (layout_location_first(lw->dir_location))
1606                         {
1607                         *w1 = tools;
1608                         layout_location_compute(lw->file_location, lw->image_location, files, image, w2, w3);
1609                         }
1610                 else
1611                         {
1612                         *w3 = tools;
1613                         layout_location_compute(lw->file_location, lw->image_location, files, image, w1, w2);
1614                         }
1615                 }
1616         else if (layout_location_single(lw->file_location))
1617                 {
1618                 if (layout_location_first(lw->file_location))
1619                         {
1620                         *w1 = files;
1621                         layout_location_compute(lw->dir_location, lw->image_location, tools, image, w2, w3);
1622                         }
1623                 else
1624                         {
1625                         *w3 = files;
1626                         layout_location_compute(lw->dir_location, lw->image_location, tools, image, w1, w2);
1627                         }
1628                 }
1629         else
1630                 {
1631                 /* image */
1632                 if (layout_location_first(lw->image_location))
1633                         {
1634                         *w1 = image;
1635                         layout_location_compute(lw->file_location, lw->dir_location, files, tools, w2, w3);
1636                         }
1637                 else
1638                         {
1639                         *w3 = image;
1640                         layout_location_compute(lw->file_location, lw->dir_location, files, tools, w1, w2);
1641                         }
1642                 }
1643 }
1644
1645 void layout_split_change(LayoutWindow *lw, ImageSplitMode mode)
1646 {
1647         GtkWidget *image;
1648         gint i;
1649
1650         for (i = 0; i < MAX_SPLIT_IMAGES; i++)
1651                 {
1652                 if (lw->split_images[i])
1653                         {
1654                         gtk_widget_hide(lw->split_images[i]->widget);
1655                         if (gtk_widget_get_parent(lw->split_images[i]->widget) != lw->utility_paned)
1656                                 gtk_container_remove(GTK_CONTAINER(gtk_widget_get_parent(lw->split_images[i]->widget)), lw->split_images[i]->widget);
1657                         }
1658                 }
1659         gtk_container_remove(GTK_CONTAINER(lw->utility_paned), lw->split_image_widget);
1660
1661         image = layout_image_setup_split(lw, mode);
1662
1663         gtk_paned_pack1(GTK_PANED(lw->utility_paned), image, TRUE, FALSE);
1664         gtk_widget_show(image);
1665         layout_util_sync(lw);
1666 }
1667
1668 static void layout_grid_setup(LayoutWindow *lw)
1669 {
1670         gint priority_location;
1671         GtkWidget *h;
1672         GtkWidget *v;
1673         GtkWidget *w1, *w2, *w3;
1674
1675         GtkWidget *image_sb; /* image together with sidebars in utility box */
1676         GtkWidget *tools;
1677         GtkWidget *files;
1678
1679         layout_actions_setup(lw);
1680
1681         lw->group_box = gtk_vbox_new(FALSE, 0);
1682         gtk_box_pack_end(GTK_BOX(lw->main_box), lw->group_box, TRUE, TRUE, 0);
1683         gtk_widget_show(lw->group_box);
1684
1685         priority_location = layout_grid_compass(lw);
1686
1687         if (lw->utility_box)
1688                 {
1689                 layout_split_change(lw, lw->split_mode); /* this re-creates image frame for the new configuration */
1690                 image_sb = lw->utility_box;
1691                 }
1692         else
1693                 {
1694                 GtkWidget *image; /* image or split images together */
1695                 image = layout_image_setup_split(lw, lw->split_mode);
1696                 image_sb = layout_bars_prepare(lw, image);
1697                 }
1698
1699         tools = layout_tools_new(lw);
1700         files = layout_list_new(lw);
1701
1702
1703         if (lw->options.tools_float || lw->options.tools_hidden)
1704                 {
1705                 gtk_box_pack_start(GTK_BOX(lw->group_box), image_sb, TRUE, TRUE, 0);
1706                 gtk_widget_show(image_sb);
1707
1708                 layout_tools_setup(lw, tools, files);
1709
1710                 image_grab_focus(lw->image);
1711
1712                 return;
1713                 }
1714         else if (lw->tools)
1715                 {
1716                 layout_tools_geometry_sync(lw);
1717                 gtk_widget_destroy(lw->tools);
1718                 lw->tools = NULL;
1719                 lw->tools_pane = NULL;
1720                 }
1721
1722         layout_status_setup(lw, lw->group_box, FALSE);
1723
1724         layout_grid_compute(lw, image_sb, tools, files, &w1, &w2, &w3);
1725
1726         v = lw->v_pane = gtk_vpaned_new();
1727
1728         h = lw->h_pane = gtk_hpaned_new();
1729
1730         if (!layout_location_vertical(priority_location))
1731                 {
1732                 GtkWidget *tmp;
1733
1734                 tmp = v;
1735                 v = h;
1736                 h = tmp;
1737                 }
1738
1739         gtk_box_pack_start(GTK_BOX(lw->group_box), v, TRUE, TRUE, 0);
1740
1741         if (!layout_location_first(priority_location))
1742                 {
1743                 gtk_paned_pack1(GTK_PANED(v), h, FALSE, TRUE);
1744                 gtk_paned_pack2(GTK_PANED(v), w3, TRUE, TRUE);
1745
1746                 gtk_paned_pack1(GTK_PANED(h), w1, FALSE, TRUE);
1747                 gtk_paned_pack2(GTK_PANED(h), w2, TRUE, TRUE);
1748                 }
1749         else
1750                 {
1751                 gtk_paned_pack1(GTK_PANED(v), w1, FALSE, TRUE);
1752                 gtk_paned_pack2(GTK_PANED(v), h, TRUE, TRUE);
1753
1754                 gtk_paned_pack1(GTK_PANED(h), w2, FALSE, TRUE);
1755                 gtk_paned_pack2(GTK_PANED(h), w3, TRUE, TRUE);
1756                 }
1757
1758         gtk_widget_show(image_sb);
1759         gtk_widget_show(tools);
1760         gtk_widget_show(files);
1761
1762         gtk_widget_show(v);
1763         gtk_widget_show(h);
1764
1765         /* fix to have image pane visible when it is left and priority widget */
1766         if (lw->options.main_window.hdivider_pos == -1 &&
1767             w1 == image_sb &&
1768             !layout_location_vertical(priority_location) &&
1769             layout_location_first(priority_location))
1770                 {
1771                 gtk_widget_set_size_request(image_sb, 200, -1);
1772                 }
1773
1774         gtk_paned_set_position(GTK_PANED(lw->h_pane), lw->options.main_window.hdivider_pos);
1775         gtk_paned_set_position(GTK_PANED(lw->v_pane), lw->options.main_window.vdivider_pos);
1776
1777         image_grab_focus(lw->image);
1778 }
1779
1780 void layout_style_set(LayoutWindow *lw, gint style, const gchar *order)
1781 {
1782         FileData *dir_fd;
1783         gint i;
1784
1785         if (!layout_valid(&lw)) return;
1786
1787         if (style != -1)
1788                 {
1789                 LayoutLocation d, f, i;
1790
1791                 layout_config_parse(style, order, &d,  &f, &i);
1792
1793                 if (lw->dir_location == d &&
1794                     lw->file_location == f &&
1795                     lw->image_location == i) return;
1796
1797                 lw->dir_location = d;
1798                 lw->file_location = f;
1799                 lw->image_location = i;
1800                 }
1801
1802         /* remember state */
1803
1804         /* layout_image_slideshow_stop(lw); slideshow should survive */
1805         layout_image_full_screen_stop(lw);
1806
1807         dir_fd = lw->dir_fd;
1808         if (dir_fd) file_data_unregister_real_time_monitor(dir_fd);
1809         lw->dir_fd = NULL;
1810
1811         layout_geometry_get_dividers(lw, &lw->options.main_window.hdivider_pos, &lw->options.main_window.vdivider_pos);
1812
1813         /* preserve utility_box (image + sidebars), menu_bar and toolbars to be reused later in layout_grid_setup */
1814         /* lw->image is preserved together with lw->utility_box */
1815         if (lw->utility_box) gtk_container_remove(GTK_CONTAINER(gtk_widget_get_parent(lw->utility_box)), lw->utility_box);
1816
1817         if (lw->toolbar[TOOLBAR_STATUS]) gtk_container_remove(GTK_CONTAINER(gtk_widget_get_parent(lw->toolbar[TOOLBAR_STATUS])), lw->toolbar[TOOLBAR_STATUS]);
1818
1819         if (lw->menu_tool_bar) gtk_container_remove(GTK_CONTAINER(gtk_widget_get_parent(lw->menu_tool_bar)), lw->menu_tool_bar);
1820
1821         /* clear it all */
1822
1823         lw->h_pane = NULL;
1824         lw->v_pane = NULL;
1825
1826         lw->path_entry = NULL;
1827         lw->dir_view = NULL;
1828         lw->vd = NULL;
1829
1830         lw->file_view = NULL;
1831         lw->vf = NULL;
1832
1833         lw->info_box = NULL;
1834         lw->info_progress_bar = NULL;
1835         lw->info_sort = NULL;
1836         lw->info_status = NULL;
1837         lw->info_details = NULL;
1838         lw->info_pixel = NULL;
1839         lw->info_zoom = NULL;
1840
1841 /*
1842         if (lw->ui_manager) g_object_unref(lw->ui_manager);
1843         lw->ui_manager = NULL;
1844         lw->action_group = NULL;
1845         lw->action_group_editors = NULL;
1846 */
1847
1848         gtk_container_remove(GTK_CONTAINER(lw->main_box), lw->group_box);
1849         lw->group_box = NULL;
1850
1851         /* re-fill */
1852
1853         layout_grid_setup(lw);
1854         layout_tools_hide(lw, lw->options.tools_hidden);
1855
1856         layout_util_sync(lw);
1857         layout_status_update_all(lw);
1858
1859
1860         // printf("%d %d %d \n", G_OBJECT(lw->utility_box)->ref_count, G_OBJECT(lw->menu_bar)->ref_count, G_OBJECT(lw->toolbar)->ref_count);
1861
1862         /* sync */
1863
1864         if (image_get_fd(lw->image))
1865                 {
1866                 layout_set_fd(lw, image_get_fd(lw->image));
1867                 }
1868         else
1869                 {
1870                 layout_set_fd(lw, dir_fd);
1871                 }
1872         image_top_window_set_sync(lw->image, (lw->options.tools_float || lw->options.tools_hidden));
1873
1874         /* clean up */
1875
1876         file_data_unref(dir_fd);
1877 }
1878
1879 void layout_colors_update(void)
1880 {
1881         GList *work;
1882
1883         work = layout_window_list;
1884         while (work)
1885                 {
1886                 gint i;
1887                 LayoutWindow *lw = work->data;
1888                 work = work->next;
1889
1890                 if (!lw->image) continue;
1891
1892                 for (i = 0; i < MAX_SPLIT_IMAGES; i++)
1893                         {
1894                         if (!lw->split_images[i]) continue;
1895                         image_background_set_color_from_options(lw->split_images[i], !!lw->full_screen);
1896                         }
1897
1898                 image_background_set_color_from_options(lw->image, !!lw->full_screen);
1899                 }
1900 }
1901
1902 void layout_tools_float_toggle(LayoutWindow *lw)
1903 {
1904         gboolean popped;
1905
1906         if (!lw) return;
1907
1908         if (!lw->options.tools_hidden)
1909                 {
1910                 popped = !lw->options.tools_float;
1911                 }
1912         else
1913                 {
1914                 popped = TRUE;
1915                 }
1916
1917         if (lw->options.tools_float == popped)
1918                 {
1919                 if (popped && lw->options.tools_hidden)
1920                         {
1921                         layout_tools_float_set(lw, popped, FALSE);
1922                         }
1923                 }
1924         else
1925                 {
1926                 if (lw->options.tools_float)
1927                         {
1928                         layout_tools_float_set(lw, FALSE, FALSE);
1929                         }
1930                 else
1931                         {
1932                         layout_tools_float_set(lw, TRUE, FALSE);
1933                         }
1934                 }
1935 }
1936
1937 void layout_tools_hide_toggle(LayoutWindow *lw)
1938 {
1939         if (!lw) return;
1940
1941         layout_tools_float_set(lw, lw->options.tools_float, !lw->options.tools_hidden);
1942 }
1943
1944 void layout_tools_float_set(LayoutWindow *lw, gboolean popped, gboolean hidden)
1945 {
1946         if (!layout_valid(&lw)) return;
1947
1948         if (lw->options.tools_float == popped && lw->options.tools_hidden == hidden) return;
1949
1950         if (lw->options.tools_float == popped && lw->options.tools_float && lw->tools)
1951                 {
1952                 layout_tools_hide(lw, hidden);
1953                 return;
1954                 }
1955
1956         lw->options.tools_float = popped;
1957         lw->options.tools_hidden = hidden;
1958
1959         layout_style_set(lw, -1, NULL);
1960 }
1961
1962 gboolean layout_tools_float_get(LayoutWindow *lw, gboolean *popped, gboolean *hidden)
1963 {
1964         if (!layout_valid(&lw)) return FALSE;
1965
1966         *popped = lw->options.tools_float;
1967         *hidden = lw->options.tools_hidden;
1968
1969         return TRUE;
1970 }
1971
1972 void layout_toolbar_toggle(LayoutWindow *lw)
1973 {
1974         if (!layout_valid(&lw)) return;
1975         if (!lw->toolbar[TOOLBAR_MAIN]) return;
1976
1977         lw->options.toolbar_hidden = !lw->options.toolbar_hidden;
1978
1979         if (lw->options.toolbar_hidden)
1980                 {
1981                 if (gtk_widget_get_visible(lw->toolbar[TOOLBAR_MAIN])) gtk_widget_hide(lw->toolbar[TOOLBAR_MAIN]);
1982                 }
1983         else
1984                 {
1985                 if (!gtk_widget_get_visible(lw->toolbar[TOOLBAR_MAIN])) gtk_widget_show(lw->toolbar[TOOLBAR_MAIN]);
1986                 }
1987 }
1988
1989 void layout_info_pixel_set(LayoutWindow *lw, gboolean show)
1990 {
1991         GtkWidget *frame;
1992
1993         if (!layout_valid(&lw)) return;
1994         if (!lw->info_pixel) return;
1995
1996         lw->options.show_info_pixel = show;
1997
1998         frame = gtk_widget_get_parent(lw->info_pixel);
1999         if (!lw->options.show_info_pixel)
2000                 {
2001                 gtk_widget_hide(frame);
2002                 }
2003         else
2004                 {
2005                 gtk_widget_show(frame);
2006                 }
2007
2008         g_signal_emit_by_name (lw->image->pr, "update-pixel");
2009 }
2010
2011 /*
2012  *-----------------------------------------------------------------------------
2013  * configuration
2014  *-----------------------------------------------------------------------------
2015  */
2016
2017 #define CONFIG_WINDOW_DEF_WIDTH         600
2018 #define CONFIG_WINDOW_DEF_HEIGHT        400
2019
2020 typedef struct _LayoutConfig LayoutConfig;
2021 struct _LayoutConfig
2022 {
2023         LayoutWindow *lw;
2024
2025         GtkWidget *configwindow;
2026         GtkWidget *home_path_entry;
2027         GtkWidget *layout_widget;
2028
2029         LayoutOptions options;
2030 };
2031
2032 static gint layout_config_delete_cb(GtkWidget *w, GdkEventAny *event, gpointer data);
2033
2034 static void layout_config_close_cb(GtkWidget *widget, gpointer data)
2035 {
2036         LayoutConfig *lc = data;
2037
2038         gtk_widget_destroy(lc->configwindow);
2039         free_layout_options_content(&lc->options);
2040         g_free(lc);
2041 }
2042
2043 static gint layout_config_delete_cb(GtkWidget *w, GdkEventAny *event, gpointer data)
2044 {
2045         layout_config_close_cb(w, data);
2046         return TRUE;
2047 }
2048
2049 static void layout_config_apply_cb(GtkWidget *widget, gpointer data)
2050 {
2051         LayoutConfig *lc = data;
2052
2053         g_free(lc->options.order);
2054         lc->options.order = layout_config_get(lc->layout_widget, &lc->options.style);
2055
2056         config_entry_to_option(lc->home_path_entry, &lc->options.home_path, remove_trailing_slash);
2057
2058         layout_apply_options(lc->lw, &lc->options);
2059 }
2060
2061 static void layout_config_help_cb(GtkWidget *widget, gpointer data)
2062 {
2063         help_window_show("GuideOptionsLayout.html");
2064 }
2065
2066 static void layout_config_ok_cb(GtkWidget *widget, gpointer data)
2067 {
2068         LayoutConfig *lc = data;
2069         layout_config_apply_cb(widget, lc);
2070         layout_config_close_cb(widget, lc);
2071 }
2072
2073 static void home_path_set_current_cb(GtkWidget *widget, gpointer data)
2074 {
2075         LayoutConfig *lc = data;
2076         gtk_entry_set_text(GTK_ENTRY(lc->home_path_entry), layout_get_path(lc->lw));
2077 }
2078
2079 static void startup_path_set_current_cb(GtkWidget *widget, gpointer data)
2080 {
2081         LayoutConfig *lc = data;
2082         lc->options.startup_path = STARTUP_PATH_CURRENT;
2083 }
2084
2085 static void startup_path_set_last_cb(GtkWidget *widget, gpointer data)
2086 {
2087         LayoutConfig *lc = data;
2088         lc->options.startup_path = STARTUP_PATH_LAST;
2089 }
2090
2091 static void startup_path_set_home_cb(GtkWidget *widget, gpointer data)
2092 {
2093         LayoutConfig *lc = data;
2094         lc->options.startup_path = STARTUP_PATH_HOME;
2095 }
2096
2097
2098 /*
2099 static void layout_config_save_cb(GtkWidget *widget, gpointer data)
2100 {
2101         layout_config_apply();
2102         save_options(options);
2103 }
2104 */
2105
2106 void layout_show_config_window(LayoutWindow *lw)
2107 {
2108         LayoutConfig *lc;
2109         GtkWidget *win_vbox;
2110         GtkWidget *hbox;
2111         GtkWidget *vbox;
2112         GtkWidget *button;
2113         GtkWidget *ct_button;
2114         GtkWidget *group;
2115         GtkWidget *frame;
2116         GtkWidget *tabcomp;
2117
2118         lc = g_new0(LayoutConfig, 1);
2119         lc->lw = lw;
2120         layout_sync_options_with_current_state(lw);
2121         copy_layout_options(&lc->options, &lw->options);
2122
2123         lc->configwindow = window_new(GTK_WINDOW_TOPLEVEL, "Layout", PIXBUF_INLINE_ICON_CONFIG, NULL, _("Window options and layout"));
2124         gtk_window_set_type_hint(GTK_WINDOW(lc->configwindow), GDK_WINDOW_TYPE_HINT_DIALOG);
2125
2126         g_signal_connect(G_OBJECT(lc->configwindow), "delete_event",
2127                          G_CALLBACK(layout_config_delete_cb), lc);
2128
2129         gtk_window_set_default_size(GTK_WINDOW(lc->configwindow), CONFIG_WINDOW_DEF_WIDTH, CONFIG_WINDOW_DEF_HEIGHT);
2130         gtk_window_set_resizable(GTK_WINDOW(lc->configwindow), TRUE);
2131         gtk_container_set_border_width(GTK_CONTAINER(lc->configwindow), PREF_PAD_BORDER);
2132
2133         win_vbox = gtk_vbox_new(FALSE, PREF_PAD_SPACE);
2134         gtk_container_add(GTK_CONTAINER(lc->configwindow), win_vbox);
2135         gtk_widget_show(win_vbox);
2136
2137         hbox = gtk_hbutton_box_new();
2138         gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END);
2139         gtk_box_set_spacing(GTK_BOX(hbox), PREF_PAD_BUTTON_GAP);
2140         gtk_box_pack_end(GTK_BOX(win_vbox), hbox, FALSE, FALSE, 0);
2141         gtk_widget_show(hbox);
2142
2143         button = pref_button_new(NULL, GTK_STOCK_OK, NULL, FALSE,
2144                                  G_CALLBACK(layout_config_ok_cb), lc);
2145         gtk_container_add(GTK_CONTAINER(hbox), button);
2146         gtk_widget_set_can_default(button, TRUE);
2147         gtk_widget_grab_default(button);
2148         gtk_widget_show(button);
2149
2150         ct_button = button;
2151 /*
2152         button = pref_button_new(NULL, GTK_STOCK_SAVE, NULL, FALSE,
2153                                  G_CALLBACK(layout_config_save_cb), NULL);
2154         gtk_container_add(GTK_CONTAINER(hbox), button);
2155         GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
2156         gtk_widget_show(button);
2157 */
2158         button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
2159                                  G_CALLBACK(layout_config_help_cb), lc);
2160         gtk_container_add(GTK_CONTAINER(hbox), button);
2161         gtk_widget_set_can_default(button, TRUE);
2162         gtk_widget_show(button);
2163
2164         button = pref_button_new(NULL, GTK_STOCK_APPLY, NULL, FALSE,
2165                                  G_CALLBACK(layout_config_apply_cb), lc);
2166         gtk_container_add(GTK_CONTAINER(hbox), button);
2167         gtk_widget_set_can_default(button, TRUE);
2168         gtk_widget_show(button);
2169
2170         button = pref_button_new(NULL, GTK_STOCK_CANCEL, NULL, FALSE,
2171                                  G_CALLBACK(layout_config_close_cb), lc);
2172         gtk_container_add(GTK_CONTAINER(hbox), button);
2173         gtk_widget_set_can_default(button, TRUE);
2174         gtk_widget_show(button);
2175
2176         if (!generic_dialog_get_alternative_button_order(lc->configwindow))
2177                 {
2178                 gtk_box_reorder_child(GTK_BOX(hbox), ct_button, -1);
2179                 }
2180
2181         frame = pref_frame_new(win_vbox, TRUE, NULL, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2182
2183         vbox = gtk_vbox_new(FALSE, PREF_PAD_SPACE);
2184         gtk_container_add(GTK_CONTAINER(frame), vbox);
2185         gtk_widget_show(vbox);
2186
2187
2188         group = pref_group_new(vbox, FALSE, _("General options"), GTK_ORIENTATION_VERTICAL);
2189
2190         pref_label_new(group, _("Home path (empty to use your home directory)"));
2191         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2192
2193         tabcomp = tab_completion_new(&lc->home_path_entry, lc->options.home_path, NULL, NULL, NULL, NULL);
2194         tab_completion_add_select_button(lc->home_path_entry, NULL, TRUE);
2195         gtk_box_pack_start(GTK_BOX(hbox), tabcomp, TRUE, TRUE, 0);
2196         gtk_widget_show(tabcomp);
2197
2198         button = pref_button_new(hbox, NULL, _("Use current"), FALSE,
2199                                  G_CALLBACK(home_path_set_current_cb), lc);
2200
2201         pref_checkbox_new_int(group, _("Show date in directories list view"),
2202                               lc->options.show_directory_date, &lc->options.show_directory_date);
2203
2204         pref_checkbox_new_int(group, _("Exit program when this window is closed"),
2205                               lc->options.exit_on_close, &lc->options.exit_on_close);
2206
2207         group = pref_group_new(vbox, FALSE, _("Start-up directory:"), GTK_ORIENTATION_VERTICAL);
2208
2209         button = pref_radiobutton_new(group, NULL, _("No change"),
2210                                       (lc->options.startup_path == STARTUP_PATH_CURRENT),
2211                                       G_CALLBACK(startup_path_set_current_cb), lc);
2212         button = pref_radiobutton_new(group, button, _("Restore last path"),
2213                                       (lc->options.startup_path == STARTUP_PATH_LAST),
2214                                       G_CALLBACK(startup_path_set_last_cb), lc);
2215         button = pref_radiobutton_new(group, button, _("Home path"),
2216                                       (lc->options.startup_path == STARTUP_PATH_HOME),
2217                                       G_CALLBACK(startup_path_set_home_cb), lc);
2218
2219         group = pref_group_new(vbox, FALSE, _("Layout"), GTK_ORIENTATION_VERTICAL);
2220
2221         lc->layout_widget = layout_config_new();
2222         layout_config_set(lc->layout_widget, lw->options.style, lw->options.order);
2223         gtk_box_pack_start(GTK_BOX(group), lc->layout_widget, TRUE, TRUE, 0);
2224
2225         gtk_widget_show(lc->layout_widget);
2226         gtk_widget_show(lc->configwindow);
2227 }
2228
2229 /*
2230  *-----------------------------------------------------------------------------
2231  * base
2232  *-----------------------------------------------------------------------------
2233  */
2234
2235 void layout_sync_options_with_current_state(LayoutWindow *lw)
2236 {
2237         Histogram *histogram;
2238         if (!layout_valid(&lw)) return;
2239
2240         lw->options.main_window.maximized =  window_maximized(lw->window);
2241         if (!lw->options.main_window.maximized)
2242                 {
2243                 layout_geometry_get(lw, &lw->options.main_window.x, &lw->options.main_window.y,
2244                                     &lw->options.main_window.w, &lw->options.main_window.h);
2245                 }
2246
2247         layout_geometry_get_dividers(lw, &lw->options.main_window.hdivider_pos, &lw->options.main_window.vdivider_pos);
2248
2249 //      layout_sort_get(NULL, &options->file_sort.method, &options->file_sort.ascending);
2250
2251         layout_geometry_get_tools(lw, &lw->options.float_window.x, &lw->options.float_window.y,
2252                                   &lw->options.float_window.w, &lw->options.float_window.h, &lw->options.float_window.vdivider_pos);
2253
2254         lw->options.image_overlay.state = image_osd_get(lw->image);
2255         histogram = image_osd_get_histogram(lw->image);
2256
2257         lw->options.image_overlay.histogram_channel = histogram->histogram_channel;
2258         lw->options.image_overlay.histogram_mode = histogram->histogram_mode;
2259
2260         g_free(lw->options.last_path);
2261         lw->options.last_path = g_strdup(layout_get_path(lw));
2262
2263         layout_geometry_get_log_window(lw, &lw->options.log_window.x, &lw->options.log_window.y,
2264                                          &lw->options.log_window.w, &lw->options.log_window.h);
2265
2266 }
2267
2268 void layout_apply_options(LayoutWindow *lw, LayoutOptions *lop)
2269 {
2270         gboolean refresh_style;
2271         gboolean refresh_lists;
2272
2273         if (!layout_valid(&lw)) return;
2274 /* FIXME: add other options too */
2275
2276         refresh_style = (lop->style != lw->options.style || strcmp(lop->order, lw->options.order) != 0);
2277         refresh_lists = (lop->show_directory_date != lw->options.show_directory_date);
2278
2279         copy_layout_options(&lw->options, lop);
2280
2281         if (refresh_style) layout_style_set(lw, lw->options.style, lw->options.order);
2282         if (refresh_lists) layout_refresh(lw);
2283 }
2284
2285
2286 void layout_close(LayoutWindow *lw)
2287 {
2288         if (!lw->options.exit_on_close && layout_window_list && layout_window_list->next)
2289                 {
2290                 layout_free(lw);
2291                 }
2292         else
2293                 {
2294                 exit_program();
2295                 }
2296 }
2297
2298 void layout_free(LayoutWindow *lw)
2299 {
2300         gint i;
2301         if (!lw) return;
2302
2303         layout_window_list = g_list_remove(layout_window_list, lw);
2304         if (current_lw == lw) current_lw = NULL;
2305
2306         if (lw->exif_window) g_signal_handlers_disconnect_matched(G_OBJECT(lw->exif_window), G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, lw);
2307
2308         layout_bars_close(lw);
2309
2310         g_object_unref(lw->menu_bar);
2311         g_object_unref(lw->utility_box);
2312
2313         for (i = 0; i < TOOLBAR_COUNT; i++)
2314                 {
2315                 if (lw->toolbar[i]) g_object_unref(lw->toolbar[i]);
2316                 }
2317
2318         gtk_widget_destroy(lw->window);
2319
2320         if (lw->split_image_sizegroup) g_object_unref(lw->split_image_sizegroup);
2321
2322         file_data_unregister_notify_func(layout_image_notify_cb, lw);
2323
2324         if (lw->dir_fd)
2325                 {
2326                 file_data_unregister_real_time_monitor(lw->dir_fd);
2327                 file_data_unref(lw->dir_fd);
2328                 }
2329
2330         free_layout_options_content(&lw->options);
2331         g_free(lw);
2332 }
2333
2334 static gboolean layout_delete_cb(GtkWidget *widget, GdkEventAny *event, gpointer data)
2335 {
2336         LayoutWindow *lw = data;
2337
2338         layout_close(lw);
2339         return TRUE;
2340 }
2341
2342 LayoutWindow *layout_new(FileData *dir_fd, LayoutOptions *lop)
2343 {
2344         return layout_new_with_geometry(dir_fd, lop, NULL);
2345 }
2346
2347 LayoutWindow *layout_new_with_geometry(FileData *dir_fd, LayoutOptions *lop,
2348                                        const gchar *geometry)
2349 {
2350         LayoutWindow *lw;
2351         GdkGeometry hint;
2352         GdkWindowHints hint_mask;
2353         Histogram *histogram;
2354
2355         DEBUG_1("%s layout_new: start", get_exec_time());
2356         lw = g_new0(LayoutWindow, 1);
2357
2358         if (lop)
2359                 copy_layout_options(&lw->options, lop);
2360         else
2361                 init_layout_options(&lw->options);
2362
2363         lw->sort_method = SORT_NAME;
2364         lw->sort_ascend = TRUE;
2365
2366         layout_set_unique_id(lw);
2367 //      lw->options.tools_float = popped;
2368 //      lw->options.tools_hidden = hidden;
2369 //      lw->bar_sort_enabled = options->panels.sort.enabled;
2370 //      lw->bar_enabled = options->panels.info.enabled;
2371
2372         /* default layout */
2373
2374         layout_config_parse(lw->options.style, lw->options.order,
2375                             &lw->dir_location,  &lw->file_location, &lw->image_location);
2376         if (lw->options.dir_view_type > DIRVIEW_LAST) lw->options.dir_view_type = 0;
2377         if (lw->options.file_view_type > FILEVIEW_LAST) lw->options.file_view_type = 0;
2378
2379         /* divider positions */
2380
2381         if (!options->save_window_positions)
2382                 {
2383                 lw->options.main_window.hdivider_pos = MAIN_WINDOW_DIV_HPOS;
2384                 lw->options.main_window.vdivider_pos = MAIN_WINDOW_DIV_VPOS;
2385                 lw->options.float_window.vdivider_pos = MAIN_WINDOW_DIV_VPOS;
2386                 }
2387
2388         /* window */
2389
2390         lw->window = window_new(GTK_WINDOW_TOPLEVEL, GQ_APPNAME_LC, NULL, NULL, NULL);
2391         gtk_window_set_resizable(GTK_WINDOW(lw->window), TRUE);
2392         gtk_container_set_border_width(GTK_CONTAINER(lw->window), 0);
2393
2394         if (options->save_window_positions)
2395                 {
2396                 hint_mask = GDK_HINT_USER_POS;
2397                 }
2398         else
2399                 {
2400                 hint_mask = 0;
2401                 }
2402
2403         hint.min_width = 32;
2404         hint.min_height = 32;
2405         hint.base_width = 0;
2406         hint.base_height = 0;
2407         gtk_window_set_geometry_hints(GTK_WINDOW(lw->window), NULL, &hint,
2408                                       GDK_HINT_MIN_SIZE | GDK_HINT_BASE_SIZE | hint_mask);
2409
2410         if (options->save_window_positions)
2411                 {
2412                 gtk_window_set_default_size(GTK_WINDOW(lw->window), lw->options.main_window.w, lw->options.main_window.h);
2413 //              if (!layout_window_list)
2414 //                      {
2415                 gtk_window_move(GTK_WINDOW(lw->window), lw->options.main_window.x, lw->options.main_window.y);
2416                 if (lw->options.main_window.maximized) gtk_window_maximize(GTK_WINDOW(lw->window));
2417 //                      }
2418                 }
2419         else
2420                 {
2421                 gtk_window_set_default_size(GTK_WINDOW(lw->window), MAINWINDOW_DEF_WIDTH, MAINWINDOW_DEF_HEIGHT);
2422                 }
2423
2424         g_signal_connect(G_OBJECT(lw->window), "delete_event",
2425                          G_CALLBACK(layout_delete_cb), lw);
2426
2427         g_signal_connect(G_OBJECT(lw->window), "focus-in-event",
2428                          G_CALLBACK(layout_set_current_cb), lw);
2429
2430         layout_keyboard_init(lw, lw->window);
2431
2432 #ifdef HAVE_LIRC
2433         layout_image_lirc_init(lw);
2434 #endif
2435
2436         lw->main_box = gtk_vbox_new(FALSE, 0);
2437         gtk_container_add(GTK_CONTAINER(lw->window), lw->main_box);
2438         gtk_widget_show(lw->main_box);
2439
2440         layout_grid_setup(lw);
2441         image_top_window_set_sync(lw->image, (lw->options.tools_float || lw->options.tools_hidden));
2442
2443         layout_util_sync(lw);
2444         layout_status_update_all(lw);
2445
2446         if (dir_fd)
2447                 {
2448                 layout_set_fd(lw, dir_fd);
2449                 }
2450         else
2451                 {
2452                 GdkPixbuf *pixbuf;
2453
2454                 pixbuf = pixbuf_inline(PIXBUF_INLINE_LOGO);
2455
2456                 /* FIXME: the zoom value set here is the value, which is then copied again and again
2457                    in "Leave Zoom at previous setting" mode. This is not ideal.  */
2458                 image_change_pixbuf(lw->image, pixbuf, 0.0, FALSE);
2459                 g_object_unref(pixbuf);
2460                 }
2461
2462         if (geometry)
2463                 {
2464                 if (!gtk_window_parse_geometry(GTK_WINDOW(lw->window), geometry))
2465                         {
2466                         log_printf("%s", _("Invalid geometry\n"));
2467                         }
2468                 }
2469
2470         gtk_widget_show(lw->window);
2471         layout_tools_hide(lw, lw->options.tools_hidden);
2472
2473         image_osd_set(lw->image, lw->options.image_overlay.state);
2474         histogram = image_osd_get_histogram(lw->image);
2475
2476         histogram->histogram_channel = lw->options.image_overlay.histogram_channel;
2477         histogram->histogram_mode = lw->options.image_overlay.histogram_mode;
2478
2479         layout_window_list = g_list_append(layout_window_list, lw);
2480
2481         file_data_register_notify_func(layout_image_notify_cb, lw, NOTIFY_PRIORITY_LOW);
2482
2483         DEBUG_1("%s layout_new: end", get_exec_time());
2484
2485         return lw;
2486 }
2487
2488 void layout_write_attributes(LayoutOptions *layout, GString *outstr, gint indent)
2489 {
2490         WRITE_NL(); WRITE_CHAR(*layout, id);
2491
2492         WRITE_NL(); WRITE_INT(*layout, style);
2493         WRITE_NL(); WRITE_CHAR(*layout, order);
2494         WRITE_NL(); WRITE_UINT(*layout, dir_view_type);
2495         WRITE_NL(); WRITE_UINT(*layout, file_view_type);
2496         WRITE_NL(); WRITE_BOOL(*layout, show_marks);
2497         WRITE_NL(); WRITE_BOOL(*layout, show_file_filter);
2498         WRITE_NL(); WRITE_BOOL(*layout, show_thumbnails);
2499         WRITE_NL(); WRITE_BOOL(*layout, show_directory_date);
2500         WRITE_NL(); WRITE_CHAR(*layout, home_path);
2501         WRITE_NL(); WRITE_CHAR(*layout, last_path);
2502         WRITE_NL(); WRITE_UINT(*layout, startup_path);
2503         WRITE_NL(); WRITE_BOOL(*layout, exit_on_close);
2504         WRITE_SEPARATOR();
2505
2506         WRITE_NL(); WRITE_INT(*layout, main_window.x);
2507         WRITE_NL(); WRITE_INT(*layout, main_window.y);
2508         WRITE_NL(); WRITE_INT(*layout, main_window.w);
2509         WRITE_NL(); WRITE_INT(*layout, main_window.h);
2510         WRITE_NL(); WRITE_BOOL(*layout, main_window.maximized);
2511         WRITE_NL(); WRITE_INT(*layout, main_window.hdivider_pos);
2512         WRITE_NL(); WRITE_INT(*layout, main_window.vdivider_pos);
2513         WRITE_SEPARATOR();
2514
2515         WRITE_NL(); WRITE_INT(*layout, folder_window.vdivider_pos);
2516         WRITE_SEPARATOR();
2517
2518         WRITE_NL(); WRITE_INT(*layout, float_window.x);
2519         WRITE_NL(); WRITE_INT(*layout, float_window.y);
2520         WRITE_NL(); WRITE_INT(*layout, float_window.w);
2521         WRITE_NL(); WRITE_INT(*layout, float_window.h);
2522         WRITE_NL(); WRITE_INT(*layout, float_window.vdivider_pos);
2523         WRITE_SEPARATOR();
2524
2525         WRITE_NL(); WRITE_INT(*layout, properties_window.w);
2526         WRITE_NL(); WRITE_INT(*layout, properties_window.h);
2527         WRITE_SEPARATOR();
2528
2529         WRITE_NL(); WRITE_BOOL(*layout, tools_float);
2530         WRITE_NL(); WRITE_BOOL(*layout, tools_hidden);
2531         WRITE_SEPARATOR();
2532
2533         WRITE_NL(); WRITE_BOOL(*layout, toolbar_hidden);
2534         WRITE_NL(); WRITE_BOOL(*layout, show_info_pixel);
2535
2536         WRITE_NL(); WRITE_UINT(*layout, image_overlay.state);
2537         WRITE_NL(); WRITE_INT(*layout, image_overlay.histogram_channel);
2538         WRITE_NL(); WRITE_INT(*layout, image_overlay.histogram_mode);
2539
2540         WRITE_NL(); WRITE_INT(*layout, log_window.x);
2541         WRITE_NL(); WRITE_INT(*layout, log_window.y);
2542         WRITE_NL(); WRITE_INT(*layout, log_window.w);
2543         WRITE_NL(); WRITE_INT(*layout, log_window.h);
2544         WRITE_SEPARATOR();
2545
2546         WRITE_NL(); WRITE_BOOL(*layout, animate);
2547 }
2548
2549
2550 void layout_write_config(LayoutWindow *lw, GString *outstr, gint indent)
2551 {
2552         layout_sync_options_with_current_state(lw);
2553         WRITE_NL(); WRITE_STRING("<layout");
2554         layout_write_attributes(&lw->options, outstr, indent + 1);
2555         WRITE_STRING(">");
2556
2557         bar_sort_write_config(lw->bar_sort, outstr, indent + 1);
2558         bar_write_config(lw->bar, outstr, indent + 1);
2559
2560         WRITE_SEPARATOR();
2561         generic_dialog_windows_write_config(outstr, indent + 1);
2562
2563         WRITE_SEPARATOR();
2564         layout_toolbar_write_config(lw, TOOLBAR_MAIN, outstr, indent + 1);
2565
2566         WRITE_NL(); WRITE_STRING("</layout>");
2567 }
2568
2569 void layout_load_attributes(LayoutOptions *layout, const gchar **attribute_names, const gchar **attribute_values)
2570 {
2571         gchar *id = NULL;
2572
2573         while (*attribute_names)
2574                 {
2575                 const gchar *option = *attribute_names++;
2576                 const gchar *value = *attribute_values++;
2577
2578                 /* layout options */
2579                 if (READ_CHAR_FULL("id", id)) continue;
2580
2581                 if (READ_INT(*layout, style)) continue;
2582                 if (READ_CHAR(*layout, order)) continue;
2583
2584                 if (READ_UINT(*layout, dir_view_type)) continue;
2585                 if (READ_UINT(*layout, file_view_type)) continue;
2586                 if (READ_BOOL(*layout, show_marks)) continue;
2587                 if (READ_BOOL(*layout, show_file_filter)) continue;
2588                 if (READ_BOOL(*layout, show_thumbnails)) continue;
2589                 if (READ_BOOL(*layout, show_directory_date)) continue;
2590                 if (READ_CHAR(*layout, home_path)) continue;
2591                 if (READ_CHAR(*layout, last_path)) continue;
2592                 if (READ_UINT_CLAMP(*layout, startup_path, 0, STARTUP_PATH_HOME)) continue;
2593                 if (READ_BOOL(*layout, exit_on_close)) continue;
2594
2595                 /* window positions */
2596
2597                 if (READ_INT(*layout, main_window.x)) continue;
2598                 if (READ_INT(*layout, main_window.y)) continue;
2599                 if (READ_INT(*layout, main_window.w)) continue;
2600                 if (READ_INT(*layout, main_window.h)) continue;
2601                 if (READ_BOOL(*layout, main_window.maximized)) continue;
2602                 if (READ_INT(*layout, main_window.hdivider_pos)) continue;
2603                 if (READ_INT(*layout, main_window.vdivider_pos)) continue;
2604
2605                 if (READ_INT_CLAMP(*layout, folder_window.vdivider_pos, 1, 1000)) continue;
2606
2607                 if (READ_INT(*layout, float_window.x)) continue;
2608                 if (READ_INT(*layout, float_window.y)) continue;
2609                 if (READ_INT(*layout, float_window.w)) continue;
2610                 if (READ_INT(*layout, float_window.h)) continue;
2611                 if (READ_INT(*layout, float_window.vdivider_pos)) continue;
2612
2613                 if (READ_INT(*layout, properties_window.w)) continue;
2614                 if (READ_INT(*layout, properties_window.h)) continue;
2615
2616                 if (READ_BOOL(*layout, tools_float)) continue;
2617                 if (READ_BOOL(*layout, tools_hidden)) continue;
2618                 if (READ_BOOL(*layout, toolbar_hidden)) continue;
2619                 if (READ_BOOL(*layout, show_info_pixel)) continue;
2620
2621                 if (READ_UINT(*layout, image_overlay.state)) continue;
2622                 if (READ_INT(*layout, image_overlay.histogram_channel)) continue;
2623                 if (READ_INT(*layout, image_overlay.histogram_mode)) continue;
2624
2625                 if (READ_INT(*layout, log_window.x)) continue;
2626                 if (READ_INT(*layout, log_window.y)) continue;
2627                 if (READ_INT(*layout, log_window.w)) continue;
2628                 if (READ_INT(*layout, log_window.h)) continue;
2629
2630                 if (READ_BOOL(*layout, animate)) continue;
2631
2632                 log_printf("unknown attribute %s = %s\n", option, value);
2633                 }
2634         if (id && strcmp(id, LAYOUT_ID_CURRENT) != 0)
2635                 {
2636                 g_free(layout->id);
2637                 layout->id = id;
2638                 }
2639         else
2640                 {
2641                 g_free(id);
2642                 }
2643 }
2644
2645 static void layout_config_startup_path(LayoutOptions *lop, gchar **path)
2646 {
2647         switch (lop->startup_path)
2648                 {
2649                 case STARTUP_PATH_LAST:
2650                         *path = (lop->last_path && isdir(lop->last_path)) ? g_strdup(lop->last_path) : get_current_dir();
2651                         break;
2652                 case STARTUP_PATH_HOME:
2653                         *path = (lop->home_path && isdir(lop->home_path)) ? g_strdup(lop->home_path) : g_strdup(homedir());
2654                         break;
2655                 default:
2656                         *path = get_current_dir();
2657                         break;
2658                 }
2659 }
2660
2661
2662 static void layout_config_commandline(LayoutOptions *lop, gchar **path)
2663 {
2664         if (command_line->startup_blank)
2665                 {
2666                 *path = NULL;
2667                 }
2668         else if (command_line->file)
2669                 {
2670                 *path = g_strdup(command_line->file);
2671                 }
2672         else if (command_line->path)
2673                 {
2674                 *path = g_strdup(command_line->path);
2675                 }
2676         else layout_config_startup_path(lop, path);
2677
2678         if (command_line->tools_show)
2679                 {
2680                 lop->tools_float = FALSE;
2681                 lop->tools_hidden = FALSE;
2682                 }
2683         else if (command_line->tools_hide)
2684                 {
2685                 lop->tools_hidden = TRUE;
2686                 }
2687 }
2688
2689 LayoutWindow *layout_new_from_config(const gchar **attribute_names, const gchar **attribute_values, gboolean use_commandline)
2690 {
2691         LayoutOptions lop;
2692         LayoutWindow *lw;
2693         gchar *path = NULL;
2694
2695         init_layout_options(&lop);
2696
2697         if (attribute_names) layout_load_attributes(&lop, attribute_names, attribute_values);
2698
2699         if (use_commandline)
2700                 {
2701                 layout_config_commandline(&lop, &path);
2702                 }
2703         else
2704                 {
2705                 layout_config_startup_path(&lop, &path);
2706                 }
2707
2708         lw = layout_new_with_geometry(NULL, &lop, use_commandline ? command_line->geometry : NULL);
2709         layout_sort_set(lw, options->file_sort.method, options->file_sort.ascending);
2710         layout_set_path(lw, path);
2711
2712         if (use_commandline && command_line->startup_full_screen) layout_image_full_screen_start(lw);
2713         if (use_commandline && command_line->startup_in_slideshow) layout_image_slideshow_start(lw);
2714         if (use_commandline && command_line->log_window_show) log_window_new(lw);
2715
2716         g_free(path);
2717         free_layout_options_content(&lop);
2718         return lw;
2719 }
2720
2721 void layout_update_from_config(LayoutWindow *lw, const gchar **attribute_names, const gchar **attribute_values)
2722 {
2723         LayoutOptions lop;
2724
2725         init_layout_options(&lop);
2726
2727         if (attribute_names) layout_load_attributes(&lop, attribute_names, attribute_values);
2728
2729         layout_apply_options(lw, &lop);
2730
2731         free_layout_options_content(&lop);
2732 }
2733
2734
2735 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */