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